diff options
author | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-04 22:27:43 +0000 |
---|---|---|
committer | alexeypa@chromium.org <alexeypa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-04 22:27:43 +0000 |
commit | ef948e69b97c179af5eb69ae318714052230df4f (patch) | |
tree | cc76efb6983b1a5868f26769fb654185880f2805 /remoting/host | |
parent | 38091251bfc38e7ae748edbf66b13dd360f68bb4 (diff) | |
download | chromium_src-ef948e69b97c179af5eb69ae318714052230df4f.zip chromium_src-ef948e69b97c179af5eb69ae318714052230df4f.tar.gz chromium_src-ef948e69b97c179af5eb69ae318714052230df4f.tar.bz2 |
[Chromoting] Introducing refcount-based life time management of the message loops in the service (daemon) and me2me host (network) processes.
This CL introduces AutoMessageLoop wrapper that provides control over life time of a message loop via scoped_refptr references. This scheme is useful in the cases when shutdown code has to run on a particular thread or when the OS requires resources (such as windows) to be freed before exiting a message loop.
The CL switches threads, owned by remoting::HostService, remoting::HostProcess and remoting::ChromotingHostContext, to refcount-based lifetime management. This change required updating tear-down sequences in remoting_me2me_host and the host plugin code.
BUG=134694
Review URL: https://chromiumcodereview.appspot.com/10829467
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154827 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'remoting/host')
-rw-r--r-- | remoting/host/chromoting_host_context.cc | 68 | ||||
-rw-r--r-- | remoting/host/chromoting_host_context.h | 68 | ||||
-rw-r--r-- | remoting/host/chromoting_host_context_unittest.cc | 4 | ||||
-rw-r--r-- | remoting/host/chromoting_host_unittest.cc | 2 | ||||
-rw-r--r-- | remoting/host/client_session_unittest.cc | 1 | ||||
-rw-r--r-- | remoting/host/constants.h | 1 | ||||
-rw-r--r-- | remoting/host/host_mock_objects.cc | 4 | ||||
-rw-r--r-- | remoting/host/plugin/host_script_object.cc | 27 | ||||
-rw-r--r-- | remoting/host/remoting_me2me_host.cc | 97 | ||||
-rw-r--r-- | remoting/host/simple_host_process.cc | 3 | ||||
-rw-r--r-- | remoting/host/win/host_service.cc | 60 | ||||
-rw-r--r-- | remoting/host/win/host_service.h | 15 |
12 files changed, 233 insertions, 117 deletions
diff --git a/remoting/host/chromoting_host_context.cc b/remoting/host/chromoting_host_context.cc index b110567..3aa26af 100644 --- a/remoting/host/chromoting_host_context.cc +++ b/remoting/host/chromoting_host_context.cc @@ -8,24 +8,36 @@ #include "base/bind.h" #include "base/threading/thread.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/host/url_request_context.h" namespace remoting { ChromotingHostContext::ChromotingHostContext( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) - : network_thread_("ChromotingNetworkThread"), + scoped_refptr<AutoThreadTaskRunner> ui_task_runner) + : audio_thread_("ChromotingAudioThread"), capture_thread_("ChromotingCaptureThread"), - encode_thread_("ChromotingEncodeThread"), - audio_thread_("ChromotingAudioThread"), desktop_thread_("ChromotingDesktopThread"), + encode_thread_("ChromotingEncodeThread"), file_thread_("ChromotingFileIOThread"), + network_thread_("ChromotingNetworkThread"), ui_task_runner_(ui_task_runner) { } ChromotingHostContext::~ChromotingHostContext() { } +void ChromotingHostContext::ReleaseTaskRunners() { + url_request_context_getter_ = NULL; + audio_task_runner_ = NULL; + capture_task_runner_ = NULL; + desktop_task_runner_ = NULL; + encode_task_runner_ = NULL; + file_task_runner_ = NULL; + network_task_runner_ = NULL; + ui_task_runner_ = NULL; +} + bool ChromotingHostContext::Start() { // Start all the threads. bool started = capture_thread_.Start() && encode_thread_.Start() && @@ -39,40 +51,62 @@ bool ChromotingHostContext::Start() { if (!started) return false; + // Wrap worker threads with |AutoThreadTaskRunner| and have them reference + // the main thread via |ui_task_runner_|, to ensure that it remain active to + // Stop() them when no references remain. + audio_task_runner_ = + new AutoThreadTaskRunner(audio_thread_.message_loop_proxy(), + ui_task_runner_); + capture_task_runner_ = + new AutoThreadTaskRunner(capture_thread_.message_loop_proxy(), + ui_task_runner_); + desktop_task_runner_ = + new AutoThreadTaskRunner(desktop_thread_.message_loop_proxy(), + ui_task_runner_); + encode_task_runner_ = + new AutoThreadTaskRunner(encode_thread_.message_loop_proxy(), + ui_task_runner_); + file_task_runner_ = + new AutoThreadTaskRunner(file_thread_.message_loop_proxy(), + ui_task_runner_); + + network_task_runner_ = + new AutoThreadTaskRunner(network_thread_.message_loop_proxy(), + ui_task_runner_); url_request_context_getter_ = new URLRequestContextGetter( ui_task_runner(), network_task_runner(), static_cast<MessageLoopForIO*>(file_thread_.message_loop())); return true; } +base::SingleThreadTaskRunner* ChromotingHostContext::audio_task_runner() { + return audio_task_runner_; +} + base::SingleThreadTaskRunner* ChromotingHostContext::capture_task_runner() { - return capture_thread_.message_loop_proxy(); + return capture_task_runner_; } -base::SingleThreadTaskRunner* ChromotingHostContext::encode_task_runner() { - return encode_thread_.message_loop_proxy(); +base::SingleThreadTaskRunner* ChromotingHostContext::desktop_task_runner() { + return desktop_task_runner_; } -base::SingleThreadTaskRunner* ChromotingHostContext::audio_task_runner() { - return audio_thread_.message_loop_proxy(); +base::SingleThreadTaskRunner* ChromotingHostContext::encode_task_runner() { + return encode_task_runner_; } -base::SingleThreadTaskRunner* ChromotingHostContext::network_task_runner() { - return network_thread_.message_loop_proxy(); +base::SingleThreadTaskRunner* ChromotingHostContext::file_task_runner() { + return file_task_runner_; } -base::SingleThreadTaskRunner* ChromotingHostContext::desktop_task_runner() { - return desktop_thread_.message_loop_proxy(); +base::SingleThreadTaskRunner* ChromotingHostContext::network_task_runner() { + return network_task_runner_; } base::SingleThreadTaskRunner* ChromotingHostContext::ui_task_runner() { return ui_task_runner_; } -base::SingleThreadTaskRunner* ChromotingHostContext::file_task_runner() { - return file_thread_.message_loop_proxy(); -} - const scoped_refptr<net::URLRequestContextGetter>& ChromotingHostContext::url_request_context_getter() { DCHECK(url_request_context_getter_.get()); diff --git a/remoting/host/chromoting_host_context.h b/remoting/host/chromoting_host_context.h index 149444a..497b8e3 100644 --- a/remoting/host/chromoting_host_context.h +++ b/remoting/host/chromoting_host_context.h @@ -5,22 +5,17 @@ #ifndef REMOTING_HOST_CHROMOTING_HOST_CONTEXT_H_ #define REMOTING_HOST_CHROMOTING_HOST_CONTEXT_H_ -#include <string> - #include "base/gtest_prod_util.h" #include "base/memory/ref_counted.h" -#include "base/threading/platform_thread.h" +#include "base/single_thread_task_runner.h" #include "base/threading/thread.h" -namespace base { -class SingleThreadTaskRunner; -} // namespace base - namespace net { class URLRequestContextGetter; } // namespace net namespace remoting { +class AutoThreadTaskRunner; // A class that manages threads and running context for the chromoting host // process. This class is virtual only for testing purposes (see below). @@ -28,9 +23,11 @@ class ChromotingHostContext { public: // Create a context. ChromotingHostContext( - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); + scoped_refptr<AutoThreadTaskRunner> ui_task_runner); virtual ~ChromotingHostContext(); + void ReleaseTaskRunners(); + // TODO(ajwong): Move the Start method out of this class. Then // create a static factory for construction, and destruction. We // should be able to remove the need for virtual functions below @@ -38,61 +35,70 @@ class ChromotingHostContext { // this API. virtual bool Start(); - // Task runner for the thread that is used for the UI. In the NPAPI - // plugin this corresponds to the main plugin thread. - virtual base::SingleThreadTaskRunner* ui_task_runner(); + // Task runner for the thread used for audio capture and encoding. + virtual base::SingleThreadTaskRunner* audio_task_runner(); // Task runner for the thread used by the ScreenRecorder to capture // the screen. virtual base::SingleThreadTaskRunner* capture_task_runner(); - // Task runner for the thread used to encode video streams. - virtual base::SingleThreadTaskRunner* encode_task_runner(); - - // Task runner for the thread used for audio capture and encoding. - virtual base::SingleThreadTaskRunner* audio_task_runner(); - - // Task runner for the thread used for network IO. This thread runs - // a libjingle message loop, and is the only thread on which - // libjingle code may be run. - virtual base::SingleThreadTaskRunner* network_task_runner(); - // Task runner for the thread that is used by the EventExecutor. // // TODO(sergeyu): Do we need a separate thread for EventExecutor? // Can we use some other thread instead? virtual base::SingleThreadTaskRunner* desktop_task_runner(); + // Task runner for the thread used to encode video streams. + virtual base::SingleThreadTaskRunner* encode_task_runner(); + // Task runner for the thread that is used for blocking file // IO. This thread is used by the URLRequestContext to read proxy // configuration and by NatConfig to read policy configs. virtual base::SingleThreadTaskRunner* file_task_runner(); + // Task runner for the thread used for network IO. This thread runs + // a libjingle message loop, and is the only thread on which + // libjingle code may be run. + virtual base::SingleThreadTaskRunner* network_task_runner(); + + // Task runner for the thread that is used for the UI. In the NPAPI + // plugin this corresponds to the main plugin thread. + virtual base::SingleThreadTaskRunner* ui_task_runner(); + const scoped_refptr<net::URLRequestContextGetter>& url_request_context_getter(); private: FRIEND_TEST_ALL_PREFIXES(ChromotingHostContextTest, StartAndStop); - // A thread that hosts all network operations. - base::Thread network_thread_; + // A thread that hosts audio capture and encoding. + base::Thread audio_thread_; // A thread that hosts screen capture. base::Thread capture_thread_; - // A thread that hosts all encode operations. - base::Thread encode_thread_; - - // A thread that hosts audio capture and encoding. - base::Thread audio_thread_; - // A thread that hosts input injection. base::Thread desktop_thread_; + // A thread that hosts all encode operations. + base::Thread encode_thread_; + // Thread for blocking IO operations. base::Thread file_thread_; - scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; + // A thread that hosts all network operations. + base::Thread network_thread_; + + // Task runners wrapping the above threads. These should be declared after + // the corresponding threads to guarantee proper order of destruction. + scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> capture_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> desktop_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> encode_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_; + scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_; + + scoped_refptr<AutoThreadTaskRunner> ui_task_runner_; scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_; diff --git a/remoting/host/chromoting_host_context_unittest.cc b/remoting/host/chromoting_host_context_unittest.cc index 1ceb95c..a4e670f 100644 --- a/remoting/host/chromoting_host_context_unittest.cc +++ b/remoting/host/chromoting_host_context_unittest.cc @@ -4,6 +4,7 @@ #include "base/message_loop.h" #include "base/message_loop_proxy.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/host/chromoting_host_context.h" #include "testing/gtest/include/gtest/gtest.h" @@ -13,7 +14,8 @@ namespace remoting { // operates properly and all threads and message loops are valid. TEST(ChromotingHostContextTest, StartAndStop) { MessageLoopForUI message_loop; - ChromotingHostContext context(base::MessageLoopProxy::current()); + ChromotingHostContext context(new AutoThreadTaskRunner( + base::MessageLoopProxy::current())); context.Start(); EXPECT_TRUE(context.network_task_runner()); diff --git a/remoting/host/chromoting_host_unittest.cc b/remoting/host/chromoting_host_unittest.cc index 2fbf2cc..3a82f0c 100644 --- a/remoting/host/chromoting_host_unittest.cc +++ b/remoting/host/chromoting_host_unittest.cc @@ -368,6 +368,7 @@ class ChromotingHostTest : public testing::Test { protected: MessageLoop message_loop_; scoped_refptr<base::MessageLoopProxy> message_loop_proxy_; + MockChromotingHostContext context_; MockConnectionToClientEventHandler handler_; MockSignalStrategy signal_strategy_; MockEventExecutor* event_executor_; @@ -375,7 +376,6 @@ class ChromotingHostTest : public testing::Test { scoped_ptr<It2MeHostUserInterface> it2me_host_user_interface_; scoped_refptr<ChromotingHost> host_; MockHostStatusObserver host_status_observer_; - MockChromotingHostContext context_; protocol::MockSessionManager* session_manager_; std::string xmpp_login_; MockConnectionToClient* connection1_; diff --git a/remoting/host/client_session_unittest.cc b/remoting/host/client_session_unittest.cc index 84783bb..bf54230 100644 --- a/remoting/host/client_session_unittest.cc +++ b/remoting/host/client_session_unittest.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/message_loop.h" #include "remoting/base/constants.h" #include "remoting/host/client_session.h" #include "remoting/host/host_mock_objects.h" diff --git a/remoting/host/constants.h b/remoting/host/constants.h index 0d37c38..e2723b6 100644 --- a/remoting/host/constants.h +++ b/remoting/host/constants.h @@ -18,6 +18,7 @@ enum HostExitCodes { // Error codes that don't indicate a permanent error condition. kSuccessExitCode = 0, kReservedForX11ExitCode = 1, + kHostInitializationFailed = 7, // Error codes that do indicate a permanent error condition. kInvalidHostConfigurationExitCode = 2, diff --git a/remoting/host/host_mock_objects.cc b/remoting/host/host_mock_objects.cc index f192f8e..f8867a3 100644 --- a/remoting/host/host_mock_objects.cc +++ b/remoting/host/host_mock_objects.cc @@ -6,6 +6,7 @@ #include "base/message_loop_proxy.h" #include "net/base/ip_endpoint.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/base/capture_data.h" #include "remoting/proto/event.pb.h" #include "remoting/protocol/transport.h" @@ -59,7 +60,8 @@ scoped_ptr<LocalInputMonitor> LocalInputMonitor::Create() { } MockChromotingHostContext::MockChromotingHostContext() - : ChromotingHostContext(base::MessageLoopProxy::current()) { + : ChromotingHostContext(new AutoThreadTaskRunner( + base::MessageLoopProxy::current())) { } MockChromotingHostContext::~MockChromotingHostContext() {} diff --git a/remoting/host/plugin/host_script_object.cc b/remoting/host/plugin/host_script_object.cc index 118114f..8cffb5e 100644 --- a/remoting/host/plugin/host_script_object.cc +++ b/remoting/host/plugin/host_script_object.cc @@ -15,6 +15,7 @@ #include "base/utf_string_conversions.h" #include "base/values.h" #include "net/base/net_util.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/base/auth_token_util.h" #include "remoting/host/chromoting_host.h" #include "remoting/host/chromoting_host_context.h" @@ -106,6 +107,10 @@ HostNPScriptObject::~HostNPScriptObject() { HostLogHandler::UnregisterLoggingScriptObject(this); + // Stop the message loop. Any attempt to post a task to + // |context_.ui_task_runner()| will result in a CHECK() after this point. + // TODO(alexeypa): Enable posting messages to |plugin_task_runner_| during + // shutdown to avoid this hack. plugin_task_runner_->Detach(); // Stop listening for policy updates. @@ -121,9 +126,7 @@ 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. - disconnected_event_.Reset(); DisconnectInternal(); - disconnected_event_.Wait(); // UI needs to be shut down on the UI thread before we destroy the // host context (because it depends on the context object), but @@ -132,7 +135,15 @@ HostNPScriptObject::~HostNPScriptObject() { // unregister it from this thread). it2me_host_user_interface_.reset(); - // Stops all threads. + // Release the context's TaskRunner references for the threads, so they can + // exit when no objects need them. + host_context_->ReleaseTaskRunners(); + + // |disconnected_event_| is signalled when the last reference to the plugin + // thread is dropped. + disconnected_event_.Wait(); + + // Stop all threads. host_context_.reset(); } @@ -143,7 +154,10 @@ bool HostNPScriptObject::Init() { DCHECK(plugin_task_runner_->BelongsToCurrentThread()); VLOG(2) << "Init"; - host_context_.reset(new ChromotingHostContext(plugin_task_runner_)); + host_context_.reset(new ChromotingHostContext(new AutoThreadTaskRunner( + plugin_task_runner_, + base::Bind(&base::WaitableEvent::Signal, + base::Unretained(&disconnected_event_))))); if (!host_context_->Start()) { host_context_.reset(); return false; @@ -878,13 +892,12 @@ void HostNPScriptObject::DisconnectInternal() { switch (state_) { case kDisconnected: - disconnected_event_.Signal(); return; case kStarting: + desktop_environment_.reset(); SetState(kDisconnecting); SetState(kDisconnected); - disconnected_event_.Signal(); return; case kDisconnecting: @@ -913,7 +926,7 @@ void HostNPScriptObject::DisconnectInternal() { void HostNPScriptObject::OnShutdownFinished() { DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); - disconnected_event_.Signal(); + desktop_environment_.reset(); } void HostNPScriptObject::OnPolicyUpdate( diff --git a/remoting/host/remoting_me2me_host.cc b/remoting/host/remoting_me2me_host.cc index 2d67463..192cfe2 100644 --- a/remoting/host/remoting_me2me_host.cc +++ b/remoting/host/remoting_me2me_host.cc @@ -28,6 +28,7 @@ #include "ipc/ipc_channel_proxy.h" #include "net/base/network_change_notifier.h" #include "net/socket/ssl_server_socket.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/base/breakpad.h" #include "remoting/base/constants.h" #include "remoting/host/branding.h" @@ -95,6 +96,10 @@ const char kOfficialOAuth2ClientId[] = "440925447803-avn2sj1kc099s0r7v62je5s339mu0am1.apps.googleusercontent.com"; const char kOfficialOAuth2ClientSecret[] = "Bgur6DFiOMM1h8x-AQpuTQlK"; +void QuitMessageLoop(MessageLoop* message_loop) { + message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); +} + } // namespace namespace remoting { @@ -103,8 +108,8 @@ class HostProcess : public HeartbeatSender::Listener, public IPC::Listener { public: - HostProcess() - : message_loop_(MessageLoop::TYPE_UI), + HostProcess(scoped_ptr<ChromotingHostContext> context) + : context_(context.Pass()), #ifdef OFFICIAL_BUILD oauth_use_official_client_id_(true), #else @@ -121,9 +126,6 @@ class HostProcess base::Unretained(this))) #endif { - context_.reset( - new ChromotingHostContext(message_loop_.message_loop_proxy())); - context_->Start(); network_change_notifier_.reset(net::NetworkChangeNotifier::Create()); config_updated_timer_.reset(new base::DelayTimer<HostProcess>( FROM_HERE, base::TimeDelta::FromSeconds(2), this, @@ -162,7 +164,7 @@ class HostProcess } void ConfigUpdated() { - DCHECK(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); // Call ConfigUpdatedDelayed after a short delay, so that this object won't // try to read the updated configuration file before it has been @@ -173,7 +175,7 @@ class HostProcess } void ConfigUpdatedDelayed() { - DCHECK(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); if (LoadConfig()) { // PostTask to create new authenticator factory in case PIN has changed. @@ -218,7 +220,7 @@ class HostProcess #elif defined(OS_WIN) scoped_refptr<base::files::FilePathWatcher::Delegate> delegate( new ConfigChangedDelegate( - message_loop_.message_loop_proxy(), + context_->ui_task_runner(), base::Bind(&HostProcess::ConfigUpdated, base::Unretained(this)))); config_watcher_.reset(new base::files::FilePathWatcher()); if (!config_watcher_->Watch(host_config_path_, delegate)) { @@ -241,9 +243,16 @@ class HostProcess return false; } - int Run() { - if (!LoadConfig()) { - return kInvalidHostConfigurationExitCode; + void StartHostProcess() { + DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); + + if (!InitWithCommandLine(CommandLine::ForCurrentProcess()) || + !LoadConfig()) { + context_->network_task_runner()->PostTask( + FROM_HERE, + base::Bind(&HostProcess::Shutdown, base::Unretained(this), + kInvalidHostConfigurationExitCode)); + return; } #if defined(OS_MACOSX) || defined(OS_WIN) @@ -275,19 +284,28 @@ class HostProcess base::Bind(&HostProcess::ListenForConfigChanges, base::Unretained(this))); #endif - message_loop_.Run(); + } + + int get_exit_code() const { return exit_code_; } + + private: + void ShutdownHostProcess() { + DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); + + daemon_channel_.reset(); #if defined(OS_MACOSX) || defined(OS_WIN) host_user_interface_.reset(); #endif - daemon_channel_.reset(); - base::WaitableEvent done_event(true, false); - policy_watcher_->StopWatching(&done_event); - done_event.Wait(); - policy_watcher_.reset(); + if (policy_watcher_.get()) { + base::WaitableEvent done_event(true, false); + policy_watcher_->StopWatching(&done_event); + done_event.Wait(); + policy_watcher_.reset(); + } - return exit_code_; + context_.reset(); } // Overridden from HeartbeatSender::Listener @@ -296,7 +314,6 @@ class HostProcess Shutdown(kInvalidHostIdExitCode); } - private: void StartWatchingPolicy() { policy_watcher_.reset( policy_hack::PolicyWatcher::Create(context_->file_task_runner())); @@ -306,7 +323,7 @@ class HostProcess // Read host config, returning true if successful. bool LoadConfig() { - DCHECK(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); // TODO(sergeyu): There is a potential race condition: this function is // called on the main thread while the class members it mutates are used on @@ -575,7 +592,7 @@ class HostProcess // Invoked when the user uses the Disconnect windows to terminate // the sessions. void OnDisconnectRequested() { - DCHECK(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); + DCHECK(context_->ui_task_runner()->BelongsToCurrentThread()); host_->DisconnectAllClients(); } @@ -627,12 +644,17 @@ class HostProcess host_ = NULL; ResetHost(); - message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); + // Complete the rest of shutdown on the main thread. + context_->ui_task_runner()->PostTask( + FROM_HERE, + base::Bind(&HostProcess::ShutdownHostProcess, + base::Unretained(this))); } void ResetHost() { DCHECK(context_->network_task_runner()->BelongsToCurrentThread()); + desktop_environment_.reset(); host_event_logger_.reset(); log_to_server_.reset(); heartbeat_sender_.reset(); @@ -640,7 +662,6 @@ class HostProcess signal_strategy_.reset(); } - MessageLoop message_loop_; scoped_ptr<ChromotingHostContext> context_; scoped_ptr<IPC::ChannelProxy> daemon_channel_; scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_; @@ -716,12 +737,11 @@ int main(int argc, char** argv) { logging::APPEND_TO_OLD_LOG_FILE, logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS); - const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); - #if defined(TOOLKIT_GTK) // Required for any calls into GTK functions, such as the Disconnect and // Continue windows, though these should not be used for the Me2Me case // (crbug.com/104377). + const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); gfx::GtkInitFromCommandLine(*cmd_line); #endif // TOOLKIT_GTK @@ -730,15 +750,28 @@ int main(int argc, char** argv) { net::EnableSSLServerSockets(); #if defined(OS_LINUX) - remoting::VideoFrameCapturer::EnableXDamage(true); + remoting::VideoFrameCapturer::EnableXDamage(true); #endif - remoting::HostProcess me2me_host; - if (!me2me_host.InitWithCommandLine(cmd_line)) { - return remoting::kInvalidHostConfigurationExitCode; - } - - return me2me_host.Run(); + // Create the main message loop and start helper threads. + MessageLoop message_loop(MessageLoop::TYPE_UI); + base::Closure quit_message_loop = base::Bind(&QuitMessageLoop, &message_loop); + scoped_ptr<remoting::ChromotingHostContext> context( + new remoting::ChromotingHostContext( + new remoting::AutoThreadTaskRunner(message_loop.message_loop_proxy(), + quit_message_loop))); + if (!context->Start()) + return remoting::kHostInitializationFailed; + + // Create the host process instance and run the rest of the initialization on + // the main message loop. + remoting::HostProcess me2me_host(context.Pass()); + message_loop.PostTask( + FROM_HERE, + base::Bind(&remoting::HostProcess::StartHostProcess, + base::Unretained(&me2me_host))); + message_loop.Run(); + return me2me_host.get_exit_code(); } #if defined(OS_WIN) diff --git a/remoting/host/simple_host_process.cc b/remoting/host/simple_host_process.cc index 6353a3d1..0887eb3 100644 --- a/remoting/host/simple_host_process.cc +++ b/remoting/host/simple_host_process.cc @@ -32,6 +32,7 @@ #include "crypto/nss_util.h" #include "net/base/network_change_notifier.h" #include "net/socket/ssl_server_socket.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/base/constants.h" #include "remoting/host/audio_capturer.h" #include "remoting/host/chromoting_host_context.h" @@ -97,7 +98,7 @@ class SimpleHost : public HeartbeatSender::Listener { public: SimpleHost() : message_loop_(MessageLoop::TYPE_UI), - context_(message_loop_.message_loop_proxy()), + context_(new AutoThreadTaskRunner(message_loop_.message_loop_proxy())), fake_(false), is_it2me_(false), shutting_down_(false), diff --git a/remoting/host/win/host_service.cc b/remoting/host/win/host_service.cc index 87088fe..92dda1d 100644 --- a/remoting/host/win/host_service.cc +++ b/remoting/host/win/host_service.cc @@ -24,6 +24,7 @@ #include "base/threading/thread.h" #include "base/utf_string_conversions.h" #include "base/win/wrapped_window_proc.h" +#include "remoting/base/auto_thread_task_runner.h" #include "remoting/base/breakpad.h" #include "remoting/base/scoped_sc_handle_win.h" #include "remoting/base/stoppable.h" @@ -92,6 +93,10 @@ void usage(const FilePath& program_name) { UTF16ToWide(program_name.value()).c_str()); } +void QuitMessageLoop(MessageLoop* message_loop) { + message_loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); +} + } // namespace namespace remoting { @@ -120,7 +125,7 @@ void HostService::RemoveWtsConsoleObserver(WtsConsoleObserver* observer) { void HostService::OnChildStopped() { child_.reset(NULL); - main_task_runner_->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + main_task_runner_ = NULL; } void HostService::OnSessionChange() { @@ -196,21 +201,14 @@ int HostService::Run() { return (this->*run_routine_)(); } -void HostService::RunMessageLoop(MessageLoop* message_loop) { - // Launch the I/O thread. - base::Thread io_thread(kIoThreadName); - base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0); - if (!io_thread.StartWithOptions(io_thread_options)) { - LOG(ERROR) << "Failed to start the I/O thread"; - stopped_event_.Signal(); - return; - } +void HostService::CreateLauncher( + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) { #if defined(REMOTING_MULTI_PROCESS) child_ = DaemonProcess::Create( main_task_runner_, - io_thread.message_loop_proxy(), + io_task_runner, base::Bind(&HostService::OnChildStopped, base::Unretained(this))).PassAs<Stoppable>(); @@ -221,15 +219,25 @@ void HostService::RunMessageLoop(MessageLoop* message_loop) { base::Bind(&HostService::OnChildStopped, base::Unretained(this)), this, main_task_runner_, - io_thread.message_loop_proxy())); + io_task_runner)); #endif // !defined(REMOTING_MULTI_PROCESS) +} + +void HostService::RunMessageLoop(MessageLoop* message_loop) { + // Launch the I/O thread. + base::Thread io_thread(kIoThreadName); + base::Thread::Options io_thread_options(MessageLoop::TYPE_IO, 0); + if (!io_thread.StartWithOptions(io_thread_options)) { + LOG(FATAL) << "Failed to start the I/O thread"; + return; + } + + CreateLauncher(new AutoThreadTaskRunner(io_thread.message_loop_proxy(), + main_task_runner_)); // Run the service. message_loop->Run(); - - // Release the control handler. - stopped_event_.Signal(); } int HostService::Elevate() { @@ -279,8 +287,11 @@ int HostService::RunAsService() { int HostService::RunInConsole() { MessageLoop message_loop(MessageLoop::TYPE_UI); - // Allow other threads to post to our message loop. - main_task_runner_ = message_loop.message_loop_proxy(); + // Keep a reference to the main message loop while it is used. Once the last + // reference is dropped, QuitClosure() will be posted to the loop. + main_task_runner_ = + new AutoThreadTaskRunner(message_loop.message_loop_proxy(), + base::Bind(&QuitMessageLoop, &message_loop)); int result = kErrorExitCode; @@ -327,6 +338,9 @@ int HostService::RunInConsole() { // Run the service. RunMessageLoop(&message_loop); + // Release the control handler. + stopped_event_.Signal(); + WTSUnRegisterSessionNotification(window); result = kSuccessExitCode; } @@ -375,11 +389,14 @@ DWORD WINAPI HostService::ServiceControlHandler(DWORD control, } VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { - MessageLoop message_loop; + MessageLoop message_loop(MessageLoop::TYPE_DEFAULT); - // Allow other threads to post to our message loop. + // Keep a reference to the main message loop while it is used. Once the last + // reference is dropped QuitClosure() will be posted to the loop. HostService* self = HostService::GetInstance(); - self->main_task_runner_ = message_loop.message_loop_proxy(); + self->main_task_runner_ = + new AutoThreadTaskRunner(message_loop.message_loop_proxy(), + base::Bind(&QuitMessageLoop, &message_loop)); // Register the service control handler. self->service_status_handle_ = @@ -416,6 +433,9 @@ VOID WINAPI HostService::ServiceMain(DWORD argc, WCHAR* argv[]) { // Run the service. self->RunMessageLoop(&message_loop); + // Release the control handler. + self->stopped_event_.Signal(); + // Tell SCM that the service is stopped. service_status.dwCurrentState = SERVICE_STOPPED; service_status.dwControlsAccepted = 0; diff --git a/remoting/host/win/host_service.h b/remoting/host/win/host_service.h index 9533f02..80bbc90 100644 --- a/remoting/host/win/host_service.h +++ b/remoting/host/win/host_service.h @@ -22,14 +22,13 @@ class SingleThreadTaskRunner; namespace remoting { -#if defined(REMOTING_MULTI_PROCESS) -class DaemonProcess; -#endif // defined(REMOTING_MULTI_PROCESS) - +class AutoThreadTaskRunner; class Stoppable; class WtsConsoleObserver; -#if !defined(REMOTING_MULTI_PROCESS) +#if defined(REMOTING_MULTI_PROCESS) +class DaemonProcess; +#else // !defined(REMOTING_MULTI_PROCESS) class WtsSessionProcessLauncher; #endif // !defined(REMOTING_MULTI_PROCESS) @@ -57,6 +56,10 @@ class HostService : public WtsConsoleMonitor { // Notifies the service of changes in session state. void OnSessionChange(); + // Creates the process launcher. + void CreateLauncher( + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner); + // This is a common entry point to the main service loop called by both // RunAsService() and RunInConsole(). void RunMessageLoop(MessageLoop* message_loop); @@ -98,7 +101,7 @@ class HostService : public WtsConsoleMonitor { scoped_ptr<Stoppable> child_; // Service message loop. - scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; + scoped_refptr<AutoThreadTaskRunner> main_task_runner_; // The action routine to be executed. int (HostService::*run_routine_)(); |