diff options
author | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-20 05:23:36 +0000 |
---|---|---|
committer | jam@chromium.org <jam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-02-20 05:23:36 +0000 |
commit | 514e711ea07b6a1aef47ebf20250a37bd632402c (patch) | |
tree | 632f5e8902cc4231e9c14d0ad28035d63a0c964d /chrome/common | |
parent | 4acbad918766b81f1da3f10e2ae8aa2b10bb0593 (diff) | |
download | chromium_src-514e711ea07b6a1aef47ebf20250a37bd632402c.zip chromium_src-514e711ea07b6a1aef47ebf20250a37bd632402c.tar.gz chromium_src-514e711ea07b6a1aef47ebf20250a37bd632402c.tar.bz2 |
Refactor code from RenderThread and PluginThread and move it to ChildThread. ChildProcess now owns the ChildThread, which removes duplicate code and simplifies things.
Clean up ChildProcess, there really was no need for all the templates and statics in it and its subclasses.
Review URL: http://codereview.chromium.org/21502
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@10080 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/child_process.cc | 108 | ||||
-rw-r--r-- | chrome/common/child_process.h | 76 | ||||
-rw-r--r-- | chrome/common/child_thread.cc | 95 | ||||
-rw-r--r-- | chrome/common/child_thread.h | 76 | ||||
-rw-r--r-- | chrome/common/common.scons | 2 | ||||
-rw-r--r-- | chrome/common/common.vcproj | 8 | ||||
-rw-r--r-- | chrome/common/ipc_sync_channel_unittest.cc | 26 | ||||
-rw-r--r-- | chrome/common/temp_scaffolding_stubs.cc | 1 |
8 files changed, 251 insertions, 141 deletions
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc index b64984c..27265d3 100644 --- a/chrome/common/child_process.cc +++ b/chrome/common/child_process.cc @@ -4,109 +4,63 @@ #include "chrome/common/child_process.h" -#include "base/atomic_ref_count.h" #include "base/basictypes.h" -#include "base/command_line.h" #include "base/string_util.h" -#include "base/waitable_event.h" -#include "chrome/common/chrome_switches.h" -#include "webkit/glue/webkit_glue.h" +#include "chrome/common/child_thread.h" ChildProcess* ChildProcess::child_process_; -MessageLoop* ChildProcess::main_thread_loop_; -static base::AtomicRefCount ref_count; -base::WaitableEvent* ChildProcess::shutdown_event_; - -ChildProcess::ChildProcess() { +ChildProcess::ChildProcess(ChildThread* child_thread) + : shutdown_event_(true, false), + ref_count_(0), + child_thread_(child_thread) { DCHECK(!child_process_); + child_process_ = this; + if (child_thread_.get()) // null in unittests. + child_thread_->Run(); } ChildProcess::~ChildProcess() { DCHECK(child_process_ == this); + + // Signal this event before destroying the child process. That way all + // background threads can cleanup. + // For example, in the renderer the RenderThread instances will be able to + // notice shutdown before the render process begins waiting for them to exit. + shutdown_event_.Signal(); + + if (child_thread_.get()) + child_thread_->Stop(); + + child_process_ = NULL; } // Called on any thread void ChildProcess::AddRefProcess() { - base::AtomicRefCountInc(&ref_count); + base::AtomicRefCountInc(&ref_count_); } // Called on any thread void ChildProcess::ReleaseProcess() { - DCHECK(!base::AtomicRefCountIsZero(&ref_count)); + DCHECK(!base::AtomicRefCountIsZero(&ref_count_)); DCHECK(child_process_); - if (!base::AtomicRefCountDec(&ref_count)) + if (!base::AtomicRefCountDec(&ref_count_)) child_process_->OnFinalRelease(); } +base::WaitableEvent* ChildProcess::GetShutDownEvent() { + DCHECK(child_process_); + return &child_process_->shutdown_event_; +} + // Called on any thread -// static bool ChildProcess::ProcessRefCountIsZero() { - return base::AtomicRefCountIsZero(&ref_count); + return base::AtomicRefCountIsZero(&ref_count_); } void ChildProcess::OnFinalRelease() { - DCHECK(main_thread_loop_); - main_thread_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); -} - -base::WaitableEvent* ChildProcess::GetShutDownEvent() { - return shutdown_event_; -} - -// On error, it is OK to leave the global pointers, as long as the only -// non-NULL pointers are valid. GlobalCleanup will always get called, which -// will delete any non-NULL services. -bool ChildProcess::GlobalInit(const std::wstring &channel_name, - ChildProcessFactoryInterface *factory) { - // OK to be called multiple times. - if (main_thread_loop_) - return true; - - if (channel_name.empty()) { - NOTREACHED() << "Unable to get the channel name"; - return false; + if (child_thread_.get()) { + child_thread_->owner_loop()->PostTask( + FROM_HERE, new MessageLoop::QuitTask()); } - - // Remember the current message loop, so we can communicate with this thread - // again when we need to shutdown (see ReleaseProcess). - main_thread_loop_ = MessageLoop::current(); - - // An event that will be signalled when we shutdown. - shutdown_event_ = new base::WaitableEvent(true, false); - - child_process_ = factory->Create(channel_name); - - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - if (command_line.HasSwitch(switches::kUserAgent)) { -#if defined(OS_WIN) - // TODO(port): calling this connects an, otherwise disconnected, subgraph - // of symbols, causing huge numbers of linker errors. - webkit_glue::SetUserAgent(WideToUTF8( - command_line.GetSwitchValue(switches::kUserAgent))); -#endif - } - - return true; } - -void ChildProcess::GlobalCleanup() { - // Signal this event before destroying the child process. That way all - // background threads. - // For example, in the renderer the RenderThread instances will be able to - // notice shutdown before the render process begins waiting for them to exit. - shutdown_event_->Signal(); - - // Destroy the child process first to force all background threads to - // terminate before we bring down other resources. (We null pointers - // just in case.) - child_process_->Cleanup(); - delete child_process_; - child_process_ = NULL; - - main_thread_loop_ = NULL; - - delete shutdown_event_; - shutdown_event_ = NULL; -} - diff --git a/chrome/common/child_process.h b/chrome/common/child_process.h index 4a63efb..14fa406 100644 --- a/chrome/common/child_process.h +++ b/chrome/common/child_process.h @@ -7,45 +7,26 @@ #include <string> #include <vector> +#include "base/atomic_ref_count.h" #include "base/basictypes.h" #include "base/message_loop.h" +#include "base/scoped_ptr.h" +#include "base/waitable_event.h" -namespace base { - class WaitableEvent; -}; - -class ChildProcess; +class ChildThread; -class ChildProcessFactoryInterface { - public: - virtual ChildProcess* Create(const std::wstring& channel_name) = 0; -}; - -template<class T> -class ChildProcessFactory : public ChildProcessFactoryInterface { - virtual ChildProcess* Create(const std::wstring& channel_name) { - return new T(channel_name); - } -}; // Base class for child processes of the browser process (i.e. renderer and // plugin host). This is a singleton object for each child process. class ChildProcess { public: + // Child processes should have an object that derives from this class. The + // constructor will return once ChildThread has started. + ChildProcess(ChildThread* child_thread); + virtual ~ChildProcess(); - // initializes/cleansup the global variables, services, and libraries - // Derived classes need to implement a static GlobalInit, that calls - // into ChildProcess::GlobalInit with a class factory -//static bool GlobalInit(const std::wstring& channel_name); - static void GlobalCleanup(); - - // These are used for ref-counting the child process. The process shuts - // itself down when the ref count reaches 0. These functions may be called - // on any thread. - // For example, in the renderer process, generally each tab managed by this - // process will hold a reference to the process, and release when closed. - static void AddRefProcess(); - static void ReleaseProcess(); + // Getter for this process' main thread. + ChildThread* child_thread() { return child_thread_.get(); } // A global event object that is signalled when the main thread's message // loop exits. This gives background threads a way to observe the main @@ -56,22 +37,24 @@ class ChildProcess { // up waiting. // For example, see the renderer code used to implement // webkit_glue::GetCookies. - static base::WaitableEvent* GetShutDownEvent(); + base::WaitableEvent* GetShutDownEvent(); - // You must call Init after creating this object before it will be valid - ChildProcess(); - virtual ~ChildProcess(); + // These are used for ref-counting the child process. The process shuts + // itself down when the ref count reaches 0. These functions may be called + // on any thread. + // For example, in the renderer process, generally each tab managed by this + // process will hold a reference to the process, and release when closed. + void AddRefProcess(); + void ReleaseProcess(); protected: - static bool GlobalInit(const std::wstring& channel_name, - ChildProcessFactoryInterface* factory); - - static bool ProcessRefCountIsZero(); + friend class ChildThread; - // The singleton instance for this process. - static ChildProcess* child_process_; + // Getter for the one ChildProcess object for this process. + static ChildProcess* current() { return child_process_; } - static MessageLoop* main_thread_loop_; + protected: + bool ProcessRefCountIsZero(); // Derived classes can override this to alter the behavior when the ref count // reaches 0. The default implementation calls Quit on the main message loop @@ -80,10 +63,15 @@ class ChildProcess { virtual void OnFinalRelease(); private: - // Derived classes can override this to handle any cleanup, called by - // GlobalCleanup. - virtual void Cleanup() {} - static base::WaitableEvent* shutdown_event_; + // The singleton instance for this process. + static ChildProcess* child_process_; + + // An event that will be signalled when we shutdown. + base::WaitableEvent shutdown_event_; + + base::AtomicRefCount ref_count_; + + scoped_ptr<ChildThread> child_thread_; DISALLOW_EVIL_CONSTRUCTORS(ChildProcess); }; diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc new file mode 100644 index 0000000..8aca654 --- /dev/null +++ b/chrome/common/child_thread.cc @@ -0,0 +1,95 @@ +// Copyright (c) 2009 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 "chrome/common/child_thread.h" + +#include "base/command_line.h" +#include "chrome/common/child_process.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/ipc_logging.h" +#include "webkit/glue/webkit_glue.h" + +ChildThread::ChildThread(Thread::Options options) + : Thread("Chrome_ChildThread"), + owner_loop_(MessageLoop::current()), + in_send_(0), + options_(options) { + DCHECK(owner_loop_); + channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValue( + switches::kProcessChannelID); + + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUserAgent)) { +#if defined(OS_WIN) + // TODO(port): calling this connects an, otherwise disconnected, subgraph + // of symbols, causing huge numbers of linker errors. + webkit_glue::SetUserAgent(WideToUTF8( + CommandLine::ForCurrentProcess()->GetSwitchValue(switches::kUserAgent))); +#endif + } +} + +ChildThread::~ChildThread() { +} + +bool ChildThread::Run() { + return StartWithOptions(options_); +} + +void ChildThread::OnChannelError() { + owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask()); +} + +bool ChildThread::Send(IPC::Message* msg) { + if (!channel_.get()) { + delete msg; + return false; + } + + in_send_++; + bool rv = channel_->Send(msg); + in_send_--; + return rv; +} + +void ChildThread::AddRoute(int32 routing_id, IPC::Channel::Listener* listener) { + DCHECK(MessageLoop::current() == message_loop()); + + router_.AddRoute(routing_id, listener); +} + +void ChildThread::RemoveRoute(int32 routing_id) { + DCHECK(MessageLoop::current() == message_loop()); + + router_.RemoveRoute(routing_id); +} + +void ChildThread::OnMessageReceived(const IPC::Message& msg) { + if (msg.routing_id() == MSG_ROUTING_CONTROL) { + OnControlMessageReceived(msg); + } else { + router_.OnMessageReceived(msg); + } +} + +ChildThread* ChildThread::current() { + return ChildProcess::current()->child_thread(); +} + +void ChildThread::Init() { + channel_.reset(new IPC::SyncChannel(channel_name_, + IPC::Channel::MODE_CLIENT, this, NULL, owner_loop_, true, + ChildProcess::current()->GetShutDownEvent())); +#ifdef IPC_MESSAGE_LOG_ENABLED + IPC::Logging::current()->SetIPCSender(this); +#endif +} + +void ChildThread::CleanUp() { +#ifdef IPC_MESSAGE_LOG_ENABLED + IPC::Logging::current()->SetIPCSender(NULL); +#endif + // Need to destruct the SyncChannel to the browser before we go away because + // it caches a pointer to this thread. + channel_.reset(); +} diff --git a/chrome/common/child_thread.h b/chrome/common/child_thread.h new file mode 100644 index 0000000..ac835cc --- /dev/null +++ b/chrome/common/child_thread.h @@ -0,0 +1,76 @@ +// Copyright (c) 2009 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 CHROME_COMMON_CHILD_THREAD_H_ +#define CHROME_COMMON_CHILD_THREAD_H_ + +#include "base/thread.h" +#include "chrome/common/ipc_sync_channel.h" +#include "chrome/common/message_router.h" + +// Child processes's background thread should derive from this class. +class ChildThread : public IPC::Channel::Listener, + public IPC::Message::Sender, + public base::Thread { + public: + // Creates the thread. + ChildThread(Thread::Options options); + virtual ~ChildThread(); + + // IPC::Message::Sender implementation: + virtual bool Send(IPC::Message* msg); + + // See documentation on MessageRouter for AddRoute and RemoveRoute + void AddRoute(int32 routing_id, IPC::Channel::Listener* listener); + void RemoveRoute(int32 routing_id); + + MessageLoop* owner_loop() { return owner_loop_; } + + protected: + friend class ChildProcess; + + // Starts the thread. + bool Run(); + + // Overrides the channel name. Used for --single-process mode. + void SetChannelName(const std::wstring& name) { channel_name_ = name; } + + protected: + virtual void OnControlMessageReceived(const IPC::Message& msg) { } + + // Returns the one child thread. + static ChildThread* current(); + + IPC::SyncChannel* channel() { return channel_.get(); } + + // Indicates if ChildThread::Send() is on the call stack. + virtual bool InSend() const { return in_send_ != 0; } + + // Thread implementation. + virtual void Init(); + virtual void CleanUp(); + + private: + // IPC::Channel::Listener implementation: + virtual void OnMessageReceived(const IPC::Message& msg); + virtual void OnChannelError(); + + // The message loop used to run tasks on the thread that started this thread. + MessageLoop* owner_loop_; + + std::wstring channel_name_; + scoped_ptr<IPC::SyncChannel> channel_; + + // Used only on the background render thread to implement message routing + // functionality to the consumers of the ChildThread. + MessageRouter router_; + + int in_send_; + + Thread::Options options_; + + DISALLOW_EVIL_CONSTRUCTORS(ChildThread); +}; + +#endif // CHROME_COMMON_CHILD_THREAD_H_ diff --git a/chrome/common/common.scons b/chrome/common/common.scons index b2cc936..cc5e95d 100644 --- a/chrome/common/common.scons +++ b/chrome/common/common.scons @@ -110,6 +110,8 @@ input_files = ChromeFileList([ 'child_process_host.h', 'child_process_info.cc', 'child_process_info.h', + 'child_thread.cc', + 'child_thread.h', 'chrome_constants.cc', 'chrome_constants.h', 'chrome_counters.cc', diff --git a/chrome/common/common.vcproj b/chrome/common/common.vcproj index 67a664e..2e91a0d 100644 --- a/chrome/common/common.vcproj +++ b/chrome/common/common.vcproj @@ -358,6 +358,14 @@ > </File> <File + RelativePath=".\child_thread.cc" + > + </File> + <File + RelativePath=".\child_thread.h" + > + </File> + <File RelativePath=".\chrome_constants.cc" > </File> diff --git a/chrome/common/ipc_sync_channel_unittest.cc b/chrome/common/ipc_sync_channel_unittest.cc index 596faed..f59cced 100644 --- a/chrome/common/ipc_sync_channel_unittest.cc +++ b/chrome/common/ipc_sync_channel_unittest.cc @@ -14,7 +14,6 @@ #include "base/string_util.h" #include "base/thread.h" #include "base/waitable_event.h" -#include "chrome/common/child_process.h" #include "chrome/common/ipc_message.h" #include "chrome/common/ipc_sync_channel.h" #include "chrome/common/stl_util-inl.h" @@ -29,17 +28,6 @@ using base::WaitableEvent; namespace { -// SyncChannel should only be used in child processes as we don't want to hang -// the browser. So in the unit test we need to have a ChildProcess object. -class TestProcess : public ChildProcess { - public: - explicit TestProcess(const std::wstring& channel_name) {} - static void GlobalInit() { - ChildProcessFactory<TestProcess> factory; - ChildProcess::GlobalInit(L"blah", &factory); - } -}; - // Base class for a "process" with listener and IPC threads. class Worker : public Channel::Listener, public Message::Sender { public: @@ -50,7 +38,8 @@ class Worker : public Channel::Listener, public Message::Sender { mode_(mode), ipc_thread_((thread_name + "_ipc").c_str()), listener_thread_((thread_name + "_listener").c_str()), - overrided_thread_(NULL) { } + overrided_thread_(NULL), + shutdown_event_(true, false) { } // Will create a named channel and use this name for the threads' name. Worker(const std::wstring& channel_name, Channel::Mode mode) @@ -60,7 +49,8 @@ class Worker : public Channel::Listener, public Message::Sender { mode_(mode), ipc_thread_((WideToUTF8(channel_name) + "_ipc").c_str()), listener_thread_((WideToUTF8(channel_name) + "_listener").c_str()), - overrided_thread_(NULL) { } + overrided_thread_(NULL), + shutdown_event_(true, false) { } // The IPC thread needs to outlive SyncChannel, so force the correct order of // destruction. @@ -153,7 +143,7 @@ class Worker : public Channel::Listener, public Message::Sender { StartThread(&ipc_thread_, MessageLoop::TYPE_IO); channel_.reset(new SyncChannel( channel_name_, mode_, this, NULL, ipc_thread_.message_loop(), true, - TestProcess::GetShutDownEvent())); + &shutdown_event_)); channel_created_->Signal(); Run(); } @@ -195,6 +185,8 @@ class Worker : public Channel::Listener, public Message::Sender { base::Thread listener_thread_; base::Thread* overrided_thread_; + base::WaitableEvent shutdown_event_; + DISALLOW_EVIL_CONSTRUCTORS(Worker); }; @@ -202,8 +194,6 @@ class Worker : public Channel::Listener, public Message::Sender { // Starts the test with the given workers. This function deletes the workers // when it's done. void RunTest(std::vector<Worker*> workers) { - TestProcess::GlobalInit(); - // First we create the workers that are channel servers, or else the other // workers' channel initialization might fail because the pipe isn't created.. for (size_t i = 0; i < workers.size(); ++i) { @@ -224,8 +214,6 @@ void RunTest(std::vector<Worker*> workers) { workers[i]->done_event()->Wait(); STLDeleteContainerPointers(workers.begin(), workers.end()); - - TestProcess::GlobalCleanup(); } } // namespace diff --git a/chrome/common/temp_scaffolding_stubs.cc b/chrome/common/temp_scaffolding_stubs.cc index 6a1b9c3c..8fcf796 100644 --- a/chrome/common/temp_scaffolding_stubs.cc +++ b/chrome/common/temp_scaffolding_stubs.cc @@ -316,7 +316,6 @@ bool RLZTracker::RecordProductEvent(Product product, AccessPoint point, // This depends on porting all the plugin IPC messages. bool IsPluginProcess() { - NOTIMPLEMENTED(); return false; } |