Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Tue, 23 Oct 2012 22:41:34 -0400
changeset 111345 3593d9ccfec22d065ee4fa6065dca29be4990439
parent 111344 b43af99c5e5b54fa0baff63af7dd5d73819e4d59 (current diff)
parent 111323 93cc1ee9429165ad859ac031ade8fde49eceeeaa (diff)
child 111346 0d2953f1459789258bf0409f5ff2bc0381aa4f5e
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
milestone19.0a1
Merge m-c to inbound.
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -34,16 +34,17 @@
 
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 
 #include "nsWrapperCacheInlines.h"
 #include "nsDOMMutationObserver.h"
 #include "nsICycleCollectorListener.h"
+#include "nsThread.h"
 
 using namespace mozilla::dom;
 using namespace xpc;
 
 NS_IMPL_THREADSAFE_ISUPPORTS7(nsXPConnect,
                               nsIXPConnect,
                               nsISupportsWeakReference,
                               nsIThreadObserver,
@@ -152,23 +153,22 @@ nsXPConnect::GetXPConnect()
         if (!gSelf->mInterfaceInfoManager) {
             NS_RUNTIMEABORT("Couldn't get global interface info manager.");
         }
 
         // Initial extra ref to keep the singleton alive
         // balanced by explicit call to ReleaseXPConnectSingleton()
         NS_ADDREF(gSelf);
 
-        // Add XPConnect as an thread observer.
+        // Set XPConnect as the main thread observer.
         //
         // The cycle collector sometimes calls GetXPConnect, but it should never
         // be the one that initializes gSelf.
         MOZ_ASSERT(NS_IsMainThread());
-        nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
-        if (NS_FAILED(thread->AddObserver(gSelf))) {
+        if (NS_FAILED(nsThread::SetMainThreadObserver(gSelf))) {
             NS_RELEASE(gSelf);
             // Fall through to returning null
         }
     }
     return gSelf;
 }
 
 // static
@@ -181,24 +181,17 @@ nsXPConnect::GetSingleton()
 }
 
 // static
 void
 nsXPConnect::ReleaseXPConnectSingleton()
 {
     nsXPConnect* xpc = gSelf;
     if (xpc) {
-
-        // The thread subsystem may have been shut down already, so make sure
-        // to check for null here.
-        nsCOMPtr<nsIThreadInternal> thread = do_QueryInterface(NS_GetCurrentThread());
-        if (thread) {
-            MOZ_ASSERT(NS_IsMainThread());
-            thread->RemoveObserver(xpc);
-        }
+        nsThread::SetMainThreadObserver(nullptr);
 
 #ifdef DEBUG
         // force a dump of the JavaScript gc heap if JS is still alive
         // if requested through XPC_SHUTDOWN_HEAP_DUMP environment variable
         {
             const char* dumpName = getenv("XPC_SHUTDOWN_HEAP_DUMP");
             if (dumpName) {
                 FILE* dumpFile = (*dumpName == '\0' ||
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -42,16 +42,18 @@ using namespace mozilla;
 
 #ifdef PR_LOGGING
 static PRLogModuleInfo *sLog = PR_NewLogModule("nsThread");
 #endif
 #define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
 
 NS_DECL_CI_INTERFACE_GETTER(nsThread)
 
+nsIThreadObserver* nsThread::sMainThreadObserver = nullptr;
+
 namespace mozilla {
 
 // Fun fact: Android's GCC won't convert bool* to int32_t*, so we can't
 // PR_ATOMIC_SET a bool.
 static int32_t sMemoryPressurePending = 0;
 
 /*
  * It's important that this function not acquire any locks, nor do anything
@@ -575,16 +577,22 @@ nsThread::ProcessNextEvent(bool mayWait,
                             NS_LITERAL_STRING("low-memory").get());
       }
       else {
         NS_WARNING("Can't get observer service!");
       }
     }
   }
 
+  bool notifyMainThreadObserver =
+    (MAIN_THREAD == mIsMainThread) && sMainThreadObserver;
+  if (notifyMainThreadObserver) 
+   sMainThreadObserver->OnProcessNextEvent(this, mayWait && !ShuttingDown(),
+                                           mRunningEvent);
+
   nsCOMPtr<nsIThreadObserver> obs = mObserver;
   if (obs)
     obs->OnProcessNextEvent(this, mayWait && !ShuttingDown(), mRunningEvent);
 
   NOTIFY_EVENT_OBSERVERS(OnProcessNextEvent,
                          (this, mayWait && !ShuttingDown(), mRunningEvent));
 
   ++mRunningEvent;
@@ -619,16 +627,19 @@ nsThread::ProcessNextEvent(bool mayWait,
 
   --mRunningEvent;
 
   NOTIFY_EVENT_OBSERVERS(AfterProcessNextEvent, (this, mRunningEvent));
 
   if (obs)
     obs->AfterProcessNextEvent(this, mRunningEvent);
 
+  if (notifyMainThreadObserver && sMainThreadObserver)
+    sMainThreadObserver->AfterProcessNextEvent(this, mRunningEvent);
+
   return rv;
 }
 
 //-----------------------------------------------------------------------------
 // nsISupportsPriority
 
 NS_IMETHODIMP
 nsThread::GetPriority(int32_t *priority)
@@ -727,16 +738,31 @@ nsThread::RemoveObserver(nsIThreadObserv
 
   if (observer && !mEventObservers.RemoveElement(observer)) {
     NS_WARNING("Removing an observer that was never added!");
   }
 
   return NS_OK;
 }
 
+nsresult
+nsThread::SetMainThreadObserver(nsIThreadObserver* aObserver)
+{
+  if (aObserver && nsThread::sMainThreadObserver) {
+    return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  if (!NS_IsMainThread()) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  nsThread::sMainThreadObserver = aObserver;
+  return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsThreadSyncDispatch::Run()
 {
   if (mSyncTask) {
     mResult = mSyncTask->Run();
     mSyncTask = nullptr;
--- a/xpcom/threads/nsThread.h
+++ b/xpcom/threads/nsThread.h
@@ -45,17 +45,22 @@ public:
 
   // If this flag is true, then the nsThread was created using
   // nsIThreadManager::NewThread.
   bool ShutdownRequired() { return mShutdownRequired; }
 
   // Clear the observer list.
   void ClearObservers() { mEventObservers.Clear(); }
 
+  static nsresult
+  SetMainThreadObserver(nsIThreadObserver* aObserver);
+
 private:
+  static nsIThreadObserver* sMainThreadObserver;
+
   friend class nsThreadShutdownEvent;
 
   ~nsThread();
 
   bool ShuttingDown() { return mShutdownContext != nullptr; }
 
   static void ThreadFunc(void *arg);