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.h76
-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, 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;
}