summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/child_process.cc26
-rw-r--r--chrome/common/child_process.h18
-rw-r--r--chrome/common/child_process_host.cc31
-rw-r--r--chrome/common/child_process_host.h11
-rw-r--r--chrome/common/child_thread.cc32
-rw-r--r--chrome/common/child_thread.h8
-rw-r--r--chrome/common/plugin_messages_internal.h12
7 files changed, 90 insertions, 48 deletions
diff --git a/chrome/common/child_process.cc b/chrome/common/child_process.cc
index 27b55b7..55f5bb0 100644
--- a/chrome/common/child_process.cc
+++ b/chrome/common/child_process.cc
@@ -35,32 +35,22 @@ ChildProcess::~ChildProcess() {
child_process_ = NULL;
}
-// Called on any thread
void ChildProcess::AddRefProcess() {
- base::AtomicRefCountInc(&ref_count_);
+ DCHECK(MessageLoop::current() == child_thread_->message_loop());
+ ref_count_++;
}
-// Called on any thread
void ChildProcess::ReleaseProcess() {
- DCHECK(!base::AtomicRefCountIsZero(&ref_count_));
+ DCHECK(MessageLoop::current() == child_thread_->message_loop());
+ DCHECK(ref_count_);
DCHECK(child_process_);
- if (!base::AtomicRefCountDec(&ref_count_))
- child_process_->OnFinalRelease();
+ if (--ref_count_)
+ return;
+
+ child_thread_->OnProcessFinalRelease();
}
base::WaitableEvent* ChildProcess::GetShutDownEvent() {
DCHECK(child_process_);
return &child_process_->shutdown_event_;
}
-
-// Called on any thread
-bool ChildProcess::ProcessRefCountIsZero() {
- return base::AtomicRefCountIsZero(&ref_count_);
-}
-
-void ChildProcess::OnFinalRelease() {
- if (child_thread_.get()) {
- child_thread_->owner_loop()->PostTask(
- FROM_HERE, new MessageLoop::QuitTask());
- }
-}
diff --git a/chrome/common/child_process.h b/chrome/common/child_process.h
index 5844b5b..23bfad8 100644
--- a/chrome/common/child_process.h
+++ b/chrome/common/child_process.h
@@ -7,7 +7,6 @@
#include <string>
#include <vector>
-#include "base/atomic_ref_count.h"
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/scoped_ptr.h"
@@ -40,34 +39,21 @@ class ChildProcess {
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.
+ // itself down when the ref count reaches 0.
// 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:
- friend class ChildThread;
-
// Getter for the one ChildProcess object for this process.
static ChildProcess* current() { return child_process_; }
- 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
- // which causes the process to shutdown. Note, this can be called on any
- // thread. (See ReleaseProcess)
- virtual void OnFinalRelease();
-
private:
// 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_;
+ int ref_count_;
// An event that will be signalled when we shutdown.
base::WaitableEvent shutdown_event_;
diff --git a/chrome/common/child_process_host.cc b/chrome/common/child_process_host.cc
index 4269678..6618554 100644
--- a/chrome/common/child_process_host.cc
+++ b/chrome/common/child_process_host.cc
@@ -17,7 +17,12 @@
#include "chrome/common/process_watcher.h"
#include "chrome/common/result_codes.h"
-typedef std::list<ChildProcessInfo*> ChildProcessList;
+#if defined(OS_WIN)
+#include "chrome/common/plugin_messages.h"
+#endif
+
+namespace {
+typedef std::list<ChildProcessHost*> ChildProcessList;
// The NotificationTask is used to notify about plugin process connection/
// disconnection. It is needed because the notifications in the
@@ -39,6 +44,9 @@ class ChildNotificationTask : public Task {
ChildProcessInfo info_;
};
+} // namespace
+
+
ChildProcessHost::ChildProcessHost(
ProcessType type, ResourceDispatcherHost* resource_dispatcher_host)
@@ -143,10 +151,22 @@ void ChildProcessHost::ListenerHook::OnMessageReceived(
bool msg_is_ok = true;
bool handled = host_->resource_dispatcher_host_->OnMessageReceived(
msg, host_, &msg_is_ok);
- if (!handled)
- host_->OnMessageReceived(msg);
- if (!msg_is_ok)
+ if (!handled) {
+#if defined(OS_WIN)
+ if (msg.type() == PluginProcessHostMsg_ShutdownRequest::ID) {
+ // Must remove the process from the list now, in case it gets used for a
+ // new instance before our watcher tells us that the process terminated.
+ Singleton<ChildProcessList>::get()->remove(host_);
+ if (host_->CanShutdown())
+ host_->Send(new PluginProcessMsg_Shutdown());
+#endif
+ } else {
+ host_->OnMessageReceived(msg);
+ }
+ }
+
+ if (!msg_is_ok)
base::KillProcess(host_->handle(), ResultCodes::KILLED_BAD_MESSAGE, false);
#ifdef IPC_MESSAGE_LOG_ENABLED
@@ -158,6 +178,7 @@ void ChildProcessHost::ListenerHook::OnMessageReceived(
void ChildProcessHost::ListenerHook::OnChannelConnected(int32 peer_pid) {
host_->opening_channel_ = false;
host_->OnChannelConnected(peer_pid);
+ host_->Send(new PluginProcessMsg_AskBeforeShutdown());
// Notify in the main loop of the connection.
host_->Notify(NotificationType::CHILD_PROCESS_HOST_CONNECTED);
@@ -186,7 +207,7 @@ ChildProcessHost::Iterator::Iterator(ProcessType type)
++(*this);
}
-ChildProcessInfo* ChildProcessHost::Iterator::operator++() {
+ChildProcessHost* ChildProcessHost::Iterator::operator++() {
do {
++iterator_;
if (Done())
diff --git a/chrome/common/child_process_host.h b/chrome/common/child_process_host.h
index cef940c..d4d2dd9 100644
--- a/chrome/common/child_process_host.h
+++ b/chrome/common/child_process_host.h
@@ -38,21 +38,24 @@ class ChildProcessHost : public ResourceDispatcherHost::Receiver,
public:
Iterator();
Iterator(ProcessType type);
- ChildProcessInfo* operator->() { return *iterator_; }
- ChildProcessInfo* operator*() { return *iterator_; }
- ChildProcessInfo* operator++();
+ ChildProcessHost* operator->() { return *iterator_; }
+ ChildProcessHost* operator*() { return *iterator_; }
+ ChildProcessHost* operator++();
bool Done();
private:
bool all_;
ProcessType type_;
- std::list<ChildProcessInfo*>::iterator iterator_;
+ std::list<ChildProcessHost*>::iterator iterator_;
};
protected:
ChildProcessHost(ProcessType type,
ResourceDispatcherHost* resource_dispatcher_host);
+ // Derived classes return true if it's ok to shut down the child process.
+ virtual bool CanShutdown() = 0;
+
// Creates the IPC channel. Returns true iff it succeeded.
bool CreateChannel();
diff --git a/chrome/common/child_thread.cc b/chrome/common/child_thread.cc
index 237e53c..22c82c0 100644
--- a/chrome/common/child_thread.cc
+++ b/chrome/common/child_thread.cc
@@ -11,13 +11,18 @@
#include "chrome/common/ipc_logging.h"
#include "webkit/glue/webkit_glue.h"
+#if defined(OS_WIN)
+#include "chrome/common/plugin_messages.h"
+#endif
+
// V8 needs a 1MB stack size.
const size_t ChildThread::kV8StackSize = 1024 * 1024;
ChildThread::ChildThread(Thread::Options options)
: Thread("Chrome_ChildThread"),
owner_loop_(MessageLoop::current()),
- options_(options) {
+ options_(options),
+ check_with_browser_before_shutdown_(false) {
DCHECK(owner_loop_);
channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValue(
switches::kProcessChannelID);
@@ -66,6 +71,18 @@ void ChildThread::OnMessageReceived(const IPC::Message& msg) {
if (resource_dispatcher_->OnMessageReceived(msg))
return;
+#if defined(OS_WIN)
+ if (msg.type() == PluginProcessMsg_AskBeforeShutdown::ID) {
+ check_with_browser_before_shutdown_ = true;
+ return;
+ }
+
+ if (msg.type() == PluginProcessMsg_Shutdown::ID) {
+ owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ return;
+ }
+#endif
+
if (msg.routing_id() == MSG_ROUTING_CONTROL) {
OnControlMessageReceived(msg);
} else {
@@ -97,3 +114,16 @@ void ChildThread::CleanUp() {
channel_.reset();
resource_dispatcher_.reset();
}
+
+void ChildThread::OnProcessFinalRelease() {
+ if (!check_with_browser_before_shutdown_) {
+ owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+ return;
+ }
+
+ // The child process shutdown sequence is a request response based mechanism,
+ // where we send out an initial feeler request to the child process host
+ // instance in the browser to verify if it's ok to shutdown the child process.
+ // The browser then sends back a response if it's ok to shutdown.
+ Send(new PluginProcessHostMsg_ShutdownRequest);
+}
diff --git a/chrome/common/child_thread.h b/chrome/common/child_thread.h
index c499cb5..66fcc09 100644
--- a/chrome/common/child_thread.h
+++ b/chrome/common/child_thread.h
@@ -41,6 +41,9 @@ class ChildThread : public IPC::Channel::Listener,
// Overrides the channel name. Used for --single-process mode.
void SetChannelName(const std::wstring& name) { channel_name_ = name; }
+ // Called when the process refcount is 0.
+ void OnProcessFinalRelease();
+
protected:
// The required stack size if V8 runs on a thread.
static const size_t kV8StackSize;
@@ -77,6 +80,11 @@ class ChildThread : public IPC::Channel::Listener,
// NOTE: this object lives on the owner thread.
scoped_ptr<ResourceDispatcher> resource_dispatcher_;
+ // If true, checks with the browser process before shutdown. This avoids race
+ // conditions if the process refcount is 0 but there's an IPC message inflight
+ // that would addref it.
+ bool check_with_browser_before_shutdown_;
+
DISALLOW_EVIL_CONSTRUCTORS(ChildThread);
};
diff --git a/chrome/common/plugin_messages_internal.h b/chrome/common/plugin_messages_internal.h
index b9c7a58..61c53f0 100644
--- a/chrome/common/plugin_messages_internal.h
+++ b/chrome/common/plugin_messages_internal.h
@@ -16,15 +16,19 @@ IPC_BEGIN_MESSAGES(PluginProcess)
IPC_MESSAGE_CONTROL1(PluginProcessMsg_CreateChannel,
bool /* off_the_record */)
- IPC_MESSAGE_CONTROL1(PluginProcessMsg_ShutdownResponse,
- bool /* ok to shutdown */)
-
// Allows a chrome plugin loaded in the browser process to send arbitrary
// data to an instance of the same plugin loaded in a plugin process.
IPC_MESSAGE_CONTROL1(PluginProcessMsg_PluginMessage,
std::vector<uint8> /* opaque data */)
- IPC_MESSAGE_CONTROL0(PluginProcessMsg_BrowserShutdown)
+ // The following messages are used by all child processes, even though they
+ // are listed under PluginProcess. It seems overkill to define ChildProcess.
+ // Tells the child process it should stop.
+ IPC_MESSAGE_CONTROL0(PluginProcessMsg_AskBeforeShutdown)
+
+ // Sent in response to PluginProcessHostMsg_ShutdownRequest to tell the child
+ // process that it's safe to shutdown.
+ IPC_MESSAGE_CONTROL0(PluginProcessMsg_Shutdown)
IPC_END_MESSAGES(PluginProcess)