Bug 528146: Run plug-in code on the thread that starts in main(). r=cjones
authorBenoit Girard <b56girard@gmail.com>
Mon, 10 May 2010 23:18:00 -0500
changeset 42302 11edbb06abc02d5319969c0ad3cc10b2a84683c9
parent 42301 ddf980769a0011fdec82ecf8178751bda4d48e4d
child 42303 bc3db67ad44396bed2f7cb05b6ccb12da98a2088
push idunknown
push userunknown
push dateunknown
reviewerscjones
bugs528146
milestone1.9.3a5pre
Bug 528146: Run plug-in code on the thread that starts in main(). r=cjones
dom/plugins/Makefile.in
dom/plugins/PluginInstanceChild.cpp
dom/plugins/PluginModuleChild.cpp
dom/plugins/PluginProcessChild.cpp
dom/plugins/PluginProcessChild.h
dom/plugins/PluginThreadChild.cpp
dom/plugins/PluginThreadChild.h
ipc/chromium/src/base/thread.cc
ipc/chromium/src/base/thread.h
ipc/chromium/src/chrome/common/ipc_channel_win.cc
ipc/chromium/src/chrome/common/ipc_channel_win.h
ipc/glue/IOThreadChild.h
ipc/glue/Makefile.in
ipc/glue/MozillaChildThread.cpp
ipc/glue/MozillaChildThread.h
ipc/glue/ProcessChild.cpp
ipc/glue/ProcessChild.h
ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
ipc/ipdl/test/cxx/IPDLUnitTestThreadChild.cpp
ipc/ipdl/test/cxx/IPDLUnitTestThreadChild.h
ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
ipc/ipdl/test/cxx/Makefile.in
toolkit/xre/nsEmbedFunctions.cpp
toolkit/xre/nsX11ErrorHandler.cpp
--- a/dom/plugins/Makefile.in
+++ b/dom/plugins/Makefile.in
@@ -78,17 +78,17 @@ EXPORTS_mozilla/plugins = \
   PluginInstanceParent.h \
   AStream.h \
   BrowserStreamChild.h \
   BrowserStreamParent.h \
   PluginStreamChild.h \
   PluginStreamParent.h \
   PluginMessageUtils.h \
   PluginProcessParent.h \
-  PluginThreadChild.h \
+  PluginProcessChild.h \
   StreamNotifyChild.h \
   StreamNotifyParent.h \
   $(NULL)
 
 MODULE           = dom
 LIBRARY_NAME     = domplugins_s
 LIBXUL_LIBRARY   = 1
 FORCE_STATIC_LIB = 1
@@ -98,24 +98,24 @@ ENABLE_CXX_EXCEPTIONS = 1
 CPPSRCS = \
   ChildAsyncCall.cpp \
   ChildTimer.cpp \
   PluginMessageUtils.cpp \
   PluginInstanceChild.cpp \
   PluginInstanceParent.cpp \
   PluginModuleChild.cpp \
   PluginModuleParent.cpp \
+  PluginProcessChild.cpp \
   PluginProcessParent.cpp \
   PluginScriptableObjectChild.cpp \
   PluginScriptableObjectParent.cpp \
   BrowserStreamChild.cpp \
   BrowserStreamParent.cpp \
   PluginStreamChild.cpp \
   PluginStreamParent.cpp \
-  PluginThreadChild.cpp \
   $(NULL)
 
 LOCAL_INCLUDES = \
   -I$(topsrcdir)/modules/plugin/base/public/ \
   -I$(topsrcdir)/modules/plugin/base/src/ \
   $(NULL)
 
 include $(topsrcdir)/config/config.mk
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -37,20 +37,21 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "PluginInstanceChild.h"
 #include "PluginModuleChild.h"
 #include "BrowserStreamChild.h"
 #include "PluginStreamChild.h"
 #include "StreamNotifyChild.h"
-#include "PluginThreadChild.h"
+#include "PluginProcessChild.h"
 
 #include "mozilla/ipc/SyncChannel.h"
 
+using mozilla::ipc::ProcessChild;
 using namespace mozilla::plugins;
 
 #ifdef MOZ_WIDGET_GTK2
 
 #include <gtk/gtk.h>
 #include <gdk/gdkx.h>
 #include <gdk/gdk.h>
 #include "gtk2xtbin.h"
@@ -1925,17 +1926,17 @@ void
 PluginInstanceChild::AsyncCall(PluginThreadCallback aFunc, void* aUserData)
 {
     ChildAsyncCall* task = new ChildAsyncCall(this, aFunc, aUserData);
 
     {
         MutexAutoLock lock(mAsyncCallMutex);
         mPendingAsyncCalls.AppendElement(task);
     }
-    PluginThreadChild::current()->message_loop()->PostTask(FROM_HERE, task);
+    ProcessChild::message_loop()->PostTask(FROM_HERE, task);
 }
 
 static PLDHashOperator
 InvalidateObject(DeletingObjectEntry* e, void* userArg)
 {
     NPObject* o = e->GetKey();
     if (!e->mDeleted && o->_class && o->_class->invalidate)
         o->_class->invalidate(o);
--- a/dom/plugins/PluginModuleChild.cpp
+++ b/dom/plugins/PluginModuleChild.cpp
@@ -54,17 +54,16 @@
 #include "nsCOMPtr.h"
 #include "nsPluginsDir.h"
 #include "nsXULAppAPI.h"
 
 #include "mozilla/plugins/PluginInstanceChild.h"
 #include "mozilla/plugins/StreamNotifyChild.h"
 #include "mozilla/plugins/BrowserStreamChild.h"
 #include "mozilla/plugins/PluginStreamChild.h"
-#include "mozilla/plugins/PluginThreadChild.h"
 #include "PluginIdentifierChild.h"
 
 #include "nsNPAPIPlugin.h"
 
 using namespace mozilla::plugins;
 
 #if defined(XP_WIN)
 #ifndef WM_MOUSEHWHEEL
rename from dom/plugins/PluginThreadChild.cpp
rename to dom/plugins/PluginProcessChild.cpp
--- a/dom/plugins/PluginThreadChild.cpp
+++ b/dom/plugins/PluginProcessChild.cpp
@@ -32,48 +32,45 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "mozilla/plugins/PluginThreadChild.h"
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/plugins/PluginProcessChild.h"
 
 #include "prlink.h"
 
 #include "base/command_line.h"
 #include "base/string_util.h"
-#include "chrome/common/child_process.h"
 #include "chrome/common/chrome_switches.h"
 
-using mozilla::ipc::MozillaChildThread;
+#ifdef XP_WIN
+#include <objbase.h>
+#endif
+
+using mozilla::ipc::IOThreadChild;
 
 namespace mozilla {
 namespace plugins {
 
-PluginThreadChild::PluginThreadChild(ProcessHandle aParentHandle) :
-    MozillaChildThread(aParentHandle, MessageLoop::TYPE_UI)
-{
-    NS_ASSERTION(!gInstance, "Two PluginThreadChild?");
-    gInstance = this;
-}
-
-PluginThreadChild::~PluginThreadChild()
+bool
+PluginProcessChild::Init()
 {
-    gInstance = NULL;
-}
-
-PluginThreadChild* PluginThreadChild::gInstance;
+#ifdef XP_WIN
+    // Silverlight depends on the host calling CoInitialize.
+    ::CoInitialize(NULL);
+#endif
 
-void
-PluginThreadChild::Init()
-{
-    MozillaChildThread::Init();
+    // Certain plugins, such as flash, steal the unhandled exception filter
+    // thus we never get crash reports when they fault. This call fixes it.
+    message_loop()->set_exception_restoration(true);
 
     std::string pluginFilename;
 
 #if defined(OS_POSIX)
     // NB: need to be very careful in ensuring that the first arg
     // (after the binary name) here is indeed the plugin module path.
     // Keep in sync with dom/plugins/PluginModuleParent.
     std::vector<std::string> values = CommandLine::ForCurrentProcess()->argv();
@@ -87,33 +84,37 @@ PluginThreadChild::Init()
     NS_ABORT_IF_FALSE(values.size() >= 1, "not enough loose args");
 
     pluginFilename = WideToUTF8(values[0]);
 
 #else
 #  error Sorry
 #endif
 
-    // FIXME owner_loop() is bad here
-    mPlugin.Init(pluginFilename,
-                 GetParentProcessHandle(), owner_loop(), channel());
+    mPlugin.Init(pluginFilename, ParentHandle(),
+                 IOThreadChild::message_loop(),
+                 IOThreadChild::channel());
+
+    return true;
 }
 
 void
-PluginThreadChild::CleanUp()
+PluginProcessChild::CleanUp()
 {
-    mPlugin.CleanUp();
-    MozillaChildThread::CleanUp();
+#ifdef XP_WIN
+    ::CoUninitialize();
+#endif
 }
 
 /* static */
 void
-PluginThreadChild::AppendNotesToCrashReport(const nsCString& aNotes)
+PluginProcessChild::AppendNotesToCrashReport(const nsCString& aNotes)
 {
     AssertPluginThread();
 
-    if (gInstance) {
-        gInstance->mPlugin.SendAppendNotesToCrashReport(aNotes);
+    PluginProcessChild* p = PluginProcessChild::current();
+    if (p) {
+        p->mPlugin.SendAppendNotesToCrashReport(aNotes);
     }
 }
 
 } // namespace plugins
 } // namespace mozilla
rename from dom/plugins/PluginThreadChild.h
rename to dom/plugins/PluginProcessChild.h
--- a/dom/plugins/PluginThreadChild.h
+++ b/dom/plugins/PluginProcessChild.h
@@ -32,54 +32,50 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#ifndef dom_plugins_PluginThreadChild_h
-#define dom_plugins_PluginThreadChild_h 1
-
-#include "base/basictypes.h"
+#ifndef dom_plugins_PluginProcessChild_h
+#define dom_plugins_PluginProcessChild_h 1
 
-#include "mozilla/ipc/MozillaChildThread.h"
-#include "base/file_path.h"
-#include "base/process.h"
-
+#include "mozilla/ipc/ProcessChild.h"
 #include "mozilla/plugins/PluginModuleChild.h"
 
 namespace mozilla {
 namespace plugins {
 //-----------------------------------------------------------------------------
 
-// The PluginThreadChild class represents a background thread where plugin instances
-// live.
-class PluginThreadChild : public mozilla::ipc::MozillaChildThread {
+class PluginProcessChild : public mozilla::ipc::ProcessChild {
+protected:
+    typedef mozilla::ipc::ProcessChild ProcessChild;
+
 public:
-    PluginThreadChild(ProcessHandle aParentHandle);
-    ~PluginThreadChild();
+    PluginProcessChild(ProcessHandle parentHandle) : ProcessChild(parentHandle)
+    { }
 
-    static PluginThreadChild* current() {
-        return gInstance;
-    }
+    virtual ~PluginProcessChild()
+    { }
+
+    NS_OVERRIDE virtual bool Init();
+    NS_OVERRIDE virtual void CleanUp();
 
     // For use on the plugin thread.
     static void AppendNotesToCrashReport(const nsCString& aNotes);
 
-private:
-    static PluginThreadChild* gInstance;
+protected:
+    static PluginProcessChild* current() {
+        return static_cast<PluginProcessChild*>(ProcessChild::current());
+    }
 
-    // Thread implementation:
-    virtual void Init();
-    virtual void CleanUp();
+private:
+    PluginModuleChild mPlugin;
 
-    PluginModuleChild mPlugin;
-    IPC::Channel* mChannel;
-
-    DISALLOW_EVIL_CONSTRUCTORS(PluginThreadChild);
+    DISALLOW_EVIL_CONSTRUCTORS(PluginProcessChild);
 };
 
 }  // namespace plugins
 }  // namespace mozilla
 
-#endif  // ifndef dom_plugins_PluginThreadChild_h
+#endif  // ifndef dom_plugins_PluginProcessChild_h
--- a/ipc/chromium/src/base/thread.cc
+++ b/ipc/chromium/src/base/thread.cc
@@ -140,29 +140,20 @@ void Thread::ThreadMain() {
   MessageLoop message_loop(startup_data_->options.message_loop_type);
 
   // Complete the initialization of our Thread object.
   thread_id_ = PlatformThread::CurrentId();
   PlatformThread::SetName(name_.c_str());
   message_loop.set_thread_name(name_);
   message_loop_ = &message_loop;
 
-#if defined(CHROMIUM_MOZILLA_BUILD)
-  bool wait_for_init = startup_data_->options.wait_for_init;
-  if (!wait_for_init)
-    startup_data_->event.Signal();
-#endif
-
   // Let the thread do extra initialization.
   // Let's do this before signaling we are started.
   Init();
 
-#if defined(CHROMIUM_MOZILLA_BUILD)
-  if (wait_for_init)
-#endif
   startup_data_->event.Signal();
   // startup_data_ can't be touched anymore since the starting thread is now
   // unlocked.
 
   message_loop.Run();
 
   // Let the thread do extra cleanup.
   CleanUp();
--- a/ipc/chromium/src/base/thread.h
+++ b/ipc/chromium/src/base/thread.h
@@ -23,45 +23,19 @@ class Thread : PlatformThread::Delegate 
     // Specifies the type of message loop that will be allocated on the thread.
     MessageLoop::Type message_loop_type;
 
     // Specifies the maximum stack size that the thread is allowed to use.
     // This does not necessarily correspond to the thread's initial stack size.
     // A value of 0 indicates that the default maximum should be used.
     size_t stack_size;
 
-#if defined(CHROMIUM_MOZILLA_BUILD)
-    // Specifies whether the thread that launched this sub-thread
-    // should wait for the sub-thread's Init() routine to finish
-    // before dropping into the event loop.  If it is false, the
-    // sub-thread will signal just before calling Init().  If true,
-    // the sub-thread will signal just after.
-    bool wait_for_init;
-
-    Options() :
-        message_loop_type(MessageLoop::TYPE_DEFAULT),
-        stack_size(0),
-        wait_for_init(true)
-      {}
-    Options(MessageLoop::Type type, size_t size) :
-        message_loop_type(type),
-        stack_size(size),
-        wait_for_init(true)
-      {}
-      Options(MessageLoop::Type type, size_t size, bool wait_init) :
-        message_loop_type(type),
-        stack_size(size),
-        wait_for_init(wait_init)
-      {}
-
-#else
     Options() : message_loop_type(MessageLoop::TYPE_DEFAULT), stack_size(0) {}
     Options(MessageLoop::Type type, size_t size)
         : message_loop_type(type), stack_size(size) {}
-#endif
   };
 
   // Constructor.
   // name is a display string to identify the thread.
   explicit Thread(const char *name);
 
   // Destroys the thread, stopping it if necessary.
   //
--- a/ipc/chromium/src/chrome/common/ipc_channel_win.cc
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.cc
@@ -75,16 +75,19 @@ void Channel::ChannelImpl::Close() {
     UMA_HISTOGRAM_TIMES("AsyncIO.IPCChannelClose", base::Time::Now() - start);
   }
 
   while (!output_queue_.empty()) {
     Message* m = output_queue_.front();
     output_queue_.pop();
     delete m;
   }
+
+  if (thread_check_.get())
+    thread_check_.reset();
 }
 
 bool Channel::ChannelImpl::Send(Message* message) {
   DCHECK(thread_check_->CalledOnValidThread());
   chrome::Counters::ipc_send_counter().Increment();
 #ifdef IPC_MESSAGE_DEBUG_EXTRA
   DLOG(INFO) << "sending message @" << message << " on channel @" << this
              << " with type " << message->type()
--- a/ipc/chromium/src/chrome/common/ipc_channel_win.h
+++ b/ipc/chromium/src/chrome/common/ipc_channel_win.h
@@ -15,17 +15,21 @@
 class NonThreadSafe;
 
 namespace IPC {
 
 class Channel::ChannelImpl : public MessageLoopForIO::IOHandler {
  public:
   // Mirror methods of Channel, see ipc_channel.h for description.
   ChannelImpl(const std::wstring& channel_id, Mode mode, Listener* listener);
-  ~ChannelImpl() { Close(); }
+  ~ChannelImpl() { 
+    if (pipe_ != INVALID_HANDLE_VALUE) {
+      Close();
+    }
+  }
   bool Connect();
   void Close();
   void set_listener(Listener* listener) { listener_ = listener; }
   bool Send(Message* message);
  private:
   const std::wstring PipeName(const std::wstring& channel_id) const;
   bool CreatePipe(const std::wstring& channel_id, Mode mode);
 
new file mode 100644
--- /dev/null
+++ b/ipc/glue/IOThreadChild.h
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=2 et :
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Plugin App.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Benoit Girard <b56girard@gmail.com>.
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef dom_plugins_IOThreadChild_h
+#define dom_plugins_IOThreadChild_h 1
+
+#include "chrome/common/child_thread.h"
+
+namespace mozilla {
+namespace ipc {
+//-----------------------------------------------------------------------------
+
+// The IOThreadChild class represents a background thread where the
+// IPC IO MessageLoop lives.
+class IOThreadChild : public ChildThread {
+public:
+  IOThreadChild()
+    : ChildThread(base::Thread::Options(MessageLoop::TYPE_IO,
+                                        0)) // stack size
+  { }
+
+  ~IOThreadChild()
+  { }
+
+  static MessageLoop* message_loop() {
+    return IOThreadChild::current()->Thread::message_loop();
+  }
+
+  // IOThreadChild owns the returned IPC::Channel.
+  static IPC::Channel* channel() {
+    return IOThreadChild::current()->ChildThread::channel();
+  }
+
+protected:
+  static IOThreadChild* current() {
+    return static_cast<IOThreadChild*>(ChildThread::current());
+  }
+
+private:
+  DISALLOW_EVIL_CONSTRUCTORS(IOThreadChild);
+};
+
+}  // namespace plugins
+}  // namespace mozilla
+
+#endif  // ifndef dom_plugins_IOThreadChild_h
--- a/ipc/glue/Makefile.in
+++ b/ipc/glue/Makefile.in
@@ -52,35 +52,36 @@ EXPORT_LIBRARY = 1
 EXPORTS_NAMESPACES = IPC mozilla/ipc
 
 EXPORTS_IPC = IPCMessageUtils.h
 
 EXPORTS_mozilla/ipc = \
   AsyncChannel.h \
   BrowserProcessSubThread.h \
   GeckoChildProcessHost.h \
-  MozillaChildThread.h \
+  IOThreadChild.h \
+  ProcessChild.h \
   ProtocolUtils.h \
   RPCChannel.h \
   SharedMemory.h \
   SharedMemoryBasic.h \
   SharedMemorySysV.h \
   Shmem.h \
   SyncChannel.h \
   ScopedXREEmbed.h \
   $(NULL)
 
 ENABLE_CXX_EXCEPTIONS = 1
 
 CPPSRCS += \
   AsyncChannel.cpp \
   BrowserProcessSubThread.cpp \
   GeckoChildProcessHost.cpp \
-  MozillaChildThread.cpp \
   MessagePump.cpp \
+  ProcessChild.cpp \
   RPCChannel.cpp \
   ScopedXREEmbed.cpp \
   Shmem.cpp \
   StringUtil.cpp \
   SyncChannel.cpp \
   $(NULL)
 
 ifeq ($(OS_ARCH),WINNT)
deleted file mode 100644
--- a/ipc/glue/MozillaChildThread.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: sw=2 ts=8 et :
- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Plugin App.
- *
- * The Initial Developer of the Original Code is
- *   Ben Turner <bent.mozilla@gmail.com>.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "mozilla/ipc/MozillaChildThread.h"
-
-#include "nsXPCOM.h"
-
-#ifdef XP_WIN
-#include <objbase.h>
-#endif
-
-namespace mozilla {
-namespace ipc {
-
-void
-MozillaChildThread::OnControlMessageReceived(const IPC::Message& aMessage) {
-  /*
-  IPC_BEGIN_MESSAGE_MAP(MozillaChildThread, aMessage)
-  IPC_END_MESSAGE_MAP()
-  */
-}
-
-void
-MozillaChildThread::Init()
-{
-  ChildThread::Init();
-
-#ifdef XP_WIN
-  // Silverlight depends on the host calling CoInitialize.
-  ::CoInitialize(NULL);
-#endif
-  // Add notification service here once bug 560630 is fixed
-
-  // Certain plugins, such as flash, steal the unhandled exception filter
-  // thus we never get crash reports when they fault. This call fixes it.
-  message_loop()->set_exception_restoration(true);
-
-  NS_LogInit();
-}
-
-void
-MozillaChildThread::CleanUp()
-{
-  NS_LogTerm();
-
-#ifdef XP_WIN
-  ::CoUninitialize();
-#endif
-}
-
-} // namespace ipc
-} // namespace mozilla
deleted file mode 100644
--- a/ipc/glue/MozillaChildThread.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: sw=2 ts=8 et :
- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Plugin App.
- *
- * The Initial Developer of the Original Code is
- *   Ben Turner <bent.mozilla@gmail.com>.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef mozilla_ipc_MozillaChildThread_h
-#define mozilla_ipc_MozillaChildThread_h
-
-#include "base/thread.h"
-#include "base/process.h"
-
-#include "chrome/common/child_thread.h"
-
-namespace mozilla {
-namespace ipc {
-
-/**
- * A MozillaChildThread is the main thread in a child process. It will
- * initialize XPCOM leak detectors (NS_LogInit) but it will not initialize
- * XPCOM (see ContentProcessThread for a child which uses XPCOM).
- */
-class MozillaChildThread : public ChildThread
-{
-public:
-  typedef base::ProcessHandle ProcessHandle;
-
-  MozillaChildThread(ProcessHandle aParentProcessHandle,
-		     MessageLoop::Type type=MessageLoop::TYPE_UI)
-  : ChildThread(base::Thread::Options(type,    // message loop type
-				      0,       // stack size
-				      false)), // wait for Init()?
-    mParentProcessHandle(aParentProcessHandle)
-  { }
-
-protected:
-  virtual void OnControlMessageReceived(const IPC::Message& aMessage);
-
-  ProcessHandle GetParentProcessHandle() {
-    return mParentProcessHandle;
-  }
-
-  // Thread implementation:
-  virtual void Init();
-  virtual void CleanUp();
-
-private:
-  ProcessHandle mParentProcessHandle;
-
-  DISALLOW_EVIL_CONSTRUCTORS(MozillaChildThread);
-};
-
-} /* namespace ipc */
-} /* namespace mozilla */
-
-#endif /* mozilla_ipc_MozillaChildThread_h */
new file mode 100644
--- /dev/null
+++ b/ipc/glue/ProcessChild.cpp
@@ -0,0 +1,66 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsDebug.h"
+
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/ipc/ProcessChild.h"
+
+namespace mozilla {
+namespace ipc {
+
+ProcessChild* ProcessChild::gProcessChild;
+
+ProcessChild::ProcessChild(ProcessHandle parentHandle)
+  : ChildProcess(new IOThreadChild())
+  , mUILoop(MessageLoop::current())
+  , mParentHandle(parentHandle)
+{
+  NS_ABORT_IF_FALSE(mUILoop, "UILoop should be created by now");
+  NS_ABORT_IF_FALSE(!gProcessChild, "should only be one ProcessChild");
+  gProcessChild = this;
+}
+
+ProcessChild::~ProcessChild()
+{
+  gProcessChild = NULL;
+}
+
+} // namespace ipc
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/ipc/glue/ProcessChild.h
@@ -0,0 +1,93 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: sw=2 ts=8 et :
+ */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at:
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Code.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_ipc_ProcessChild_h
+#define mozilla_ipc_ProcessChild_h
+
+#include "base/message_loop.h"
+#include "base/process.h"
+
+#include "chrome/common/child_process.h"
+
+// ProcessChild is the base class for all subprocesses of the main
+// browser process.  Its code runs on the thread that started in
+// main().
+
+namespace mozilla {
+namespace ipc {
+
+class ProcessChild : public ChildProcess {
+protected:
+  typedef base::ProcessHandle ProcessHandle;
+
+public:
+  ProcessChild(ProcessHandle parentHandle);
+  virtual ~ProcessChild();
+
+  virtual bool Init() = 0;
+  virtual void CleanUp()
+  { }
+
+  static MessageLoop* message_loop() {
+    return gProcessChild->mUILoop;
+  }
+
+protected:
+  static ProcessChild* current() {
+    return gProcessChild;
+  }
+
+  ProcessHandle ParentHandle() {
+    return mParentHandle;
+  }
+
+private:
+  static ProcessChild* gProcessChild;
+
+  MessageLoop* mUILoop;
+  ProcessHandle mParentHandle;
+
+  DISALLOW_EVIL_CONSTRUCTORS(ProcessChild);
+};
+
+} // namespace ipc
+} // namespace mozilla
+
+
+#endif // ifndef mozilla_ipc_ProcessChild_h
rename from ipc/ipdl/test/cxx/IPDLUnitTestThreadChild.cpp
rename to ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
--- a/ipc/ipdl/test/cxx/IPDLUnitTestThreadChild.cpp
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.cpp
@@ -31,35 +31,29 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-#include "IPDLUnitTestThreadChild.h"
+#include "mozilla/ipc/IOThreadChild.h"
 
+#include "IPDLUnitTestProcessChild.h"
 #include "IPDLUnitTests.h"
 
-using mozilla::ipc::MozillaChildThread;
+using mozilla::ipc::IOThreadChild;
 
 namespace mozilla {
 namespace _ipdltest {
 
-IPDLUnitTestThreadChild::IPDLUnitTestThreadChild(ProcessHandle aParentHandle) :
-    MozillaChildThread(aParentHandle)
-{
-}
-
-IPDLUnitTestThreadChild::~IPDLUnitTestThreadChild()
+bool
+IPDLUnitTestProcessChild::Init()
 {
-}
-
-void
-IPDLUnitTestThreadChild::Init()
-{
-    MozillaChildThread::Init();
-    IPDLUnitTestChildInit(channel(), GetParentProcessHandle(), owner_loop());
+    IPDLUnitTestChildInit(IOThreadChild::channel(),
+                          ParentHandle(),
+                          IOThreadChild::message_loop());
+    return true;
 }
 
 } // namespace _ipdltest
 } // namespace mozilla
rename from ipc/ipdl/test/cxx/IPDLUnitTestThreadChild.h
rename to ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
--- a/ipc/ipdl/test/cxx/IPDLUnitTestThreadChild.h
+++ b/ipc/ipdl/test/cxx/IPDLUnitTestProcessChild.h
@@ -34,27 +34,32 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
 #define mozilla__ipdltest_IPDLUnitTestThreadChild_h 1
 
-#include "mozilla/ipc/MozillaChildThread.h"
+#include "mozilla/ipc/ProcessChild.h"
 
 namespace mozilla {
 namespace _ipdltest {
 
-class IPDLUnitTestThreadChild : public mozilla::ipc::MozillaChildThread
+class IPDLUnitTestProcessChild : public mozilla::ipc::ProcessChild
 {
+  typedef mozilla::ipc::ProcessChild ProcessChild;
+
 public:
-  IPDLUnitTestThreadChild(ProcessHandle aParentHandle);
-  ~IPDLUnitTestThreadChild();
+  IPDLUnitTestProcessChild(ProcessHandle aParentHandle) :
+    ProcessChild(aParentHandle)
+  { }
 
-protected:
-  virtual void Init();
+  ~IPDLUnitTestProcessChild()
+  { }
+
+  virtual bool Init();
 };
 
 } // namespace _ipdltest
 } // namespace mozilla
 
 #endif // ifndef mozilla__ipdltest_IPDLUnitTestThreadChild_h
--- a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
+++ b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp
@@ -6,25 +6,23 @@
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "base/command_line.h"
 #include "base/string_util.h"
 
 #include "IPDLUnitTestSubprocess.h"
-#include "IPDLUnitTestThreadChild.h"
 
 //-----------------------------------------------------------------------------
 //===== TEMPLATED =====
 ${INCLUDES}
 //-----------------------------------------------------------------------------
 
 using mozilla::_ipdltest::IPDLUnitTestSubprocess;
-using mozilla::_ipdltest::IPDLUnitTestThreadChild;
 
 void* mozilla::_ipdltest::gParentActor;
 IPDLUnitTestSubprocess* mozilla::_ipdltest::gSubprocess;
 
 void* mozilla::_ipdltest::gChildActor;
 
 //-----------------------------------------------------------------------------
 // data/functions accessed by both parent and child processes
--- a/ipc/ipdl/test/cxx/Makefile.in
+++ b/ipc/ipdl/test/cxx/Makefile.in
@@ -43,17 +43,17 @@ include $(DEPTH)/config/autoconf.mk
 
 TOOL_DIRS += app
 
 MODULE = ipdlunittest
 
 EXPORTS_NAMESPACES = mozilla/_ipdltest
 EXPORTS_mozilla/_ipdltest =  \
   IPDLUnitTests.h  \
-  IPDLUnitTestThreadChild.h  \
+  IPDLUnitTestProcessChild.h  \
   IPDLUnitTestTypes.h \
   $(NULL)
 
 LIBRARY_NAME = $(MODULE)_s
 LIBXUL_LIBRARY = 1
 FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 
@@ -87,17 +87,17 @@ IPDLTESTSRCS = $(addsuffix .cpp,$(IPDLTE
 IPDLTESTHDRS = $(addprefix $(srcdir)/,$(addsuffix .h,$(IPDLTESTS)))
 
 TESTER_TEMPLATE := $(srcdir)/IPDLUnitTests.template.cpp
 GENTESTER := $(srcdir)/genIPDLUnitTests.py
 
 CPPSRCS =  \
   IPDLUnitTests.cpp  \
   IPDLUnitTestSubprocess.cpp  \
-  IPDLUnitTestThreadChild.cpp  \
+  IPDLUnitTestProcessChild.cpp  \
   $(IPDLTESTSRCS)  \
   $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 
--- a/toolkit/xre/nsEmbedFunctions.cpp
+++ b/toolkit/xre/nsEmbedFunctions.cpp
@@ -78,39 +78,38 @@
 #include "nsX11ErrorHandler.h"
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "base/message_loop.h"
 #include "base/process_util.h"
 #include "chrome/common/child_process.h"
 #include "chrome/common/notification_service.h"
 
+#include "mozilla/ipc/BrowserProcessSubThread.h"
 #include "mozilla/ipc/GeckoChildProcessHost.h"
-#include "mozilla/ipc/BrowserProcessSubThread.h"
+#include "mozilla/ipc/IOThreadChild.h"
+#include "mozilla/ipc/ProcessChild.h"
 #include "ScopedXREEmbed.h"
 
-#include "mozilla/plugins/PluginThreadChild.h"
-
-#include "mozilla/Monitor.h"
+#include "mozilla/plugins/PluginProcessChild.h"
 
 #ifdef MOZ_IPDL_TESTS
 #include "mozilla/_ipdltest/IPDLUnitTests.h"
-#include "mozilla/_ipdltest/IPDLUnitTestThreadChild.h"
+#include "mozilla/_ipdltest/IPDLUnitTestProcessChild.h"
 
-using mozilla::_ipdltest::IPDLUnitTestThreadChild;
+using mozilla::_ipdltest::IPDLUnitTestProcessChild;
 #endif  // ifdef MOZ_IPDL_TESTS
 
+using mozilla::ipc::BrowserProcessSubThread;
 using mozilla::ipc::GeckoChildProcessHost;
-using mozilla::ipc::BrowserProcessSubThread;
+using mozilla::ipc::IOThreadChild;
+using mozilla::ipc::ProcessChild;
 using mozilla::ipc::ScopedXREEmbed;
 
-using mozilla::plugins::PluginThreadChild;
-
-using mozilla::Monitor;
-using mozilla::MonitorAutoEnter;
+using mozilla::plugins::PluginProcessChild;
 
 using mozilla::startup::sChildProcessType;
 #endif
 
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 void
 XRE_GetStaticComponents(nsStaticModuleInfo const **aStaticComponents,
@@ -245,18 +244,16 @@ XRE_StringToChildProcessType(const char*
 
 #ifdef MOZ_IPC
 namespace mozilla {
 namespace startup {
 GeckoProcessType sChildProcessType = GeckoProcessType_Default;
 }
 }
 
-static MessageLoop* sIOMessageLoop;
-
 #if defined(MOZ_CRASHREPORTER)
 // FIXME/bug 539522: this out-of-place function is stuck here because
 // IPDL wants access to this crashreporter interface, and
 // crashreporter is built in such a way to make that awkward
 PRBool
 XRE_TakeMinidumpForChild(PRUint32 aChildPid, nsILocalFile** aDump)
 {
   return CrashReporter::TakeMinidumpForChild(aChildPid, aDump);
@@ -327,64 +324,66 @@ XRE_InitChildProcess(int aArgc,
   NS_LogInit();
 
   int rv = XRE_InitCommandLine(aArgc, aArgv);
   if (NS_FAILED(rv)) {
     NS_LogTerm();
     return NS_ERROR_FAILURE;
   }
 
-  MessageLoopForIO mainMessageLoop;
-
+  // Associate this thread with a UI MessageLoop
+  MessageLoopForUI uiMessageLoop;
   {
-    ChildThread* mainThread;
+    nsAutoPtr<ProcessChild> process;
 
     switch (aProcess) {
     case GeckoProcessType_Default:
       NS_RUNTIMEABORT("This makes no sense");
       break;
 
     case GeckoProcessType_Plugin:
-      mainThread = new PluginThreadChild(parentHandle);
+      process = new PluginProcessChild(parentHandle);
       break;
 
     case GeckoProcessType_IPDLUnitTest:
 #ifdef MOZ_IPDL_TESTS
-      mainThread = new IPDLUnitTestThreadChild(parentHandle);
-#else
+      process = new IPDLUnitTestProcessChild(parentHandle);
+#else 
       NS_RUNTIMEABORT("rebuild with --enable-ipdl-tests");
 #endif
       break;
 
     default:
       NS_RUNTIMEABORT("Unknown main thread class");
     }
 
-    ChildProcess process(mainThread);
+    if (!process->Init()) {
+      NS_LogTerm();
+      return NS_ERROR_FAILURE;
+    }
 
-    // Do IPC event loop
-    sIOMessageLoop = MessageLoop::current();
+    // Run the UI event loop on the main thread.
+    uiMessageLoop.MessageLoop::Run();
 
-    sIOMessageLoop->Run();
-
-    sIOMessageLoop = nsnull;
+    // Allow ProcessChild to clean up after itself before going out of
+    // scope and being deleted
+    process->CleanUp();
   }
 
   NS_LogTerm();
   return XRE_DeinitCommandLine();
 }
 
 MessageLoop*
 XRE_GetIOMessageLoop()
 {
   if (sChildProcessType == GeckoProcessType_Default) {
-    NS_ASSERTION(!sIOMessageLoop, "Shouldn't be set on parent process!");
     return BrowserProcessSubThread::GetMessageLoop(BrowserProcessSubThread::IO);
   }
-  return sIOMessageLoop;
+  return IOThreadChild::message_loop();
 }
 
 namespace {
 
 class MainFunctionRunnable : public nsRunnable
 {
 public:
   NS_DECL_NSIRUNNABLE
@@ -487,17 +486,23 @@ XRE_RunAppShell()
 void
 XRE_ShutdownChildProcess()
 {
   NS_ABORT_IF_FALSE(MessageLoopForUI::current(), "Wrong thread!");
 
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
   NS_ABORT_IF_FALSE(!!ioLoop, "Bad shutdown order");
 
-  ioLoop->PostTask(FROM_HERE, new MessageLoop::QuitTask());
+  // Quit() sets off the following chain of events
+  //  (1) UI loop starts quitting
+  //  (2) UI loop returns from Run() in XRE_InitChildProcess()
+  //  (3) ProcessChild goes out of scope and terminates the IO thread
+  //  (4) ProcessChild joins the IO thread
+  //  (5) exit()
+  MessageLoop::current()->Quit(); 
 }
 
 #ifdef MOZ_X11
 void
 XRE_InstallX11ErrorHandler()
 {
   InstallX11ErrorHandler();
 }
--- a/toolkit/xre/nsX11ErrorHandler.cpp
+++ b/toolkit/xre/nsX11ErrorHandler.cpp
@@ -34,18 +34,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsX11ErrorHandler.h"
 
 #ifdef MOZ_IPC
-#include "mozilla/plugins/PluginThreadChild.h"
-using mozilla::plugins::PluginThreadChild;
+#include "mozilla/plugins/PluginProcessChild.h"
+using mozilla::plugins::PluginProcessChild;
 #endif
 
 #include "prenv.h"
 #include "nsXULAppAPI.h"
 #include "nsExceptionHandler.h"
 #include "nsDebug.h"
 
 #ifdef MOZ_WIDGET_GTK2
@@ -152,17 +152,17 @@ X11Error(Display *display, XErrorEvent *
     CrashReporter::AppendAppNotesToCrashReport(notes);
     break;
 #ifdef MOZ_IPC
   case GeckoProcessType_Plugin:
     if (CrashReporter::GetEnabled()) {
       // This is assuming that X operations are performed on the plugin
       // thread.  If plugins are using X on another thread, then we'll need to
       // handle that differently.
-      PluginThreadChild::AppendNotesToCrashReport(notes);
+      PluginProcessChild::AppendNotesToCrashReport(notes);
     }
     break;
 #endif
   default: 
     ; // crash report notes not supported.
   }
 #endif