Index: base/mp/mp_child_thread.cc |
=================================================================== |
--- base/mp/mp_child_thread.cc (revision 0) |
+++ base/mp/mp_child_thread.cc (revision 0) |
@@ -0,0 +1,153 @@ |
+// Copyright (c) 2010 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 "base/mp/mp_child_thread.h" |
+ |
+#include "base/string_util.h" |
+#include "base/command_line.h" |
+#include "base/mp/mp_child_process.h" |
+#include "base/mp/mp_messages.h" |
+#include "ipc/ipc_logging.h" |
+#include "ipc/ipc_message.h" |
+#include "ipc/ipc_sync_message_filter.h" |
+#include "ipc/ipc_switches.h" |
+ |
+namespace base { |
+ |
+MpChildThread::MpChildThread() { |
+ channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ switches::kProcessChannelID); |
+ Init(); |
+} |
+ |
+MpChildThread::MpChildThread(const std::string& channel_name) |
+ : channel_name_(channel_name) { |
+ Init(); |
+} |
+ |
+void MpChildThread::Init() { |
+ check_with_parent_before_shutdown_ = false; |
+ on_channel_error_called_ = false; |
+ message_loop_ = MessageLoop::current(); |
+ |
+ channel_.reset(new IPC::SyncChannel(channel_name_, |
+ IPC::Channel::MODE_CLIENT, this, NULL, |
+ MpChildProcess::current()->io_message_loop(), true, |
+ MpChildProcess::current()->GetShutDownEvent())); |
+#ifdef IPC_MESSAGE_LOG_ENABLED |
+ IPC::Logging::current()->SetIPCSender(this); |
+#endif |
+ |
+ sync_message_filter_ = |
+ new IPC::SyncMessageFilter(MpChildProcess::current()->GetShutDownEvent()); |
+ channel_->AddFilter(sync_message_filter_.get()); |
+} |
+ |
+MpChildThread::~MpChildThread() { |
+#ifdef IPC_MESSAGE_LOG_ENABLED |
+ IPC::Logging::current()->SetIPCSender(NULL); |
+#endif |
+ |
+ channel_->RemoveFilter(sync_message_filter_.get()); |
+ |
+ // The ChannelProxy object caches a pointer to the IPC thread, so need to |
+ // reset it as it's not guaranteed to outlive this object. |
+ // NOTE: this also has the side-effect of not closing the main IPC channel to |
+ // the browser process. This is needed because this is the signal that the |
+ // browser uses to know that this process has died, so we need it to be alive |
+ // until this process is shut down, and the OS closes the handle |
+ // automatically. We used to watch the object handle on Windows to do this, |
+ // but it wasn't possible to do so on POSIX. |
+ channel_->ClearIPCMessageLoop(); |
+} |
+ |
+void MpChildThread::OnChannelError() { |
+ set_on_channel_error_called(true); |
+ MessageLoop::current()->Quit(); |
+} |
+ |
+bool MpChildThread::Send(IPC::Message* msg) { |
+ if (!channel_.get()) { |
+ delete msg; |
+ return false; |
+ } |
+ |
+ return channel_->Send(msg); |
+} |
+ |
+void MpChildThread::AddRoute(int32 routing_id, IPC::Channel::Listener* listener) { |
+ DCHECK(MessageLoop::current() == message_loop()); |
+ |
+ router_.AddRoute(routing_id, listener); |
+} |
+ |
+void MpChildThread::RemoveRoute(int32 routing_id) { |
+ DCHECK(MessageLoop::current() == message_loop()); |
+ |
+ router_.RemoveRoute(routing_id); |
+} |
+ |
+IPC::Channel::Listener* MpChildThread::ResolveRoute(int32 routing_id) { |
+ DCHECK(MessageLoop::current() == message_loop()); |
+ |
+ return router_.ResolveRoute(routing_id); |
+} |
+ |
+void MpChildThread::OnMessageReceived(const IPC::Message& msg) { |
+ bool handled = true; |
+ IPC_BEGIN_MESSAGE_MAP(MpChildThread, msg) |
+ IPC_MESSAGE_HANDLER(MultiProcessMsg_AskBeforeShutdown, OnAskBeforeShutdown) |
+ IPC_MESSAGE_HANDLER(MultiProcessMsg_Shutdown, OnShutdown) |
+#if defined(IPC_MESSAGE_LOG_ENABLED) |
+ IPC_MESSAGE_HANDLER(MultiProcessMsg_SetIPCLoggingEnabled, |
+ OnSetIPCLoggingEnabled) |
+#endif |
+ IPC_MESSAGE_UNHANDLED(handled = false) |
+ IPC_END_MESSAGE_MAP() |
+ |
+ if (handled) |
+ return; |
+ |
+ if (msg.routing_id() == MSG_ROUTING_CONTROL) { |
+ OnControlMessageReceived(msg); |
+ } else { |
+ router_.OnMessageReceived(msg); |
+ } |
+} |
+ |
+void MpChildThread::OnAskBeforeShutdown() { |
+ check_with_parent_before_shutdown_ = true; |
+} |
+ |
+void MpChildThread::OnShutdown() { |
+ MessageLoop::current()->Quit(); |
+} |
+ |
+#if defined(IPC_MESSAGE_LOG_ENABLED) |
+void MpChildThread::OnSetIPCLoggingEnabled(bool enable) { |
+ if (enable) |
+ IPC::Logging::current()->Enable(); |
+ else |
+ IPC::Logging::current()->Disable(); |
+} |
+#endif // IPC_MESSAGE_LOG_ENABLED |
+ |
+MpChildThread* MpChildThread::current() { |
+ return MpChildProcess::current()->main_thread(); |
+} |
+ |
+void MpChildThread::OnProcessFinalRelease() { |
+ if (on_channel_error_called_ || !check_with_parent_before_shutdown_) { |
+ MessageLoop::current()->Quit(); |
+ 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 MultiProcessHostMsg_ShutdownRequest); |
+} |
+ |
+} // namespace base |