summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/child_process.cc108
-rw-r--r--chrome/common/child_process.h78
-rw-r--r--chrome/common/child_thread.cc96
-rw-r--r--chrome/common/child_thread.h76
-rw-r--r--chrome/common/common.scons2
-rw-r--r--chrome/common/common.vcproj8
-rw-r--r--chrome/common/ipc_sync_channel_unittest.cc26
-rw-r--r--chrome/common/temp_scaffolding_stubs.cc1
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;
}