summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorscottmg@chromium.org <scottmg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-02 04:41:24 +0000
committerscottmg@chromium.org <scottmg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-02 04:41:24 +0000
commit1ced72566c94c3e7f18b16236ef4ccaa0ec6e04b (patch)
tree47b7d60ed3580341e6a682712d0211f251ce27bf
parent02fea642579c5e875ae65dd1a51a08e000237931 (diff)
downloadchromium_src-1ced72566c94c3e7f18b16236ef4ccaa0ec6e04b.zip
chromium_src-1ced72566c94c3e7f18b16236ef4ccaa0ec6e04b.tar.gz
chromium_src-1ced72566c94c3e7f18b16236ef4ccaa0ec6e04b.tar.bz2
Add GamepadService, owns 1 gamepad bg thread
BUG=79050 Review URL: http://codereview.chromium.org/8760023 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@112638 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/gamepad/gamepad_provider.cc67
-rw-r--r--content/browser/gamepad/gamepad_provider.h24
-rw-r--r--content/browser/gamepad/gamepad_provider_unittest.cc12
-rw-r--r--content/browser/gamepad/gamepad_service.cc76
-rw-r--r--content/browser/gamepad/gamepad_service.h70
-rw-r--r--content/browser/renderer_host/gamepad_browser_message_filter.cc21
-rw-r--r--content/browser/renderer_host/gamepad_browser_message_filter.h13
-rw-r--r--content/browser/renderer_host/render_process_host_impl.cc2
-rw-r--r--content/content_browser.gypi2
9 files changed, 233 insertions, 54 deletions
diff --git a/content/browser/gamepad/gamepad_provider.cc b/content/browser/gamepad/gamepad_provider.cc
index c8eed65..c16245b 100644
--- a/content/browser/gamepad/gamepad_provider.cc
+++ b/content/browser/gamepad/gamepad_provider.cc
@@ -23,8 +23,6 @@
namespace content {
-GamepadProvider* GamepadProvider::instance_ = NULL;
-
// Define the default data fetcher that GamepadProvider will use if none is
// supplied. (GamepadPlatformDataFetcher).
#if defined(OS_WIN)
@@ -44,9 +42,9 @@ typedef GamepadEmptyDataFetcher GamepadPlatformDataFetcher;
#endif
GamepadProvider::GamepadProvider(GamepadDataFetcher* fetcher)
- : creator_loop_(MessageLoop::current()->message_loop_proxy()),
- provided_fetcher_(fetcher),
+ : is_paused_(false),
devices_changed_(true),
+ provided_fetcher_(fetcher),
ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
size_t data_size = sizeof(GamepadHardwareBuffer);
base::SystemMonitor* monitor = base::SystemMonitor::Get();
@@ -55,13 +53,23 @@ GamepadProvider::GamepadProvider(GamepadDataFetcher* fetcher)
gamepad_shared_memory_.CreateAndMapAnonymous(data_size);
GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
memset(hwbuf, 0, sizeof(GamepadHardwareBuffer));
+
+ polling_thread_.reset(new base::Thread("Gamepad polling thread"));
+ polling_thread_->Start();
+
+ MessageLoop* polling_loop = polling_thread_->message_loop();
+ polling_loop->PostTask(
+ FROM_HERE,
+ base::Bind(&GamepadProvider::DoInitializePollingThread, this));
}
GamepadProvider::~GamepadProvider() {
base::SystemMonitor* monitor = base::SystemMonitor::Get();
if (monitor)
monitor->RemoveDevicesChangedObserver(this);
- Stop();
+
+ polling_thread_.reset();
+ data_fetcher_.reset();
}
base::SharedMemoryHandle GamepadProvider::GetRendererSharedMemoryHandle(
@@ -71,34 +79,28 @@ base::SharedMemoryHandle GamepadProvider::GetRendererSharedMemoryHandle(
return renderer_handle;
}
-void GamepadProvider::OnDevicesChanged() {
- devices_changed_ = true;
+void GamepadProvider::Pause() {
+ base::AutoLock lock(is_paused_lock_);
+ is_paused_ = true;
}
-void GamepadProvider::Start() {
- DCHECK(MessageLoop::current()->message_loop_proxy() == creator_loop_);
-
- if (polling_thread_.get())
- return;
-
- polling_thread_.reset(new base::Thread("Gamepad polling thread"));
- if (!polling_thread_->Start()) {
- LOG(ERROR) << "Failed to start gamepad polling thread";
- polling_thread_.reset();
- return;
+void GamepadProvider::Resume() {
+ {
+ base::AutoLock lock(is_paused_lock_);
+ if (!is_paused_)
+ return;
+ is_paused_ = false;
}
MessageLoop* polling_loop = polling_thread_->message_loop();
polling_loop->PostTask(
FROM_HERE,
- base::Bind(&GamepadProvider::DoInitializePollingThread, this));
+ base::Bind(&GamepadProvider::ScheduleDoPoll, this));
}
-void GamepadProvider::Stop() {
- DCHECK(MessageLoop::current()->message_loop_proxy() == creator_loop_);
-
- polling_thread_.reset();
- data_fetcher_.reset();
+void GamepadProvider::OnDevicesChanged() {
+ base::AutoLock lock(devices_changed_lock_);
+ devices_changed_ = true;
}
void GamepadProvider::DoInitializePollingThread() {
@@ -116,6 +118,7 @@ void GamepadProvider::DoInitializePollingThread() {
void GamepadProvider::DoPoll() {
DCHECK(MessageLoop::current() == polling_thread_->message_loop());
+ bool changed;
GamepadHardwareBuffer* hwbuf = SharedMemoryAsHardwareBuffer();
ANNOTATE_BENIGN_RACE_SIZED(
@@ -123,12 +126,18 @@ void GamepadProvider::DoPoll() {
sizeof(WebKit::WebGamepads),
"Racey reads are discarded");
+ {
+ base::AutoLock lock(devices_changed_lock_);
+ changed = devices_changed_;
+ devices_changed_ = false;
+ }
+
// Acquire the SeqLock. There is only ever one writer to this data.
// See gamepad_hardware_buffer.h.
hwbuf->sequence.WriteBegin();
- data_fetcher_->GetGamepadData(&hwbuf->buffer, devices_changed_);
+ data_fetcher_->GetGamepadData(&hwbuf->buffer, changed);
hwbuf->sequence.WriteEnd();
- devices_changed_ = false;
+
// Schedule our next interval of polling.
ScheduleDoPoll();
}
@@ -136,6 +145,12 @@ void GamepadProvider::DoPoll() {
void GamepadProvider::ScheduleDoPoll() {
DCHECK(MessageLoop::current() == polling_thread_->message_loop());
+ {
+ base::AutoLock lock(is_paused_lock_);
+ if (is_paused_)
+ return;
+ }
+
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&GamepadProvider::DoPoll, weak_factory_.GetWeakPtr()),
diff --git a/content/browser/gamepad/gamepad_provider.h b/content/browser/gamepad/gamepad_provider.h
index a40047d..963e768 100644
--- a/content/browser/gamepad/gamepad_provider.h
+++ b/content/browser/gamepad/gamepad_provider.h
@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "base/message_loop_proxy.h"
#include "base/shared_memory.h"
+#include "base/synchronization/lock.h"
#include "base/system_monitor/system_monitor.h"
#include "base/task.h"
#include "content/browser/gamepad/data_fetcher.h"
@@ -29,12 +30,14 @@ class CONTENT_EXPORT GamepadProvider :
public:
explicit GamepadProvider(GamepadDataFetcher* fetcher);
- // Starts or Stops the provider. Called from creator_loop_.
- void Start();
- void Stop();
base::SharedMemoryHandle GetRendererSharedMemoryHandle(
base::ProcessHandle renderer_process);
+ // Pause and resume the background polling thread. Can be called from any
+ // thread.
+ void Pause();
+ void Resume();
+
private:
friend class base::RefCountedThreadSafe<GamepadProvider>;
@@ -53,16 +56,27 @@ class CONTENT_EXPORT GamepadProvider :
enum { kDesiredSamplingIntervalMs = 16 };
+ // Keeps track of when the background thread is paused. Access to is_paused_
+ // must be guarded by is_paused_lock_.
+ base::Lock is_paused_lock_;
+ bool is_paused_;
+
+ // Updated based on notification from SystemMonitor when the system devices
+ // have been updated, and this notification is passed on to the data fetcher
+ // to enable it to avoid redundant (and possibly expensive) is-connected
+ // tests. Access to devices_changed_ must be guarded by
+ // devices_changed_lock_.
+ base::Lock devices_changed_lock_;
+ bool devices_changed_;
+
// The Message Loop on which this object was created.
// Typically the I/O loop, but may be something else during testing.
- scoped_refptr<base::MessageLoopProxy> creator_loop_;
scoped_ptr<GamepadDataFetcher> provided_fetcher_;
// When polling_thread_ is running, members below are only to be used
// from that thread.
scoped_ptr<GamepadDataFetcher> data_fetcher_;
base::SharedMemory gamepad_shared_memory_;
- bool devices_changed_;
// Polling is done on this background thread.
scoped_ptr<base::Thread> polling_thread_;
diff --git a/content/browser/gamepad/gamepad_provider_unittest.cc b/content/browser/gamepad/gamepad_provider_unittest.cc
index b016405..cdc6374 100644
--- a/content/browser/gamepad/gamepad_provider_unittest.cc
+++ b/content/browser/gamepad/gamepad_provider_unittest.cc
@@ -56,15 +56,6 @@ class GamepadProviderTest : public testing::Test {
scoped_refptr<GamepadProvider> provider_;
};
-TEST_F(GamepadProviderTest, BasicStartStop) {
- WebGamepads test_data;
- memset(&test_data, 0, sizeof(test_data));
- GamepadProvider* provider = CreateProvider(test_data);
- provider->Start();
- provider->Stop();
- // Just ensure that there's no asserts on startup, shutdown, or destroy.
-}
-
TEST_F(GamepadProviderTest, PollingAccess) {
WebGamepads test_data;
test_data.length = 1;
@@ -77,7 +68,6 @@ TEST_F(GamepadProviderTest, PollingAccess) {
test_data.items[0].axes[1] = .5f;
GamepadProvider* provider = CreateProvider(test_data);
- provider->Start();
main_message_loop_.RunAllPending();
@@ -107,8 +97,6 @@ TEST_F(GamepadProviderTest, PollingAccess) {
EXPECT_EQ(2u, output.items[0].axesLength);
EXPECT_EQ(-1.f, output.items[0].axes[0]);
EXPECT_EQ(0.5f, output.items[0].axes[1]);
-
- provider->Stop();
}
} // namespace
diff --git a/content/browser/gamepad/gamepad_service.cc b/content/browser/gamepad/gamepad_service.cc
new file mode 100644
index 0000000..a6e90d3
--- /dev/null
+++ b/content/browser/gamepad/gamepad_service.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 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/gamepad/gamepad_service.h"
+
+#include "base/bind.h"
+#include "base/memory/singleton.h"
+#include "content/browser/gamepad/data_fetcher.h"
+#include "content/browser/gamepad/gamepad_provider.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+
+namespace content {
+
+GamepadService::GamepadService() : num_readers_(0) {
+}
+
+GamepadService::~GamepadService() {
+}
+
+GamepadService* GamepadService::GetInstance() {
+ return Singleton<GamepadService>::get();
+}
+
+void GamepadService::Start(
+ GamepadDataFetcher* data_fetcher,
+ content::RenderProcessHost* associated_rph) {
+ num_readers_++;
+ if (!provider_)
+ provider_ = new GamepadProvider(data_fetcher);
+ DCHECK(num_readers_ > 0);
+ provider_->Resume();
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&GamepadService::RegisterForCloseNotification,
+ base::Unretained(this),
+ associated_rph));
+}
+
+void GamepadService::RegisterForCloseNotification(
+ content::RenderProcessHost* rph) {
+ registrar_.Add(this,
+ content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+ content::Source<content::RenderProcessHost>(rph));
+}
+
+base::SharedMemoryHandle GamepadService::GetSharedMemoryHandle(
+ base::ProcessHandle handle) {
+ return provider_->GetRendererSharedMemoryHandle(handle);
+}
+
+void GamepadService::Stop() {
+ --num_readers_;
+ DCHECK(num_readers_ >= 0);
+
+ if (num_readers_ == 0)
+ provider_->Pause();
+}
+
+void GamepadService::Observe(int type,
+ const content::NotificationSource& source,
+ const content::NotificationDetails& details) {
+ DCHECK(type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED);
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&GamepadService::Stop, base::Unretained(this)));
+}
+
+} // namespace content
diff --git a/content/browser/gamepad/gamepad_service.h b/content/browser/gamepad/gamepad_service.h
new file mode 100644
index 0000000..7a00ee6
--- /dev/null
+++ b/content/browser/gamepad/gamepad_service.h
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 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.
+
+// Owns the GamepadProvider (the background polling thread) and keeps track of
+// the number of renderers currently using the data (and pausing the provider
+// when not in use).
+
+#ifndef CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
+#define CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
+
+#include "base/basictypes.h"
+#include "base/memory/singleton.h"
+#include "base/shared_memory.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace content {
+
+class GamepadDataFetcher;
+class GamepadProvider;
+class RenderProcessHost;
+
+class GamepadService : public NotificationObserver {
+ public:
+ // Returns the GamepadService singleton.
+ static GamepadService* GetInstance();
+
+ // Called on IO thread from a renderer host. Increments the number of users
+ // of the provider. The Provider is running when there's > 0 users, and is
+ // paused when the count drops to 0. There is no stop, the gamepad service
+ // registers with the RPH to be notified when the associated renderer closes
+ // (or crashes).
+ void Start(GamepadDataFetcher* fetcher,
+ RenderProcessHost* associated_rph);
+
+ base::SharedMemoryHandle GetSharedMemoryHandle(base::ProcessHandle handle);
+
+ private:
+ friend struct DefaultSingletonTraits<GamepadService>;
+ friend class base::RefCountedThreadSafe<GamepadService>;
+ GamepadService();
+ virtual ~GamepadService();
+
+ // Called when a renderer that Start'd us is closed/crashes.
+ void Stop();
+
+ // Run on UI thread to receive notifications of renderer closes.
+ void RegisterForCloseNotification(RenderProcessHost* rph);
+
+ // NotificationObserver overrides:
+ virtual void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) OVERRIDE;
+
+ // A registrar for listening notifications. Used to listen for when an
+ // associated renderer has gone away (possibly crashed). We don't trust
+ // the renderers to send a stop message because of the possibility of
+ // crashing.
+ NotificationRegistrar registrar_;
+
+ int num_readers_;
+ scoped_refptr<GamepadProvider> provider_;
+
+ DISALLOW_COPY_AND_ASSIGN(GamepadService);
+};
+
+} // namespace content
+
+#endif // CONTENT_BROWSER_GAMEPAD_GAMEPAD_SERVICE_H
diff --git a/content/browser/renderer_host/gamepad_browser_message_filter.cc b/content/browser/renderer_host/gamepad_browser_message_filter.cc
index 683bff5..38d7110 100644
--- a/content/browser/renderer_host/gamepad_browser_message_filter.cc
+++ b/content/browser/renderer_host/gamepad_browser_message_filter.cc
@@ -4,9 +4,14 @@
#include "content/browser/renderer_host/gamepad_browser_message_filter.h"
+#include "content/browser/gamepad/gamepad_service.h"
#include "content/common/gamepad_messages.h"
-GamepadBrowserMessageFilter::GamepadBrowserMessageFilter() {
+namespace content {
+
+GamepadBrowserMessageFilter::GamepadBrowserMessageFilter(
+ content::RenderProcessHost* render_process_host)
+ : render_process_host_(render_process_host) {
}
GamepadBrowserMessageFilter::~GamepadBrowserMessageFilter() {
@@ -28,14 +33,14 @@ bool GamepadBrowserMessageFilter::OnMessageReceived(
void GamepadBrowserMessageFilter::OnGamepadStartPolling(
base::SharedMemoryHandle* renderer_handle) {
- if (!provider_) {
- provider_ = new content::GamepadProvider(NULL);
- provider_->Start();
- }
- *renderer_handle = provider_->GetRendererSharedMemoryHandle(peer_handle());
+ GamepadService* service = GamepadService::GetInstance();
+ service->Start(NULL, render_process_host_);
+ *renderer_handle = service->GetSharedMemoryHandle(peer_handle());
}
void GamepadBrowserMessageFilter::OnGamepadStopPolling() {
- // TODO(scottmg) Remove this message entirely?
- // Stop is currently handled by the refcount on provider_.
+ // TODO(scottmg): Probably get rid of this message. We can't trust it will
+ // arrive anyway if the renderer crashes, etc.
}
+
+} // namespace content
diff --git a/content/browser/renderer_host/gamepad_browser_message_filter.h b/content/browser/renderer_host/gamepad_browser_message_filter.h
index dc991e0..2928b28 100644
--- a/content/browser/renderer_host/gamepad_browser_message_filter.h
+++ b/content/browser/renderer_host/gamepad_browser_message_filter.h
@@ -7,11 +7,18 @@
#pragma once
#include "base/compiler_specific.h"
+#include "base/shared_memory.h"
#include "content/browser/browser_message_filter.h"
-#include "content/browser/gamepad/gamepad_provider.h"
+
+namespace content {
+
+class GamepadService;
+class RenderProcessHost;
class GamepadBrowserMessageFilter : public BrowserMessageFilter {
public:
+ explicit GamepadBrowserMessageFilter(RenderProcessHost* rph);
+
// BrowserMessageFilter implementation.
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE;
@@ -23,9 +30,11 @@ class GamepadBrowserMessageFilter : public BrowserMessageFilter {
void OnGamepadStartPolling(base::SharedMemoryHandle* renderer_handle);
void OnGamepadStopPolling();
- scoped_refptr<content::GamepadProvider> provider_;
+ RenderProcessHost* render_process_host_;
DISALLOW_COPY_AND_ASSIGN(GamepadBrowserMessageFilter);
};
+} // namespace content
+
#endif // CONTENT_BROWSER_RENDERER_HOST_GAMEPAD_BROWSER_MESSAGE_FILTER_H_
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index e9bf8f0..4f05460 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -538,7 +538,7 @@ void RenderProcessHostImpl::CreateMessageFilters() {
channel_->AddFilter(new QuotaDispatcherHost(
GetID(), GetBrowserContext()->GetQuotaManager(),
content::GetContentClient()->browser()->CreateQuotaPermissionContext()));
- channel_->AddFilter(new GamepadBrowserMessageFilter);
+ channel_->AddFilter(new content::GamepadBrowserMessageFilter(this));
channel_->AddFilter(new ProfilerMessageFilter());
}
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 416a8e2..9eb8d58 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -211,6 +211,8 @@
'browser/gamepad/data_fetcher_win.h',
'browser/gamepad/gamepad_provider.cc',
'browser/gamepad/gamepad_provider.h',
+ 'browser/gamepad/gamepad_service.cc',
+ 'browser/gamepad/gamepad_service.h',
'browser/geolocation/access_token_store.cc',
'browser/geolocation/access_token_store.h',
'browser/geolocation/arbitrator_dependency_factory.cc',