summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc')
-rw-r--r--chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc244
1 files changed, 244 insertions, 0 deletions
diff --git a/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
new file mode 100644
index 00000000000..6a9b7d287d3
--- /dev/null
+++ b/chromium/content/browser/device_sensors/data_fetcher_shared_memory_base.cc
@@ -0,0 +1,244 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/device_sensors/data_fetcher_shared_memory_base.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/threading/thread.h"
+#include "base/timer/timer.h"
+#include "content/common/device_sensors/device_motion_hardware_buffer.h"
+#include "content/common/device_sensors/device_orientation_hardware_buffer.h"
+
+namespace content {
+
+namespace {
+
+static size_t GetConsumerSharedMemoryBufferSize(ConsumerType consumer_type) {
+ switch (consumer_type) {
+ case CONSUMER_TYPE_MOTION:
+ return sizeof(DeviceMotionHardwareBuffer);
+ case CONSUMER_TYPE_ORIENTATION:
+ return sizeof(DeviceOrientationHardwareBuffer);
+ default:
+ NOTREACHED();
+ }
+ return 0;
+}
+
+} // namespace
+
+class DataFetcherSharedMemoryBase::PollingThread : public base::Thread {
+ public:
+ PollingThread(const char* name, DataFetcherSharedMemoryBase* fetcher);
+ virtual ~PollingThread();
+
+ void AddConsumer(ConsumerType consumer_type, void* buffer);
+ void RemoveConsumer(ConsumerType consumer_type);
+
+ unsigned GetConsumersBitmask() const { return consumers_bitmask_; }
+ bool IsTimerRunning() const { return timer_ ? timer_->IsRunning() : false; }
+
+ private:
+ void DoPoll();
+
+ unsigned consumers_bitmask_;
+ DataFetcherSharedMemoryBase* fetcher_;
+ scoped_ptr<base::RepeatingTimer<PollingThread> > timer_;
+
+ DISALLOW_COPY_AND_ASSIGN(PollingThread);
+};
+
+// --- PollingThread methods
+
+DataFetcherSharedMemoryBase::PollingThread::PollingThread(
+ const char* name, DataFetcherSharedMemoryBase* fetcher)
+ : base::Thread(name),
+ consumers_bitmask_(0),
+ fetcher_(fetcher) {
+}
+
+DataFetcherSharedMemoryBase::PollingThread::~PollingThread() {
+}
+
+void DataFetcherSharedMemoryBase::PollingThread::AddConsumer(
+ ConsumerType consumer_type, void* buffer) {
+ DCHECK(fetcher_);
+ if (!fetcher_->Start(consumer_type, buffer))
+ return;
+
+ consumers_bitmask_ |= consumer_type;
+
+ if (!timer_ && fetcher_->GetType() == FETCHER_TYPE_POLLING_CALLBACK) {
+ timer_.reset(new base::RepeatingTimer<PollingThread>());
+ timer_->Start(FROM_HERE,
+ fetcher_->GetInterval(),
+ this, &PollingThread::DoPoll);
+ }
+}
+
+void DataFetcherSharedMemoryBase::PollingThread::RemoveConsumer(
+ ConsumerType consumer_type) {
+ DCHECK(fetcher_);
+ if (!fetcher_->Stop(consumer_type))
+ return;
+
+ consumers_bitmask_ ^= consumer_type;
+
+ if (!consumers_bitmask_)
+ timer_.reset(); // will also stop the timer.
+}
+
+void DataFetcherSharedMemoryBase::PollingThread::DoPoll() {
+ DCHECK(fetcher_);
+ DCHECK(consumers_bitmask_);
+ fetcher_->Fetch(consumers_bitmask_);
+}
+
+// --- end of PollingThread methods
+
+DataFetcherSharedMemoryBase::DataFetcherSharedMemoryBase()
+ : started_consumers_(0) {
+}
+
+DataFetcherSharedMemoryBase::~DataFetcherSharedMemoryBase() {
+ StopFetchingDeviceData(CONSUMER_TYPE_MOTION);
+ StopFetchingDeviceData(CONSUMER_TYPE_ORIENTATION);
+
+ // make sure polling thread stops asap.
+ if (polling_thread_)
+ polling_thread_->Stop();
+
+ STLDeleteContainerPairSecondPointers(shared_memory_map_.begin(),
+ shared_memory_map_.end());
+}
+
+bool DataFetcherSharedMemoryBase::StartFetchingDeviceData(
+ ConsumerType consumer_type) {
+ if (started_consumers_ & consumer_type)
+ return true;
+
+ void* buffer = GetSharedMemoryBuffer(consumer_type);
+ if (!buffer)
+ return false;
+
+ if (GetType() != FETCHER_TYPE_DEFAULT) {
+ if (!InitAndStartPollingThreadIfNecessary())
+ return false;
+ polling_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PollingThread::AddConsumer,
+ base::Unretained(polling_thread_.get()),
+ consumer_type, buffer));
+ } else {
+ if (!Start(consumer_type, buffer))
+ return false;
+ }
+
+ started_consumers_ |= consumer_type;
+
+ return true;
+}
+
+bool DataFetcherSharedMemoryBase::StopFetchingDeviceData(
+ ConsumerType consumer_type) {
+ if (!(started_consumers_ & consumer_type))
+ return true;
+
+ if (GetType() != FETCHER_TYPE_DEFAULT) {
+ polling_thread_->message_loop()->PostTask(
+ FROM_HERE,
+ base::Bind(&PollingThread::RemoveConsumer,
+ base::Unretained(polling_thread_.get()),
+ consumer_type));
+ } else {
+ if (!Stop(consumer_type))
+ return false;
+ }
+
+ started_consumers_ ^= consumer_type;
+
+ return true;
+}
+
+base::SharedMemoryHandle
+DataFetcherSharedMemoryBase::GetSharedMemoryHandleForProcess(
+ ConsumerType consumer_type, base::ProcessHandle process) {
+ SharedMemoryMap::const_iterator it = shared_memory_map_.find(consumer_type);
+ if (it == shared_memory_map_.end())
+ return base::SharedMemory::NULLHandle();
+
+ base::SharedMemoryHandle renderer_handle;
+ it->second->ShareToProcess(process, &renderer_handle);
+ return renderer_handle;
+}
+
+bool DataFetcherSharedMemoryBase::InitAndStartPollingThreadIfNecessary() {
+ if (polling_thread_)
+ return true;
+
+ polling_thread_.reset(
+ new PollingThread("Inertial Device Sensor poller", this));
+
+ if (!polling_thread_->Start()) {
+ LOG(ERROR) << "Failed to start inertial sensor data polling thread";
+ return false;
+ }
+ return true;
+}
+
+void DataFetcherSharedMemoryBase::Fetch(unsigned consumer_bitmask) {
+ NOTIMPLEMENTED();
+}
+
+DataFetcherSharedMemoryBase::FetcherType
+DataFetcherSharedMemoryBase::GetType() const {
+ return FETCHER_TYPE_DEFAULT;
+}
+
+base::TimeDelta DataFetcherSharedMemoryBase::GetInterval() const {
+ return base::TimeDelta::FromMilliseconds(kInertialSensorIntervalMillis);
+}
+
+base::SharedMemory* DataFetcherSharedMemoryBase::GetSharedMemory(
+ ConsumerType consumer_type) {
+ SharedMemoryMap::const_iterator it = shared_memory_map_.find(consumer_type);
+ if (it != shared_memory_map_.end())
+ return it->second;
+
+ size_t buffer_size = GetConsumerSharedMemoryBufferSize(consumer_type);
+ if (buffer_size == 0)
+ return NULL;
+
+ scoped_ptr<base::SharedMemory> new_shared_mem(new base::SharedMemory);
+ if (new_shared_mem->CreateAndMapAnonymous(buffer_size)) {
+ if (void* mem = new_shared_mem->memory()) {
+ memset(mem, 0, buffer_size);
+ base::SharedMemory* shared_mem = new_shared_mem.release();
+ shared_memory_map_[consumer_type] = shared_mem;
+ return shared_mem;
+ }
+ }
+ LOG(ERROR) << "Failed to initialize shared memory";
+ return NULL;
+}
+
+void* DataFetcherSharedMemoryBase::GetSharedMemoryBuffer(
+ ConsumerType consumer_type) {
+ if (base::SharedMemory* shared_memory = GetSharedMemory(consumer_type))
+ return shared_memory->memory();
+ return NULL;
+}
+
+base::MessageLoop* DataFetcherSharedMemoryBase::GetPollingMessageLoop() const {
+ return polling_thread_ ? polling_thread_->message_loop() : NULL;
+}
+
+bool DataFetcherSharedMemoryBase::IsPollingTimerRunningForTesting() const {
+ return polling_thread_ ? polling_thread_->IsTimerRunning() : false;
+}
+
+
+} // namespace content