diff options
Diffstat (limited to 'chrome/common')
-rw-r--r-- | chrome/common/child_process.cc | 108 | ||||
-rw-r--r-- | chrome/common/child_process.h | 78 | ||||
-rw-r--r-- | chrome/common/child_thread.cc | 96 | ||||
-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, 254 insertions, 141 deletions
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc index b64984c..934583a 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) + : child_thread_(child_thread), + ref_count_(0), + shutdown_event_(true, false) { 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..90f31c5 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,17 @@ 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_; + // NOTE: make sure that child_thread_ is listed before shutdown_event_, since + // it depends on it (indirectly through IPC::SyncChannel). + scoped_ptr<ChildThread> child_thread_; + + base::AtomicRefCount ref_count_; + + // An event that will be signalled when we shutdown. + base::WaitableEvent shutdown_event_; + + // The singleton instance for this process. + static ChildProcess* child_process_; DISALLOW_EVIL_CONSTRUCTORS(ChildProcess); }; diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc new file mode 100644 index 0000000..a37310d62 --- /dev/null +++ b/chrome/common/child_thread.cc @@ -0,0 +1,96 @@ +// 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/string_util.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 598c0b4..5955a826 100644 --- a/chrome/common/temp_scaffolding_stubs.cc +++ b/chrome/common/temp_scaffolding_stubs.cc @@ -295,7 +295,6 @@ bool RLZTracker::RecordProductEvent(Product product, AccessPoint point, // This depends on porting all the plugin IPC messages. bool IsPluginProcess() { - NOTIMPLEMENTED(); return false; } |