Bug 771765 - Support template content process, part 6: support re-creation of the threads created in the template process. r=khuey, r=jorendorff
authorThinker Lee <tlee@mozilla.com>, Cervantes Yu <cyu@mozilla.com>
Mon, 03 Jun 2013 18:14:42 +0800
changeset 163143 014ba29f0b931e69db61d1ff2acdf5f9e9a0c8e4
parent 163142 f75dd995b88d5dd7138556073f655ce9576dabf4
child 163144 221697fc3a86062a1536d8328a7af54444bd5bf3
push id3066
push userakeybl@mozilla.com
push dateMon, 09 Dec 2013 19:58:46 +0000
treeherdermozilla-beta@a31a0dce83aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskhuey, jorendorff
bugs771765
milestone27.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 771765 - Support template content process, part 6: support re-creation of the threads created in the template process. r=khuey, r=jorendorff The threads that are frozen/recreated include: * ImageBridgeChildThread. * Image decoding thread pool. * IPC thread (checkpointed, but not frozen). * GC Helper thread. * XPC runtime watchdog thread. * Socket transport service thread/thread pool. * Memory pressure watcher. * Timer thread. * DOM promise worker.
dom/workers/RuntimeService.cpp
gfx/layers/ipc/ImageBridgeChild.cpp
image/src/RasterImage.cpp
ipc/chromium/src/chrome/common/child_thread.cc
ipc/chromium/src/chrome/common/child_thread.h
js/src/configure.in
js/src/jsgc.cpp
js/xpconnect/src/XPCJSRuntime.cpp
netwerk/base/src/nsSocketTransportService2.cpp
netwerk/base/src/nsStreamTransportService.cpp
widget/gonk/GonkMemoryPressureMonitoring.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/threads/TimerThread.cpp
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -40,16 +40,20 @@
 #include "nsXPCOMPrivate.h"
 #include "OSFileConstants.h"
 #include "xpcpublic.h"
 
 #include "Events.h"
 #include "Worker.h"
 #include "WorkerPrivate.h"
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 
 USING_WORKERS_NAMESPACE
 
 using mozilla::MutexAutoLock;
 using mozilla::MutexAutoUnlock;
 using mozilla::Preferences;
@@ -888,16 +892,24 @@ public:
   : mWorkerPrivate(aWorkerPrivate)
   {
     NS_ASSERTION(mWorkerPrivate, "This should never be null!");
   }
 
   NS_IMETHOD
   Run()
   {
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess()) {
+      NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
+                   "NuwaMarkCurrentThread is undefined!");
+      NuwaMarkCurrentThread(nullptr, nullptr);
+      NuwaFreezeCurrentThread();
+    }
+#endif
     WorkerPrivate* workerPrivate = mWorkerPrivate;
     mWorkerPrivate = nullptr;
 
     workerPrivate->AssertIsOnWorkerThread();
 
     {
       nsCycleCollector_startup();
 
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -356,16 +356,20 @@ ConnectImageBridgeInChildProcess(Transpo
                                  ProcessHandle aOtherProcess)
 {
   // Bind the IPC channel to the image bridge thread.
   sImageBridgeChildSingleton->Open(aTransport, aOtherProcess,
                                    XRE_GetIOMessageLoop(),
                                    ipc::ChildSide);
 }
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 static void ReleaseImageClientNow(ImageClient* aClient)
 {
   MOZ_ASSERT(InImageBridgeChildThread());
   aClient->Release();
 }
 
 // static
 void ImageBridgeChild::DispatchReleaseImageClient(ImageClient* aClient)
@@ -532,16 +536,26 @@ ImageBridgeChild::StartUpInChildProcess(
     return false;
   }
 
   sImageBridgeChildThread = new Thread("ImageBridgeChild");
   if (!sImageBridgeChildThread->Start()) {
     return false;
   }
 
+#ifdef MOZ_NUWA_PROCESS
+  if (IsNuwaProcess()) {
+    sImageBridgeChildThread
+      ->message_loop()->PostTask(FROM_HERE,
+                                 NewRunnableFunction(NuwaMarkCurrentThread,
+                                                     (void (*)(void *))nullptr,
+                                                     (void *)nullptr));
+  }
+#endif
+
   sImageBridgeChildSingleton = new ImageBridgeChild();
   sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
     FROM_HERE,
     NewRunnableFunction(ConnectImageBridgeInChildProcess,
                         aTransport, processHandle));
 
   return true;
 }
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -38,16 +38,20 @@
 #include "mozilla/TimeStamp.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/gfx/Scale.h"
 
 #include "GeckoProfiler.h"
 #include "gfx2DGlue.h"
 #include <algorithm>
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::image;
 using namespace mozilla::layers;
 
 // a mask for flags that will affect the decoding
 #define DECODE_FLAGS_MASK (imgIContainer::FLAG_DECODE_NO_PREMULTIPLY_ALPHA | imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION)
 #define DECODE_FLAGS_DEFAULT 0
 
@@ -3050,16 +3054,47 @@ RasterImage::DecodePool::Singleton()
 
 already_AddRefed<nsIEventTarget>
 RasterImage::DecodePool::GetEventTarget()
 {
   nsCOMPtr<nsIEventTarget> target = do_QueryInterface(mThreadPool);
   return target.forget();
 }
 
+#ifdef MOZ_NUWA_PROCESS
+
+class RIDThreadPoolListener : public nsIThreadPoolListener
+{
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+    NS_DECL_NSITHREADPOOLLISTENER
+
+    RIDThreadPoolListener() {}
+    ~RIDThreadPoolListener() {}
+};
+
+NS_IMPL_ISUPPORTS1(RIDThreadPoolListener, nsIThreadPoolListener)
+
+NS_IMETHODIMP
+RIDThreadPoolListener::OnThreadCreated()
+{
+    if (IsNuwaProcess()) {
+        NuwaMarkCurrentThread((void (*)(void *))nullptr, nullptr);
+    }
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+RIDThreadPoolListener::OnThreadShuttingDown()
+{
+    return NS_OK;
+}
+
+#endif // MOZ_NUWA_PROCESS
+
 RasterImage::DecodePool::DecodePool()
  : mThreadPoolMutex("Thread Pool")
 {
   if (gMultithreadedDecoding) {
     mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
     if (mThreadPool) {
       mThreadPool->SetName(NS_LITERAL_CSTRING("ImageDecoder"));
       uint32_t limit;
@@ -3067,16 +3102,22 @@ RasterImage::DecodePool::DecodePool()
         limit = std::max(PR_GetNumberOfProcessors(), 2) - 1;
       } else {
         limit = static_cast<uint32_t>(gDecodingThreadLimit);
       }
 
       mThreadPool->SetThreadLimit(limit);
       mThreadPool->SetIdleThreadLimit(limit);
 
+#ifdef MOZ_NUWA_PROCESS
+      if (IsNuwaProcess()) {
+        mThreadPool->SetListener(new RIDThreadPoolListener());
+      }
+#endif
+
       nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
       if (obsSvc) {
         obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
       }
     }
   }
 }
 
--- a/ipc/chromium/src/chrome/common/child_thread.cc
+++ b/ipc/chromium/src/chrome/common/child_thread.cc
@@ -21,24 +21,45 @@ ChildThread::ChildThread(Thread::Options
   DCHECK(owner_loop_);
   channel_name_ = CommandLine::ForCurrentProcess()->GetSwitchValue(
       switches::kProcessChannelID);
 }
 
 ChildThread::~ChildThread() {
 }
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 bool ChildThread::Run() {
-  return StartWithOptions(options_);
+  bool r = StartWithOptions(options_);
+#ifdef MOZ_NUWA_PROCESS
+  NS_ASSERTION(NuwaMarkCurrentThread, "NuwaMarkCurrentThread is not defined!");
+  if (IsNuwaProcess()) {
+      message_loop()->PostTask(FROM_HERE,
+                               NewRunnableFunction(&ChildThread::MarkThread));
+  }
+#endif
+  return r;
 }
 
 void ChildThread::OnChannelError() {
   owner_loop_->PostTask(FROM_HERE, new MessageLoop::QuitTask());
 }
 
+#ifdef MOZ_NUWA_PROCESS
+void ChildThread::MarkThread() {
+    NuwaMarkCurrentThread(nullptr, nullptr);
+    if (!NuwaCheckpointCurrentThread()) {
+        NS_RUNTIMEABORT("Should not be here!");
+    }
+}
+#endif
+
 bool ChildThread::Send(IPC::Message* msg) {
   if (!channel_.get()) {
     delete msg;
     return false;
   }
 
   return channel_->Send(msg);
 }
--- a/ipc/chromium/src/chrome/common/child_thread.h
+++ b/ipc/chromium/src/chrome/common/child_thread.h
@@ -56,16 +56,20 @@ class ChildThread : public IPC::Channel:
   virtual void Init();
   virtual void CleanUp();
 
  private:
   // IPC::Channel::Listener implementation:
   virtual void OnMessageReceived(const IPC::Message& msg);
   virtual void OnChannelError();
 
+#ifdef MOZ_NUWA_PROCESS
+  static void MarkThread();
+#endif
+
   // The message loop used to run tasks on the thread that started this thread.
   MessageLoop* owner_loop_;
 
   std::wstring channel_name_;
   scoped_ptr<IPC::Channel> channel_;
 
   // Used only on the background render thread to implement message routing
   // functionality to the consumers of the ChildThread.
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4044,16 +4044,20 @@ COMPILE_CXXFLAGS=`echo \
     $_DEFINES_CXXFLAGS \
 	$_DEPEND_CFLAGS \
     $COMPILE_CXXFLAGS`
 
 AC_SUBST(NSPR_CFLAGS)
 AC_SUBST(NSPR_LIBS)
 AC_SUBST(MOZ_NATIVE_NSPR)
 
+if test -n "$MOZ_NUWA_PROCESS"; then
+    AC_DEFINE(MOZ_NUWA_PROCESS)
+fi
+
 OS_CFLAGS="$CFLAGS"
 OS_CXXFLAGS="$CXXFLAGS"
 OS_CPPFLAGS="$CPPFLAGS"
 OS_COMPILE_CFLAGS="$COMPILE_CFLAGS"
 OS_COMPILE_CXXFLAGS="$COMPILE_CXXFLAGS"
 OS_LDFLAGS="$LDFLAGS"
 OS_LIBS="$LIBS"
 AC_SUBST(OS_CFLAGS)
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2274,21 +2274,36 @@ GCHelperThread::finish()
     if (wakeup)
         PR_DestroyCondVar(wakeup);
     if (done)
         PR_DestroyCondVar(done);
 #endif /* JS_THREADSAFE */
 }
 
 #ifdef JS_THREADSAFE
+#ifdef MOZ_NUWA_PROCESS
+extern "C" {
+MFBT_API bool IsNuwaProcess();
+MFBT_API void NuwaMarkCurrentThread(void (*recreate)(void *), void *arg);
+}
+#endif
+
 /* static */
 void
 GCHelperThread::threadMain(void *arg)
 {
     PR_SetCurrentThreadName("JS GC Helper");
+
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess && IsNuwaProcess()) {
+        JS_ASSERT(NuwaMarkCurrentThread != nullptr);
+        NuwaMarkCurrentThread(nullptr, nullptr);
+    }
+#endif
+
     static_cast<GCHelperThread *>(arg)->threadLoop();
 }
 
 void
 GCHelperThread::threadLoop()
 {
     AutoLockGC lock(rt);
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -1017,16 +1017,20 @@ class Watchdog
     PRLock *mLock;
     PRCondVar *mWakeup;
     PRThread *mThread;
     bool mHibernating;
     bool mInitialized;
     bool mShuttingDown;
 };
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 class WatchdogManager : public nsIObserver
 {
   public:
 
     NS_DECL_ISUPPORTS
     WatchdogManager(XPCJSRuntime *aRuntime) : mRuntime(aRuntime)
                                             , mRuntimeState(RUNTIME_INACTIVE)
     {
@@ -1150,16 +1154,25 @@ AutoLockWatchdog::~AutoLockWatchdog()
     PR_Unlock(mWatchdog->GetLock());
 }
 
 static void
 WatchdogMain(void *arg)
 {
     PR_SetCurrentThreadName("JS Watchdog");
 
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess()) {
+        NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
+                     "NuwaMarkCurrentThread is undefined!");
+        NuwaMarkCurrentThread(nullptr, nullptr);
+        NuwaFreezeCurrentThread();
+    }
+#endif
+
     Watchdog* self = static_cast<Watchdog*>(arg);
     WatchdogManager* manager = self->Manager();
 
     // Lock lasts until we return
     AutoLockWatchdog lock(self);
 
     MOZ_ASSERT(self->Initialized());
     MOZ_ASSERT(!self->ShuttingDown());
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -629,21 +629,33 @@ nsSocketTransportService::OnProcessNextE
 
 NS_IMETHODIMP
 nsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal* thread,
                                                 uint32_t depth)
 {
     return NS_OK;
 }
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 NS_IMETHODIMP
 nsSocketTransportService::Run()
 {
     PR_SetCurrentThreadName("Socket Thread");
 
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess()) {
+        NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
+                     "NuwaMarkCurrentThread is undefined!");
+        NuwaMarkCurrentThread(nullptr, nullptr);
+    }
+#endif
+
     SOCKET_LOG(("STS thread init\n"));
 
     psm::InitializeSSLServerCertVerificationThreads();
 
     gSocketThread = PR_GetCurrentThread();
 
     // add thread event to poll list (mThreadEvent may be nullptr)
     mPollList[0].fd = mThreadEvent;
--- a/netwerk/base/src/nsStreamTransportService.cpp
+++ b/netwerk/base/src/nsStreamTransportService.cpp
@@ -420,16 +420,48 @@ nsOutputStreamTransport::WriteFrom(nsIIn
 
 NS_IMETHODIMP
 nsOutputStreamTransport::IsNonBlocking(bool *result)
 {
     *result = false;
     return NS_OK;
 }
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+
+class STSThreadPoolListener : public nsIThreadPoolListener
+{
+public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+    NS_DECL_NSITHREADPOOLLISTENER
+
+    STSThreadPoolListener() {}
+    ~STSThreadPoolListener() {}
+};
+
+NS_IMPL_ISUPPORTS1(STSThreadPoolListener, nsIThreadPoolListener)
+
+NS_IMETHODIMP
+STSThreadPoolListener::OnThreadCreated()
+{
+    if (IsNuwaProcess()) {
+        NuwaMarkCurrentThread(nullptr, nullptr);
+    }
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+STSThreadPoolListener::OnThreadShuttingDown()
+{
+    return NS_OK;
+}
+
+#endif	// MOZ_NUWA_PROCESS
+
 //-----------------------------------------------------------------------------
 // nsStreamTransportService
 //-----------------------------------------------------------------------------
 
 nsStreamTransportService::~nsStreamTransportService()
 {
     NS_ASSERTION(!mPool, "thread pool wasn't shutdown");
 }
@@ -440,16 +472,21 @@ nsStreamTransportService::Init()
     mPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
     NS_ENSURE_STATE(mPool);
 
     // Configure the pool
     mPool->SetName(NS_LITERAL_CSTRING("StreamTrans"));
     mPool->SetThreadLimit(25);
     mPool->SetIdleThreadLimit(1);
     mPool->SetIdleThreadTimeout(PR_SecondsToInterval(30));
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess()) {
+	mPool->SetListener(new STSThreadPoolListener());
+    }
+#endif
 
     nsCOMPtr<nsIObserverService> obsSvc =
         mozilla::services::GetObserverService();
     if (obsSvc)
         obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
     return NS_OK;
 }
 
--- a/widget/gonk/GonkMemoryPressureMonitoring.cpp
+++ b/widget/gonk/GonkMemoryPressureMonitoring.cpp
@@ -16,16 +16,20 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <poll.h>
 #include <android/log.h>
 
 #define LOG(args...)  \
   __android_log_print(ANDROID_LOG_INFO, "GonkMemoryPressure" , ## args)
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 using namespace mozilla;
 
 namespace {
 
 /**
  * MemoryPressureWatcher watches sysfs from its own thread to notice when the
  * system is under memory pressure.  When we observe memory pressure, we use
  * MemoryPressureRunnable to notify observers that they should release memory.
@@ -108,16 +112,24 @@ public:
 
     return NS_OK;
   }
 
   NS_IMETHOD Run()
   {
     MOZ_ASSERT(!NS_IsMainThread());
 
+#ifdef MOZ_NUWA_PROCESS
+    if (IsNuwaProcess()) {
+      NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
+                   "NuwaMarkCurrentThread is undefined!");
+      NuwaMarkCurrentThread(nullptr, nullptr);
+    }
+#endif
+
     int lowMemFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active",
                         O_RDONLY | O_CLOEXEC);
     NS_ENSURE_STATE(lowMemFd != -1);
     ScopedClose autoClose(lowMemFd);
 
     nsresult rv = CheckForMemoryPressure(lowMemFd, nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -888,16 +888,20 @@ nsPurpleBuffer::SelectPointers(GCGraphBu
 }
 
 enum ccType {
     ScheduledCC, /* Automatically triggered, based on time or the purple buffer. */
     ManualCC,    /* Explicitly triggered. */
     ShutdownCC   /* Shutdown CC, used for finding leaks. */
 };
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 ////////////////////////////////////////////////////////////////////////
 // Top level structure for the cycle collector.
 ////////////////////////////////////////////////////////////////////////
 
 class nsCycleCollector
 {
     friend class GCGraphBuilder;
 
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -154,21 +154,33 @@ nsresult TimerThread::Shutdown()
   }
 
   mThread->Shutdown();    // wait for the thread to die
 
   PR_LOG(GetTimerLog(), PR_LOG_DEBUG, ("TimerThread::Shutdown end\n"));
   return NS_OK;
 }
 
+#ifdef MOZ_NUWA_PROCESS
+#include "ipc/Nuwa.h"
+#endif
+
 /* void Run(); */
 NS_IMETHODIMP TimerThread::Run()
 {
   PR_SetCurrentThreadName("Timer");
 
+#ifdef MOZ_NUWA_PROCESS
+  if (IsNuwaProcess()) {
+    NS_ASSERTION(NuwaMarkCurrentThread != nullptr,
+                 "NuwaMarkCurrentThread is undefined!");
+    NuwaMarkCurrentThread(nullptr, nullptr);
+  }
+#endif
+
   MonitorAutoLock lock(mMonitor);
 
   // We need to know how many microseconds give a positive PRIntervalTime. This
   // is platform-dependent, we calculate it at runtime now.
   // First we find a value such that PR_MicrosecondsToInterval(high) = 1
   int32_t low = 0, high = 1;
   while (PR_MicrosecondsToInterval(high) == 0)
     high <<= 1;