diff options
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 | 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, 141 insertions, 252 deletions
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc index 27265d3..b64984c 100644 --- a/chrome/common/child_process.cc +++ b/chrome/common/child_process.cc @@ -4,63 +4,109 @@ #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 "chrome/common/child_thread.h" +#include "base/waitable_event.h" +#include "chrome/common/chrome_switches.h" +#include "webkit/glue/webkit_glue.h" ChildProcess* ChildProcess::child_process_; +MessageLoop* ChildProcess::main_thread_loop_; +static base::AtomicRefCount ref_count; +base::WaitableEvent* ChildProcess::shutdown_event_; -ChildProcess::ChildProcess(ChildThread* child_thread) - : shutdown_event_(true, false), - ref_count_(0), - child_thread_(child_thread) { + +ChildProcess::ChildProcess() { 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() { - if (child_thread_.get()) { - child_thread_->owner_loop()->PostTask( - FROM_HERE, new MessageLoop::QuitTask()); + 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; } + + // 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 14fa406..4a63efb 100644 --- a/chrome/common/child_process.h +++ b/chrome/common/child_process.h @@ -7,26 +7,45 @@ #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" -class ChildThread; +namespace base { + class WaitableEvent; +}; + +class ChildProcess; +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(); - // Getter for this process' main thread. - ChildThread* child_thread() { return child_thread_.get(); } + // 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(); // 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 @@ -37,24 +56,22 @@ class ChildProcess { // up waiting. // For example, see the renderer code used to implement // webkit_glue::GetCookies. - base::WaitableEvent* GetShutDownEvent(); + static base::WaitableEvent* GetShutDownEvent(); - // 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(); + // You must call Init after creating this object before it will be valid + ChildProcess(); + virtual ~ChildProcess(); protected: - friend class ChildThread; + static bool GlobalInit(const std::wstring& channel_name, + ChildProcessFactoryInterface* factory); - // Getter for the one ChildProcess object for this process. - static ChildProcess* current() { return child_process_; } + static bool ProcessRefCountIsZero(); - protected: - bool ProcessRefCountIsZero(); + // The singleton instance for this process. + static ChildProcess* child_process_; + + static MessageLoop* main_thread_loop_; // 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 @@ -63,15 +80,10 @@ class ChildProcess { virtual void OnFinalRelease(); private: - // 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_; + // Derived classes can override this to handle any cleanup, called by + // GlobalCleanup. + virtual void Cleanup() {} + static base::WaitableEvent* shutdown_event_; DISALLOW_EVIL_CONSTRUCTORS(ChildProcess); }; diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc deleted file mode 100644 index 056c130..0000000 --- a/chrome/common/child_thread.cc +++ /dev/null @@ -1,96 +0,0 @@ -// 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 "base/string_util.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 deleted file mode 100644 index ac835cc..0000000 --- a/chrome/common/child_thread.h +++ /dev/null @@ -1,76 +0,0 @@ -// 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 cc5e95d..b2cc936 100644 --- a/chrome/common/common.scons +++ b/chrome/common/common.scons @@ -110,8 +110,6 @@ 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 2e91a0d..67a664e 100644 --- a/chrome/common/common.vcproj +++ b/chrome/common/common.vcproj @@ -358,14 +358,6 @@ > </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 f59cced..596faed 100644 --- a/chrome/common/ipc_sync_channel_unittest.cc +++ b/chrome/common/ipc_sync_channel_unittest.cc @@ -14,6 +14,7 @@ #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" @@ -28,6 +29,17 @@ 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: @@ -38,8 +50,7 @@ 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), - shutdown_event_(true, false) { } + overrided_thread_(NULL) { } // Will create a named channel and use this name for the threads' name. Worker(const std::wstring& channel_name, Channel::Mode mode) @@ -49,8 +60,7 @@ 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), - shutdown_event_(true, false) { } + overrided_thread_(NULL) { } // The IPC thread needs to outlive SyncChannel, so force the correct order of // destruction. @@ -143,7 +153,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, - &shutdown_event_)); + TestProcess::GetShutDownEvent())); channel_created_->Signal(); Run(); } @@ -185,8 +195,6 @@ class Worker : public Channel::Listener, public Message::Sender { base::Thread listener_thread_; base::Thread* overrided_thread_; - base::WaitableEvent shutdown_event_; - DISALLOW_EVIL_CONSTRUCTORS(Worker); }; @@ -194,6 +202,8 @@ 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) { @@ -214,6 +224,8 @@ 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 8fcf796..6a1b9c3c 100644 --- a/chrome/common/temp_scaffolding_stubs.cc +++ b/chrome/common/temp_scaffolding_stubs.cc @@ -316,6 +316,7 @@ bool RLZTracker::RecordProductEvent(Product product, AccessPoint point, // This depends on porting all the plugin IPC messages. bool IsPluginProcess() { + NOTIMPLEMENTED(); return false; } |