diff options
author | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 23:57:42 +0000 |
---|---|---|
committer | sergeyu@chromium.org <sergeyu@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-16 23:57:42 +0000 |
commit | 195266b9bc120ccec02b8a027c6f204aa21dde50 (patch) | |
tree | 16df27b1f30623c39abc18a27bb57572ddabeb1c | |
parent | 8bd9e5623c17e845acbc182772b63f818f1d0bd5 (diff) | |
download | chromium_src-195266b9bc120ccec02b8a027c6f204aa21dde50.zip chromium_src-195266b9bc120ccec02b8a027c6f204aa21dde50.tar.gz chromium_src-195266b9bc120ccec02b8a027c6f204aa21dde50.tar.bz2 |
Add PluginMessageLoopProxy and use it for Host plugin UI thread.
The new class will also be used in the client plugin for the main plugin thread.
BUG=None
TEST=Everything works.
Review URL: http://codereview.chromium.org/7635030
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@97060 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | remoting/base/plugin_message_loop_proxy.cc | 114 | ||||
-rw-r--r-- | remoting/base/plugin_message_loop_proxy.h | 80 | ||||
-rw-r--r-- | remoting/host/chromoting_host_context.cc | 37 | ||||
-rw-r--r-- | remoting/host/chromoting_host_context.h | 22 | ||||
-rw-r--r-- | remoting/host/chromoting_host_context_unittest.cc | 6 | ||||
-rw-r--r-- | remoting/host/chromoting_host_unittest.cc | 8 | ||||
-rw-r--r-- | remoting/host/desktop_environment.cc | 48 | ||||
-rw-r--r-- | remoting/host/host_mock_objects.cc | 6 | ||||
-rw-r--r-- | remoting/host/host_mock_objects.h | 2 | ||||
-rw-r--r-- | remoting/host/plugin/host_plugin.cc | 53 | ||||
-rw-r--r-- | remoting/host/plugin/host_script_object.cc | 50 | ||||
-rw-r--r-- | remoting/host/plugin/host_script_object.h | 13 | ||||
-rw-r--r-- | remoting/host/simple_host_process.cc | 9 | ||||
-rw-r--r-- | remoting/remoting.gyp | 2 |
14 files changed, 317 insertions, 133 deletions
diff --git a/remoting/base/plugin_message_loop_proxy.cc b/remoting/base/plugin_message_loop_proxy.cc new file mode 100644 index 0000000..0f6c668 --- /dev/null +++ b/remoting/base/plugin_message_loop_proxy.cc @@ -0,0 +1,114 @@ +// 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 "remoting/base/plugin_message_loop_proxy.h" + +namespace remoting { + +PluginMessageLoopProxy::PluginMessageLoopProxy(Delegate* delegate) + : delegate_(delegate) { +} + +PluginMessageLoopProxy::~PluginMessageLoopProxy() { +} + +void PluginMessageLoopProxy::Detach() { + base::AutoLock auto_lock(lock_); + delegate_ = NULL; +} + +// MessageLoopProxy interface implementation. +bool PluginMessageLoopProxy::PostTask( + const tracked_objects::Location& from_here, + Task* task) { + return PostDelayedTask(from_here, task, 0); +} + +bool PluginMessageLoopProxy::PostDelayedTask( + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) { + base::AutoLock auto_lock(lock_); + if (!delegate_) { + return false; + } else { + return delegate_->RunOnPluginThread( + delay_ms, &PluginMessageLoopProxy::RunTask, task); + } +} + +bool PluginMessageLoopProxy::PostNonNestableTask( + const tracked_objects::Location& from_here, + Task* task) { + // All tasks running on this message loop are non-nestable. + return PostTask(from_here, task); +} + +bool PluginMessageLoopProxy::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) { + // All tasks running on this message loop are non-nestable. + return PostDelayedTask(from_here, task, delay_ms); +} + +bool PluginMessageLoopProxy::PostTask( + const tracked_objects::Location& from_here, + const base::Closure& task) { + return PostDelayedTask(from_here, task, 0); +} + +bool PluginMessageLoopProxy::PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) { + base::AutoLock auto_lock(lock_); + if (!delegate_) { + return false; + } else { + base::Closure* task_on_heap = new base::Closure(task); + return delegate_->RunOnPluginThread( + delay_ms, &PluginMessageLoopProxy::RunClosure, task_on_heap); + } +} + +bool PluginMessageLoopProxy::PostNonNestableTask( + const tracked_objects::Location& from_here, + const base::Closure& task) { + // All tasks running on this message loop are non-nestable. + return PostTask(from_here, task); +} + +bool PluginMessageLoopProxy::PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) { + // All tasks running on this message loop are non-nestable. + return PostDelayedTask(from_here, task, delay_ms); +} + +bool PluginMessageLoopProxy::BelongsToCurrentThread() { + base::AutoLock auto_lock(lock_); + if (delegate_) { + return delegate_->IsPluginThread(); + } else { + return false; + } +} + +// static +void PluginMessageLoopProxy::RunTask(void* data) { + Task* task = reinterpret_cast<Task*>(data); + task->Run(); + delete task; +} + +// static +void PluginMessageLoopProxy::RunClosure(void* data) { + base::Closure* task = reinterpret_cast<base::Closure*>(data); + task->Run(); + delete task; +} + +} // namespace remoting diff --git a/remoting/base/plugin_message_loop_proxy.h b/remoting/base/plugin_message_loop_proxy.h new file mode 100644 index 0000000..7b2eef2 --- /dev/null +++ b/remoting/base/plugin_message_loop_proxy.h @@ -0,0 +1,80 @@ +// 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. + +#ifndef REMOTING_BASE_PLUGIN_MESSAGE_LOOP_H_ +#define REMOTING_BASE_PLUGIN_MESSAGE_LOOP_H_ + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/message_loop_proxy.h" +#include "base/synchronization/lock.h" + +namespace remoting { + +// MessageLoopProxy for plugin main threads. +class PluginMessageLoopProxy : public base::MessageLoopProxy { + public: + class Delegate { + public: + Delegate() { } + virtual ~Delegate() { } + + virtual bool RunOnPluginThread( + int delay_ms, void(function)(void*), void* data) = 0; + virtual bool IsPluginThread() = 0; + }; + + // Caller keeps ownership of delegate. + PluginMessageLoopProxy(Delegate* delegate); + virtual ~PluginMessageLoopProxy(); + + void Detach(); + + // base::MessageLoopProxy interface. + virtual bool PostTask( + const tracked_objects::Location& from_here, + Task* task) OVERRIDE; + virtual bool PostDelayedTask( + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) OVERRIDE; + virtual bool PostNonNestableTask( + const tracked_objects::Location& from_here, + Task* task) OVERRIDE; + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + Task* task, + int64 delay_ms) OVERRIDE; + + virtual bool PostTask( + const tracked_objects::Location& from_here, + const base::Closure& task) OVERRIDE; + virtual bool PostDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) OVERRIDE; + virtual bool PostNonNestableTask( + const tracked_objects::Location& from_here, + const base::Closure& task) OVERRIDE; + virtual bool PostNonNestableDelayedTask( + const tracked_objects::Location& from_here, + const base::Closure& task, + int64 delay_ms) OVERRIDE; + + virtual bool BelongsToCurrentThread() OVERRIDE; + + private: + // |lock_| must be acquired when accessing |delegate_|. + base::Lock lock_; + Delegate* delegate_; + + static void RunTask(void* data); + static void RunClosure(void* data); + + DISALLOW_COPY_AND_ASSIGN(PluginMessageLoopProxy); +}; + +} // namespace remoting + +#endif // REMOTING_BASE_PLUGIN_MESSAGE_LOOP_H_ diff --git a/remoting/host/chromoting_host_context.cc b/remoting/host/chromoting_host_context.cc index de99a1f..6f02943 100644 --- a/remoting/host/chromoting_host_context.cc +++ b/remoting/host/chromoting_host_context.cc @@ -12,10 +12,12 @@ namespace remoting { -ChromotingHostContext::ChromotingHostContext() +ChromotingHostContext::ChromotingHostContext( + base::MessageLoopProxy* ui_message_loop) : main_thread_("ChromotingMainThread"), encode_thread_("ChromotingEncodeThread"), - desktop_thread_("ChromotingDesktopThread") { + desktop_thread_("ChromotingDesktopThread"), + ui_message_loop_(ui_message_loop) { } ChromotingHostContext::~ChromotingHostContext() { @@ -41,6 +43,10 @@ JingleThread* ChromotingHostContext::jingle_thread() { return &jingle_thread_; } +base::MessageLoopProxy* ChromotingHostContext::ui_message_loop() { + return ui_message_loop_; +} + MessageLoop* ChromotingHostContext::main_message_loop() { return main_thread_.message_loop(); } @@ -57,31 +63,4 @@ MessageLoop* ChromotingHostContext::desktop_message_loop() { return desktop_thread_.message_loop(); } -void ChromotingHostContext::SetUITaskPostFunction( - const UIThreadPostTaskFunction& poster) { - ui_poster_ = poster; - ui_main_thread_id_ = base::PlatformThread::CurrentId(); -} - -void ChromotingHostContext::PostTaskToUIThread( - const tracked_objects::Location& from_here, const base::Closure& task) { - ui_poster_.Run(from_here, task); -} - -void ChromotingHostContext::PostDelayedTaskToUIThread( - const tracked_objects::Location& from_here, - const base::Closure& task, - int delay_ms) { - // Post delayed task on the main thread that will post task on UI - // thread. It is safe to use base::Unretained() here because - // ChromotingHostContext owns |main_thread_|. - main_message_loop()->PostDelayedTask(from_here, base::Bind( - &ChromotingHostContext::PostTaskToUIThread, base::Unretained(this), - from_here, task), delay_ms); -} - -bool ChromotingHostContext::IsUIThread() const { - return ui_main_thread_id_ == base::PlatformThread::CurrentId(); -} - } // namespace remoting diff --git a/remoting/host/chromoting_host_context.h b/remoting/host/chromoting_host_context.h index 38f1cae..d2ab3e6 100644 --- a/remoting/host/chromoting_host_context.h +++ b/remoting/host/chromoting_host_context.h @@ -25,12 +25,8 @@ namespace remoting { // process. This class is virtual only for testing purposes (see below). class ChromotingHostContext { public: - typedef base::Callback<void( - const tracked_objects::Location& from_here, - const base::Closure& task)> UIThreadPostTaskFunction; - // Create a context. - ChromotingHostContext(); + ChromotingHostContext(base::MessageLoopProxy* ui_message_loop); virtual ~ChromotingHostContext(); // TODO(ajwong): Move the Start/Stop methods out of this class. Then @@ -42,21 +38,12 @@ class ChromotingHostContext { virtual JingleThread* jingle_thread(); + virtual base::MessageLoopProxy* ui_message_loop(); virtual MessageLoop* main_message_loop(); virtual MessageLoop* encode_message_loop(); virtual base::MessageLoopProxy* network_message_loop(); virtual MessageLoop* desktop_message_loop(); - // Must be called from the main GUI thread. - void SetUITaskPostFunction(const UIThreadPostTaskFunction& poster); - - void PostTaskToUIThread(const tracked_objects::Location& from_here, - const base::Closure& task); - void PostDelayedTaskToUIThread(const tracked_objects::Location& from_here, - const base::Closure& task, - int delay_ms); - bool IsUIThread() const; - private: FRIEND_TEST_ALL_PREFIXES(ChromotingHostContextTest, StartAndStop); @@ -73,10 +60,7 @@ class ChromotingHostContext { // This is NOT a Chrome-style UI thread. base::Thread desktop_thread_; - UIThreadPostTaskFunction ui_poster_; - // This IS the main Chrome GUI thread that |ui_poster_| will post to. - base::PlatformThreadId ui_main_thread_id_; - + scoped_refptr<base::MessageLoopProxy> ui_message_loop_; DISALLOW_COPY_AND_ASSIGN(ChromotingHostContext); }; diff --git a/remoting/host/chromoting_host_context_unittest.cc b/remoting/host/chromoting_host_context_unittest.cc index 21bcab8..3d857b3 100644 --- a/remoting/host/chromoting_host_context_unittest.cc +++ b/remoting/host/chromoting_host_context_unittest.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/message_loop.h" +#include "base/message_loop_proxy.h" #include "remoting/host/chromoting_host_context.h" #include "testing/gtest/include/gtest/gtest.h" @@ -11,7 +12,10 @@ namespace remoting { // A simple test that starts and stop the context. This tests the context // operates properly and all threads and message loops are valid. TEST(ChromotingHostContextTest, StartAndStop) { - ChromotingHostContext context; + MessageLoop message_loop; + ChromotingHostContext context( + base::MessageLoopProxy::current()); + context.Start(); EXPECT_TRUE(context.jingle_thread()); EXPECT_TRUE(context.main_message_loop()); diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc index 129d922..0842832 100644 --- a/remoting/host/chromoting_host_unittest.cc +++ b/remoting/host/chromoting_host_unittest.cc @@ -78,7 +78,7 @@ class ChromotingHostTest : public testing::Test { ON_CALL(context_, network_message_loop()) .WillByDefault(Return(message_loop_proxy_.get())); ON_CALL(context_, ui_message_loop()) - .WillByDefault(Return(&message_loop_)); + .WillByDefault(Return(message_loop_proxy_.get())); EXPECT_CALL(context_, main_message_loop()) .Times(AnyNumber()); EXPECT_CALL(context_, encode_message_loop()) @@ -88,12 +88,6 @@ class ChromotingHostTest : public testing::Test { EXPECT_CALL(context_, ui_message_loop()) .Times(AnyNumber()); - context_.SetUITaskPostFunction(base::Bind( - static_cast<void(MessageLoop::*)( - const tracked_objects::Location&, - const base::Closure&)>(&MessageLoop::PostTask), - base::Unretained(&message_loop_))); - Capturer* capturer = new CapturerFake(); event_executor_ = new MockEventExecutor(); curtain_ = new MockCurtain(); diff --git a/remoting/host/desktop_environment.cc b/remoting/host/desktop_environment.cc index 8377ac7..bdc7ded 100644 --- a/remoting/host/desktop_environment.cc +++ b/remoting/host/desktop_environment.cc @@ -23,21 +23,30 @@ namespace remoting { // thread. This is neccessary so that DesktopEnvironment can be // deleted synchronously even while there are pending tasks on the // message queue. +// +// TODO(sergeyu): Merge this code with remoting::TaskThreadProxy. The +// problem solved by this class is very simular to the one solved by +// ScopedRunnableMethodFactory. The main difference is that this class +// is thread-safe. Change the interface to make it look more like +// ScopedRunnableMethodFactory and rename it to avoid confusion with +// MessageLoopProxy. class UIThreadProxy : public base::RefCountedThreadSafe<UIThreadProxy> { public: - UIThreadProxy(ChromotingHostContext* context) - : context_(context) { + UIThreadProxy(base::MessageLoopProxy* message_loop) + : message_loop_(message_loop) { } + // TODO(sergeyu): Rename this method. void Detach() { - DCHECK(context_->IsUIThread()); - context_ = NULL; + DCHECK(message_loop_->BelongsToCurrentThread()); + message_loop_ = NULL; } void CallOnUIThread(const tracked_objects::Location& from_here, const base::Closure& closure) { - if (context_) { - context_->PostTaskToUIThread(from_here, base::Bind( + scoped_refptr<base::MessageLoopProxy> message_loop = message_loop_; + if (message_loop) { + message_loop->PostTask(from_here, base::Bind( &UIThreadProxy::CallClosure, this, closure)); } } @@ -45,8 +54,9 @@ class UIThreadProxy : public base::RefCountedThreadSafe<UIThreadProxy> { void CallOnUIThreadDelayed(const tracked_objects::Location& from_here, const base::Closure& closure, int delay_ms) { - if (context_) { - context_->PostDelayedTaskToUIThread(from_here, base::Bind( + scoped_refptr<base::MessageLoopProxy> message_loop = message_loop_; + if (message_loop) { + message_loop->PostDelayedTask(from_here, base::Bind( &UIThreadProxy::CallClosure, this, closure), delay_ms); } } @@ -57,11 +67,11 @@ class UIThreadProxy : public base::RefCountedThreadSafe<UIThreadProxy> { virtual ~UIThreadProxy() { } void CallClosure(const base::Closure& closure) { - if (context_) + if (message_loop_) closure.Run(); } - ChromotingHostContext* context_; + scoped_refptr<base::MessageLoopProxy> message_loop_; DISALLOW_COPY_AND_ASSIGN(UIThreadProxy); }; @@ -98,14 +108,14 @@ DesktopEnvironment::DesktopEnvironment(ChromotingHostContext* context, local_input_monitor_(local_input_monitor), is_monitoring_local_inputs_(false), continue_timer_started_(false), - proxy_(new UIThreadProxy(context)) { + proxy_(new UIThreadProxy(context->ui_message_loop())) { } DesktopEnvironment::~DesktopEnvironment() { } void DesktopEnvironment::Shutdown() { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); MonitorLocalInputs(false); ShowDisconnectWindow(false, std::string()); @@ -131,7 +141,7 @@ void DesktopEnvironment::OnPause(bool pause) { } void DesktopEnvironment::ProcessOnConnect(const std::string& username) { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); MonitorLocalInputs(true); ShowDisconnectWindow(true, username); @@ -139,7 +149,7 @@ void DesktopEnvironment::ProcessOnConnect(const std::string& username) { } void DesktopEnvironment::ProcessOnLastDisconnect() { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); MonitorLocalInputs(false); ShowDisconnectWindow(false, std::string()); @@ -152,7 +162,7 @@ void DesktopEnvironment::ProcessOnPause(bool pause) { } void DesktopEnvironment::MonitorLocalInputs(bool enable) { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); if (enable == is_monitoring_local_inputs_) return; @@ -166,7 +176,7 @@ void DesktopEnvironment::MonitorLocalInputs(bool enable) { void DesktopEnvironment::ShowDisconnectWindow(bool show, const std::string& username) { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); if (show) { disconnect_window_->Show(host_, username); @@ -176,7 +186,7 @@ void DesktopEnvironment::ShowDisconnectWindow(bool show, } void DesktopEnvironment::ShowContinueWindow(bool show) { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); if (show) { continue_window_->Show(host_); @@ -186,7 +196,7 @@ void DesktopEnvironment::ShowContinueWindow(bool show) { } void DesktopEnvironment::StartContinueWindowTimer(bool start) { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); if (start && !continue_timer_started_) { continue_timer_target_time_ = base::Time::Now() + @@ -201,7 +211,7 @@ void DesktopEnvironment::StartContinueWindowTimer(bool start) { } void DesktopEnvironment::ContinueWindowTimerFunc() { - DCHECK(context_->IsUIThread()); + DCHECK(context_->ui_message_loop()->BelongsToCurrentThread()); // This function may be called prematurely if timer was stopped and // then started again. In that case we just ignore this call. diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index de0ea97..1af08ee 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc @@ -4,6 +4,8 @@ #include "remoting/host/host_mock_objects.h" +#include "base/message_loop_proxy.h" + namespace remoting { MockCapturer::MockCapturer() {} @@ -46,7 +48,9 @@ LocalInputMonitor* LocalInputMonitor::Create() { return new MockLocalInputMonitor(); } -MockChromotingHostContext::MockChromotingHostContext() {} +MockChromotingHostContext::MockChromotingHostContext() + : ChromotingHostContext(base::MessageLoopProxy::current()) { +} MockChromotingHostContext::~MockChromotingHostContext() {} diff --git a/remoting/host/host_mock_objects.h b/remoting/host/host_mock_objects.h index 5a627ea..67aed7c 100644 --- a/remoting/host/host_mock_objects.h +++ b/remoting/host/host_mock_objects.h @@ -81,10 +81,10 @@ class MockChromotingHostContext : public ChromotingHostContext { MOCK_METHOD0(Start, void()); MOCK_METHOD0(Stop, void()); MOCK_METHOD0(jingle_thread, JingleThread*()); + MOCK_METHOD0(ui_message_loop, base::MessageLoopProxy*()); MOCK_METHOD0(main_message_loop, MessageLoop*()); MOCK_METHOD0(encode_message_loop, MessageLoop*()); MOCK_METHOD0(network_message_loop, base::MessageLoopProxy*()); - MOCK_METHOD0(ui_message_loop, MessageLoop*()); private: DISALLOW_COPY_AND_ASSIGN(MockChromotingHostContext); diff --git a/remoting/host/plugin/host_plugin.cc b/remoting/host/plugin/host_plugin.cc index f901a03..0776372 100644 --- a/remoting/host/plugin/host_plugin.cc +++ b/remoting/host/plugin/host_plugin.cc @@ -12,6 +12,7 @@ #include "base/basictypes.h" #include "base/logging.h" #include "base/stringize_macros.h" +#include "remoting/base/plugin_message_loop_proxy.h" #include "remoting/host/plugin/host_plugin_utils.h" #include "remoting/host/plugin/host_script_object.h" #include "third_party/npapi/bindings/npapi.h" @@ -58,7 +59,7 @@ base::AtExitManager* g_at_exit_manager = NULL; // NPAPI plugin implementation for remoting host. // Documentation for most of the calls in this class can be found here: // https://developer.mozilla.org/en/Gecko_Plugin_API_Reference/Scripting_plugins -class HostNPPlugin { +class HostNPPlugin : public remoting::PluginMessageLoopProxy::Delegate { public: // |mode| is the display mode of plug-in. Values: // NP_EMBED: (1) Instance was created by an EMBED tag and shares the browser @@ -66,7 +67,10 @@ class HostNPPlugin { // NP_FULL: (2) Instance was created by a separate file and is the primary // content in the window. HostNPPlugin(NPP instance, uint16 mode) - : instance_(instance), scriptable_object_(NULL) {} + : instance_(instance), + scriptable_object_(NULL), + np_thread_id_(base::PlatformThread::CurrentId()) { + } ~HostNPPlugin() { if (scriptable_object_) { @@ -146,11 +150,49 @@ class HostNPPlugin { return scriptable_object_; } + // PluginMessageLoopProxy::Delegate implementation. + virtual bool RunOnPluginThread( + int delay_ms, void(function)(void*), void* data) OVERRIDE { + if (delay_ms == 0) { + g_npnetscape_funcs->pluginthreadasynccall(instance_, function, data); + } else { + base::AutoLock auto_lock(timers_lock_); + uint32_t timer_id = g_npnetscape_funcs->scheduletimer( + instance_, delay_ms, false, &NPDelayedTaskSpringboard); + DelayedTask task = {function, data}; + timers_[timer_id] = task; + } + return true; + } + + virtual bool IsPluginThread() OVERRIDE { + return np_thread_id_ == base::PlatformThread::CurrentId(); + } + + static void NPDelayedTaskSpringboard(NPP npp, uint32_t timer_id) { + HostNPPlugin* self = reinterpret_cast<HostNPPlugin*>(npp->pdata); + DelayedTask task; + { + base::AutoLock auto_lock(self->timers_lock_); + std::map<uint32_t, DelayedTask>::iterator it = + self->timers_.find(timer_id); + CHECK(it != self->timers_.end()); + task = it->second; + self->timers_.erase(it); + } + task.function(task.data); + } + private: struct ScriptableNPObject : public NPObject { HostNPScriptObject* scriptable_object; }; + struct DelayedTask { + void (*function)(void*); + void* data; + }; + static HostNPScriptObject* ScriptableFromObject(NPObject* obj) { return reinterpret_cast<ScriptableNPObject*>(obj)->scriptable_object; } @@ -160,10 +202,11 @@ class HostNPPlugin { ScriptableNPObject* object = reinterpret_cast<ScriptableNPObject*>( g_npnetscape_funcs->memalloc(sizeof(ScriptableNPObject))); + HostNPPlugin* plugin = reinterpret_cast<HostNPPlugin*>(npp->pdata); object->_class = aClass; object->referenceCount = 1; - object->scriptable_object = new HostNPScriptObject(npp, object); + object->scriptable_object = new HostNPScriptObject(npp, object, plugin); if (!object->scriptable_object->Init()) { Deallocate(object); object = NULL; @@ -290,6 +333,10 @@ class HostNPPlugin { NPP instance_; NPObject* scriptable_object_; + + base::PlatformThreadId np_thread_id_; + std::map<uint32_t, DelayedTask> timers_; + base::Lock timers_lock_; }; // Utility functions to map NPAPI Entry Points to C++ Objects. diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc index 8b100c4..5d26050 100644 --- a/remoting/host/plugin/host_script_object.cc +++ b/remoting/host/plugin/host_script_object.cc @@ -78,11 +78,17 @@ static bool g_logging_to_plugin = false; static HostNPScriptObject* g_logging_scriptable_object = NULL; static logging::LogMessageHandlerFunction g_logging_old_handler = NULL; -HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) +HostNPScriptObject::HostNPScriptObject( + NPP plugin, + NPObject* parent, + PluginMessageLoopProxy::Delegate* plugin_thread_delegate) : plugin_(plugin), parent_(parent), state_(kDisconnected), np_thread_id_(base::PlatformThread::CurrentId()), + plugin_message_loop_proxy_( + new PluginMessageLoopProxy(plugin_thread_delegate)), + host_context_(plugin_message_loop_proxy_), failed_login_attempts_(0), disconnected_event_(true, false), nat_traversal_enabled_(false), @@ -99,10 +105,6 @@ HostNPScriptObject::HostNPScriptObject(NPP plugin, NPObject* parent) g_logging_old_handler = logging::GetLogMessageHandler(); logging::SetLogMessageHandler(&LogToUI); g_logging_scriptable_object = this; - - VLOG(2) << "HostNPScriptObject"; - host_context_.SetUITaskPostFunction(base::Bind( - &HostNPScriptObject::PostTaskToNPThread, base::Unretained(this))); } HostNPScriptObject::~HostNPScriptObject() { @@ -116,6 +118,8 @@ HostNPScriptObject::~HostNPScriptObject() { g_logging_old_handler = NULL; g_logging_scriptable_object = NULL; + plugin_message_loop_proxy_->Detach(); + // Stop listening for policy updates. if (nat_policy_.get()) { base::WaitableEvent nat_policy_stopped_(true, false); @@ -128,7 +132,6 @@ HostNPScriptObject::~HostNPScriptObject() { // here because |host_context_| needs to be stopped on the plugin // thread, but the plugin thread may not exist after the instance // is destroyed. - destructing_.Set(); disconnected_event_.Reset(); DisconnectInternal(); disconnected_event_.Wait(); @@ -577,11 +580,8 @@ void HostNPScriptObject::OnReceivedSupportID( } void HostNPScriptObject::OnStateChanged(State state) { - if (destructing_.IsSet()) - return; - - if (!host_context_.IsUIThread()) { - host_context_.PostTaskToUIThread( + if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { + plugin_message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&HostNPScriptObject::OnStateChanged, base::Unretained(this), state)); return; @@ -615,11 +615,8 @@ bool HostNPScriptObject::LogToUI(int severity, const char* file, int line, } void HostNPScriptObject::LogDebugInfo(const std::string& message) { - if (destructing_.IsSet()) - return; - - if (!host_context_.IsUIThread()) { - host_context_.PostTaskToUIThread( + if (!plugin_message_loop_proxy_->BelongsToCurrentThread()) { + plugin_message_loop_proxy_->PostTask( FROM_HERE, base::Bind(&HostNPScriptObject::LogDebugInfo, base::Unretained(this), message)); return; @@ -704,25 +701,4 @@ bool HostNPScriptObject::InvokeAndIgnoreResult(NPObject* func, return is_good; } -void HostNPScriptObject::PostTaskToNPThread( - const tracked_objects::Location& from_here, const base::Closure& task) { - // The NPAPI functions cannot make use of |from_here|, but this method is - // passed as a callback to ChromotingHostContext, so it needs to have the - // appropriate signature. - - // Copy task to the heap so that we can pass it to NPTaskSpringboard(). - base::Closure* task_in_heap = new base::Closure(task); - - // Can be called from any thread. - g_npnetscape_funcs->pluginthreadasynccall(plugin_, &NPTaskSpringboard, - task_in_heap); -} - -// static -void HostNPScriptObject::NPTaskSpringboard(void* task) { - base::Closure* real_task = reinterpret_cast<base::Closure*>(task); - real_task->Run(); - delete real_task; -} - } // namespace remoting diff --git a/remoting/host/plugin/host_script_object.h b/remoting/host/plugin/host_script_object.h index 2d776ad..04a35b4 100644 --- a/remoting/host/plugin/host_script_object.h +++ b/remoting/host/plugin/host_script_object.h @@ -15,6 +15,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/platform_thread.h" #include "base/time.h" +#include "remoting/base/plugin_message_loop_proxy.h" #include "remoting/host/chromoting_host_context.h" #include "remoting/host/host_status_observer.h" #include "remoting/host/plugin/host_plugin_utils.h" @@ -45,7 +46,8 @@ class NatPolicy; // destroyed it sychronously shuts down the host and all threads. class HostNPScriptObject : public HostStatusObserver { public: - HostNPScriptObject(NPP plugin, NPObject* parent); + HostNPScriptObject(NPP plugin, NPObject* parent, + PluginMessageLoopProxy::Delegate* plugin_thread_delegate); virtual ~HostNPScriptObject(); bool Init(); @@ -142,13 +144,6 @@ class HostNPScriptObject : public HostStatusObserver { const NPVariant* args, uint32_t argCount); - // Posts a task on the main NP thread. - void PostTaskToNPThread( - const tracked_objects::Location& from_here, const base::Closure& task); - - // Utility function for PostTaskToNPThread. - static void NPTaskSpringboard(void* task); - // Set an exception for the current call. void SetException(const std::string& exception_string); @@ -162,6 +157,7 @@ class HostNPScriptObject : public HostStatusObserver { ScopedRefNPObject log_debug_info_func_; ScopedRefNPObject on_state_changed_func_; base::PlatformThreadId np_thread_id_; + scoped_refptr<PluginMessageLoopProxy> plugin_message_loop_proxy_; scoped_ptr<RegisterSupportHostRequest> register_request_; scoped_refptr<MutableHostConfig> host_config_; @@ -172,7 +168,6 @@ class HostNPScriptObject : public HostStatusObserver { int failed_login_attempts_; base::WaitableEvent disconnected_event_; - base::CancellationFlag destructing_; scoped_ptr<policy_hack::NatPolicy> nat_policy_; diff --git a/remoting/host/simple_host_process.cc b/remoting/host/simple_host_process.cc index 3e6000c..92b515e 100644 --- a/remoting/host/simple_host_process.cc +++ b/remoting/host/simple_host_process.cc @@ -104,13 +104,8 @@ class SimpleHost { // It needs to be a UI message loop to keep runloops spinning on the Mac. MessageLoop message_loop(MessageLoop::TYPE_UI); - remoting::ChromotingHostContext context; - // static_cast needed to resolve overloaded PostTask member-function. - context.SetUITaskPostFunction(base::Bind( - static_cast<void(MessageLoop::*)( - const tracked_objects::Location&, - const base::Closure&)>(&MessageLoop::PostTask), - base::Unretained(&message_loop))); + remoting::ChromotingHostContext context( + base::MessageLoopProxy::current()); context.Start(); base::Thread file_io_thread("FileIO"); diff --git a/remoting/remoting.gyp b/remoting/remoting.gyp index 8d00dc7..6eb1c20 100644 --- a/remoting/remoting.gyp +++ b/remoting/remoting.gyp @@ -337,6 +337,8 @@ 'base/encoder_vp8.h', 'base/encoder_row_based.cc', 'base/encoder_row_based.h', + 'base/plugin_message_loop_proxy.cc', + 'base/plugin_message_loop_proxy.h', 'base/rate_counter.cc', 'base/rate_counter.h', 'base/running_average.cc', |