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.
4
5 #include "content/browser/device_orientation/data_fetcher_shared_memory_base.h"
6
7 #include "base/bind.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"
14
15 namespace content {
16
17 namespace {
18
GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type)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);
25 default:
26 NOTREACHED();
27 }
28 return 0;
29 }
30
31 }
32
33 class DataFetcherSharedMemoryBase::PollingThread : public base::Thread {
34 public:
35 PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher);
36 virtual ~PollingThread();
37
38 void AddConsumer(ConsumerType consumer_type, void* buffer);
39 void RemoveConsumer(ConsumerType consumer_type);
40
GetConsumersBitmask() const41 unsigned GetConsumersBitmask() const { return consumers_bitmask_; }
IsTimerRunning() const42 bool IsTimerRunning() const { return timer_ ? timer_->IsRunning() : false; }
43
44 private:
45
46 void DoPoll();
47
48 unsigned consumers_bitmask_;
49 DataFetcherSharedMemoryBase* fetcher_;
50 scoped_ptr<base::RepeatingTimer<PollingThread> > timer_;
51
52 DISALLOW_COPY_AND_ASSIGN(PollingThread);
53 };
54
55 // --- PollingThread methods
56
PollingThread(const char * name,DataFetcherSharedMemoryBase * fetcher)57 DataFetcherSharedMemoryBase::PollingThread::PollingThread(
58 const char* name, DataFetcherSharedMemoryBase* fetcher)
59 : base::Thread(name),
60 consumers_bitmask_(0),
61 fetcher_(fetcher) {
62 }
63
~PollingThread()64 DataFetcherSharedMemoryBase::PollingThread::~PollingThread() {
65 }
66
AddConsumer(ConsumerType consumer_type,void * buffer)67 void DataFetcherSharedMemoryBase::PollingThread::AddConsumer(
68 ConsumerType consumer_type, void* buffer) {
69 DCHECK(fetcher_);
70 if (!fetcher_->Start(consumer_type, buffer))
71 return;
72
73 consumers_bitmask_ |= consumer_type;
74
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);
80 }
81 }
82
RemoveConsumer(ConsumerType consumer_type)83 void DataFetcherSharedMemoryBase::PollingThread::RemoveConsumer(
84 ConsumerType consumer_type) {
85 DCHECK(fetcher_);
86 if (!fetcher_->Stop(consumer_type))
87 return;
88
89 consumers_bitmask_ ^= consumer_type;
90
91 if (!consumers_bitmask_)
92 timer_.reset(); // will also stop the timer.
93 }
94
DoPoll()95 void DataFetcherSharedMemoryBase::PollingThread::DoPoll() {
96 DCHECK(fetcher_);
97 DCHECK(consumers_bitmask_);
98 fetcher_->Fetch(consumers_bitmask_);
99 }
100
101 // --- end of PollingThread methods
102
DataFetcherSharedMemoryBase()103 DataFetcherSharedMemoryBase::DataFetcherSharedMemoryBase()
104 : started_consumers_(0) {
105 }
106
~DataFetcherSharedMemoryBase()107 DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() {
108 StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
109 StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
110
111 // make sure polling thread stops asap.
112 if (polling_thread_)
113 polling_thread_->Stop();
114
115 STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(),
116 shared_memory_map_.end());
117 }
118
StartFetchingDeviceData(ConsumerType consumer_type)119 bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
120 ConsumerType consumer_type) {
121 if (started_consumers_ & consumer_type)
122 return true;
123
124 void* buffer = GetSharedMemoryBuffer(consumer_type);
125 if (!buffer)
126 return false;
127
128 if (GetType() != FETCHER_TYPE_DEFAULT) {
129 if (!InitAndStartPollingThreadIfNecessary())
130 return false;
131 polling_thread_->message_loop()->PostTask(
132 FROM_HERE,
133 base::Bind(&PollingThread::AddConsumer,
134 base::Unretained(polling_thread_.get()),
135 consumer_type, buffer));
136 } else {
137 if (!Start(consumer_type, buffer))
138 return false;
139 }
140
141 started_consumers_ |= consumer_type;
142
143 return true;
144 }
145
StopFetchingDeviceData(ConsumerType consumer_type)146 bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
147 ConsumerType consumer_type) {
148 if (!(started_consumers_ & consumer_type))
149 return true;
150
151 if (GetType() != FETCHER_TYPE_DEFAULT) {
152 polling_thread_->message_loop()->PostTask(
153 FROM_HERE,
154 base::Bind(&PollingThread::RemoveConsumer,
155 base::Unretained(polling_thread_.get()),
156 consumer_type));
157 } else {
158 if (!Stop(consumer_type))
159 return false;
160 }
161
162 started_consumers_ ^= consumer_type;
163
164 return true;
165 }
166
167 base::SharedMemoryHandle
GetSharedMemoryHandleForProcess(ConsumerType consumer_type,base::ProcessHandle process)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();
173
174 base::SharedMemoryHandle renderer_handle;
175 it->second->ShareToProcess(process, &renderer_handle);
176 return renderer_handle;
177 }
178
InitAndStartPollingThreadIfNecessary()179 bool DataFetcherSharedMemoryBase::InitAndStartPollingThreadIfNecessary() {
180 if (polling_thread_)
181 return true;
182
183 polling_thread_.reset(
184 new PollingThread("Inertial Device Sensor poller", this));
185
186 if (!polling_thread_->Start()) {
187 LOG(ERROR) << "Failed to start inertial sensor data polling thread";
188 return false;
189 }
190 return true;
191 }
192
Fetch(unsigned consumer_bitmask)193 void DataFetcherSharedMemoryBase::Fetch(unsigned consumer_bitmask) {
194 NOTIMPLEMENTED();
195 }
196
197 DataFetcherSharedMemoryBase::FetcherType
GetType() const198 DataFetcherSharedMemoryBase::GetType() const {
199 return FETCHER_TYPE_DEFAULT;
200 }
201
GetInterval() const202 base::TimeDelta DataFetcherSharedMemoryBase::GetInterval() const {
203 return base::TimeDelta::FromMilliseconds(kInertialSensorIntervalMillis);
204 }
205
GetSharedMemory(ConsumerType consumer_type)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())
210 return it->second;
211
212 size_t buffer_size = GetConsumerSharedMemoryBufferSize(consumer_type);
213 if (buffer_size == 0)
214 return NULL;
215
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;
222 return shared_mem;
223 }
224 }
225 LOG(ERROR) << "Failed to initialize shared memory";
226 return NULL;
227 }
228
GetSharedMemoryBuffer(ConsumerType consumer_type)229 void* DataFetcherSharedMemoryBase::GetSharedMemoryBuffer(
230 ConsumerType consumer_type) {
231 if (base::SharedMemory* shared_memory = GetSharedMemory(consumer_type))
232 return shared_memory->memory();
233 return NULL;
234 }
235
GetPollingMessageLoop() const236 base::MessageLoop* DataFetcherSharedMemoryBase::GetPollingMessageLoop() const {
237 return polling_thread_ ? polling_thread_->message_loop() : NULL;
238 }
239
IsPollingTimerRunningForTesting() const240 bool DataFetcherSharedMemoryBase::IsPollingTimerRunningForTesting() const {
241 return polling_thread_ ? polling_thread_->IsTimerRunning() : false;
242 }
243
244
245 } // namespace content
246