1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/device_orientation/data_fetcher_shared_memory_base.h"
8 #include "base/logging.h"
9 #include "base/stl_util.h"
10 #include "base/threading/thread.h"
11 #include "base/timer/timer.h"
12 #include "content/common/device_orientation/device_motion_hardware_buffer.h"
13 #include "content/common/device_orientation/device_orientation_hardware_buffer.h"
19 static size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type
) {
20 switch (consumer_type
) {
21 case CONSUMER_TYPE_MOTION
:
22 return sizeof(DeviceMotionHardwareBuffer
);
23 case CONSUMER_TYPE_ORIENTATION
:
24 return sizeof(DeviceOrientationHardwareBuffer
);
33 class DataFetcherSharedMemoryBase::PollingThread
: public base::Thread
{
35 PollingThread(const char* name
, DataFetcherSharedMemoryBase
* fetcher
);
36 virtual ~PollingThread();
38 void AddConsumer(ConsumerType consumer_type
, void* buffer
);
39 void RemoveConsumer(ConsumerType consumer_type
);
41 unsigned GetConsumersBitmask() const { return consumers_bitmask_
; }
42 bool IsTimerRunning() const { return timer_
? timer_
->IsRunning() : false; }
48 unsigned consumers_bitmask_
;
49 DataFetcherSharedMemoryBase
* fetcher_
;
50 scoped_ptr
<base::RepeatingTimer
<PollingThread
> > timer_
;
52 DISALLOW_COPY_AND_ASSIGN(PollingThread
);
55 // --- PollingThread methods
57 DataFetcherSharedMemoryBase::PollingThread::PollingThread(
58 const char* name
, DataFetcherSharedMemoryBase
* fetcher
)
60 consumers_bitmask_(0),
64 DataFetcherSharedMemoryBase::PollingThread::~PollingThread() {
67 void DataFetcherSharedMemoryBase::PollingThread::AddConsumer(
68 ConsumerType consumer_type
, void* buffer
) {
70 if (!fetcher_
->Start(consumer_type
, buffer
))
73 consumers_bitmask_
|= consumer_type
;
75 if (!timer_
&& fetcher_
->GetType() == FETCHER_TYPE_POLLING_CALLBACK
) {
76 timer_
.reset(new base::RepeatingTimer
<PollingThread
>());
77 timer_
->Start(FROM_HERE
,
78 fetcher_
->GetInterval(),
79 this, &PollingThread::DoPoll
);
83 void DataFetcherSharedMemoryBase::PollingThread::RemoveConsumer(
84 ConsumerType consumer_type
) {
86 if (!fetcher_
->Stop(consumer_type
))
89 consumers_bitmask_
^= consumer_type
;
91 if (!consumers_bitmask_
)
92 timer_
.reset(); // will also stop the timer.
95 void DataFetcherSharedMemoryBase::PollingThread::DoPoll() {
97 DCHECK(consumers_bitmask_
);
98 fetcher_
->Fetch(consumers_bitmask_
);
101 // --- end of PollingThread methods
103 DataFetcherSharedMemoryBase::DataFetcherSharedMemoryBase()
104 : started_consumers_(0) {
107 DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() {
108 StopFetchingDeviceData(CONSUMER_TYPE_MOTION
);
109 StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION
);
111 // make sure polling thread stops asap.
113 polling_thread_
->Stop();
115 STLDeleteContainerPairSecondPointers(shared_memory_map_
.begin(),
116 shared_memory_map_
.end());
119 bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
120 ConsumerType consumer_type
) {
121 if (started_consumers_
& consumer_type
)
124 void* buffer
= GetSharedMemoryBuffer(consumer_type
);
128 if (GetType() != FETCHER_TYPE_DEFAULT
) {
129 if (!InitAndStartPollingThreadIfNecessary())
131 polling_thread_
->message_loop()->PostTask(
133 base::Bind(&PollingThread::AddConsumer
,
134 base::Unretained(polling_thread_
.get()),
135 consumer_type
, buffer
));
137 if (!Start(consumer_type
, buffer
))
141 started_consumers_
|= consumer_type
;
146 bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
147 ConsumerType consumer_type
) {
148 if (!(started_consumers_
& consumer_type
))
151 if (GetType() != FETCHER_TYPE_DEFAULT
) {
152 polling_thread_
->message_loop()->PostTask(
154 base::Bind(&PollingThread::RemoveConsumer
,
155 base::Unretained(polling_thread_
.get()),
158 if (!Stop(consumer_type
))
162 started_consumers_
^= consumer_type
;
167 base::SharedMemoryHandle
168 DataFetcherSharedMemoryBase::GetSharedMemoryHandleForProcess(
169 ConsumerType consumer_type
, base::ProcessHandle process
) {
170 SharedMemoryMap::const_iterator it
= shared_memory_map_
.find(consumer_type
);
171 if (it
== shared_memory_map_
.end())
172 return base::SharedMemory::NULLHandle();
174 base::SharedMemoryHandle renderer_handle
;
175 it
->second
->ShareToProcess(process
, &renderer_handle
);
176 return renderer_handle
;
179 bool DataFetcherSharedMemoryBase::InitAndStartPollingThreadIfNecessary() {
183 polling_thread_
.reset(
184 new PollingThread("Inertial Device Sensor poller", this));
186 if (!polling_thread_
->Start()) {
187 LOG(ERROR
) << "Failed to start inertial sensor data polling thread";
193 void DataFetcherSharedMemoryBase::Fetch(unsigned consumer_bitmask
) {
197 DataFetcherSharedMemoryBase::FetcherType
198 DataFetcherSharedMemoryBase::GetType() const {
199 return FETCHER_TYPE_DEFAULT
;
202 base::TimeDelta
DataFetcherSharedMemoryBase::GetInterval() const {
203 return base::TimeDelta::FromMilliseconds(kInertialSensorIntervalMillis
);
206 base::SharedMemory
* DataFetcherSharedMemoryBase::GetSharedMemory(
207 ConsumerType consumer_type
) {
208 SharedMemoryMap::const_iterator it
= shared_memory_map_
.find(consumer_type
);
209 if (it
!= shared_memory_map_
.end())
212 size_t buffer_size
= GetConsumerSharedMemoryBufferSize(consumer_type
);
213 if (buffer_size
== 0)
216 scoped_ptr
<base::SharedMemory
> new_shared_mem(new base::SharedMemory
);
217 if (new_shared_mem
->CreateAndMapAnonymous(buffer_size
)) {
218 if (void* mem
= new_shared_mem
->memory()) {
219 memset(mem
, 0, buffer_size
);
220 base::SharedMemory
* shared_mem
= new_shared_mem
.release();
221 shared_memory_map_
[consumer_type
] = shared_mem
;
225 LOG(ERROR
) << "Failed to initialize shared memory";
229 void* DataFetcherSharedMemoryBase::GetSharedMemoryBuffer(
230 ConsumerType consumer_type
) {
231 if (base::SharedMemory
* shared_memory
= GetSharedMemory(consumer_type
))
232 return shared_memory
->memory();
236 base::MessageLoop
* DataFetcherSharedMemoryBase::GetPollingMessageLoop() const {
237 return polling_thread_
? polling_thread_
->message_loop() : NULL
;
240 bool DataFetcherSharedMemoryBase::IsPollingTimerRunningForTesting() const {
241 return polling_thread_
? polling_thread_
->IsTimerRunning() : false;
245 } // namespace content