Bug 1323100 - Register most of the remaining threadfunc threads with the profiler. r?froydnj draft
authorMarkus Stange <mstange@themasta.com>
Thu, 05 Jan 2017 16:34:26 +0100
changeset 456893 fcc61ab1ce2362e92bc3efe3bdf8a69842f2d621
parent 456892 95bf7ae1196bfb51cbd72099be926d91d4436acf
child 456894 6c14817f368b93f59b340e949298aa9531e09c3d
push id40636
push userbmo:mstange@themasta.com
push dateFri, 06 Jan 2017 12:38:48 +0000
reviewersfroydnj
bugs1323100
milestone53.0a1
Bug 1323100 - Register most of the remaining threadfunc threads with the profiler. r?froydnj As far as I can tell, this covers all the remaining threads which we start using PR_CreateThread, except the ones that are created inside NSPR or NSS, and except for the Shutdown Watchdog thread in nsTerminator.cpp and the CacheIO thread. The Shutdown Watchdog thread stays alive past leak detection during shutdown (by design), so we'd report leaks if we profiled it. The CacheIO thread seems to stay alive past shutdown leak detection sometimes as well. This adds a AutoProfilerRegister stack class for easy registering and unregistering. There are a few places where we still call profiler_register_thread() and profiler_unregister_thread() manually, either because registration happens conditionally, or because there is a variable that gets put on the stack before the AutoProfilerRegister (e.g. a dynamically generated thread name). AutoProfilerRegister needs to be the first object on the stack because it uses its own `this` pointer as the stack top address. MozReview-Commit-ID: 3vwhS55Yzt
dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
dom/storage/StorageDBThread.cpp
js/xpconnect/src/XPCJSContext.cpp
netwerk/cache2/CacheIOThread.cpp
netwerk/dns/nsHostResolver.cpp
security/manager/ssl/nsKeygenThread.cpp
security/manager/ssl/nsProtectedAuthThread.cpp
security/manager/ssl/nsSmartCardMonitor.cpp
startupcache/StartupCache.cpp
toolkit/components/terminator/nsTerminator.cpp
toolkit/xre/EventTracer.cpp
tools/profiler/public/GeckoProfiler.h
tools/profiler/public/GeckoProfilerImpl.h
xpcom/build/MainThreadIOLogger.cpp
xpcom/threads/BackgroundHangMonitor.cpp
xpcom/threads/HangMonitor.cpp
xpcom/threads/nsProcessCommon.cpp
--- a/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
+++ b/dom/media/webaudio/blink/HRTFDatabaseLoader.cpp
@@ -23,16 +23,17 @@
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
 #include "HRTFDatabaseLoader.h"
 #include "HRTFDatabase.h"
+#include "GeckoProfiler.h"
 
 using namespace mozilla;
 
 namespace WebCore {
 
 // Singleton
 nsTHashtable<HRTFDatabaseLoader::LoaderByRateEntry>*
     HRTFDatabaseLoader::s_loaderMap = nullptr;
@@ -146,16 +147,17 @@ void HRTFDatabaseLoader::MainThreadRelea
         // on this (main) thread.
         delete this;
     }
 }
 
 // Asynchronously load the database in this thread.
 static void databaseLoaderEntry(void* threadData)
 {
+    AutoProfilerRegister registerThread("HRTFDatabaseLdr");
     PR_SetCurrentThreadName("HRTFDatabaseLdr");
 
     HRTFDatabaseLoader* loader = reinterpret_cast<HRTFDatabaseLoader*>(threadData);
     MOZ_ASSERT(loader);
     loader->load();
 }
 
 void HRTFDatabaseLoader::load()
--- a/dom/storage/StorageDBThread.cpp
+++ b/dom/storage/StorageDBThread.cpp
@@ -22,16 +22,17 @@
 #include "mozIStorageValueArray.h"
 #include "mozIStorageFunction.h"
 #include "mozilla/BasePrincipal.h"
 #include "nsIObserverService.h"
 #include "nsVariant.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/Services.h"
 #include "mozilla/Tokenizer.h"
+#include "GeckoProfiler.h"
 
 // How long we collect write oprerations
 // before they are flushed to the database
 // In milliseconds.
 #define FLUSHING_INTERVAL_MS 5000
 
 // Write Ahead Log's maximum size is 512KB
 #define MAX_WAL_SIZE_BYTES 512 * 1024
@@ -334,16 +335,17 @@ StorageDBThread::SetDefaultPriority()
   if (--mPriorityCounter <= 0) {
     PR_SetThreadPriority(mThread, PR_PRIORITY_LOW);
   }
 }
 
 void
 StorageDBThread::ThreadFunc(void* aArg)
 {
+  AutoProfilerRegister registerThread("localStorage DB");
   PR_SetCurrentThreadName("localStorage DB");
   mozilla::IOInterposer::RegisterCurrentThread();
 
   StorageDBThread* thread = static_cast<StorageDBThread*>(aArg);
   thread->ThreadFunc();
   mozilla::IOInterposer::UnregisterCurrentThread();
 }
 
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -1161,16 +1161,17 @@ AutoLockWatchdog::AutoLockWatchdog(Watch
 AutoLockWatchdog::~AutoLockWatchdog()
 {
     PR_Unlock(mWatchdog->GetLock());
 }
 
 static void
 WatchdogMain(void* arg)
 {
+    mozilla::AutoProfilerRegister registerThread("JS Watchdog");
     PR_SetCurrentThreadName("JS Watchdog");
 
     Watchdog* self = static_cast<Watchdog*>(arg);
     WatchdogManager* manager = self->Manager();
 
     // Lock lasts until we return
     AutoLockWatchdog lock(self);
 
--- a/netwerk/cache2/CacheIOThread.cpp
+++ b/netwerk/cache2/CacheIOThread.cpp
@@ -5,16 +5,17 @@
 #include "CacheIOThread.h"
 #include "CacheFileIOManager.h"
 
 #include "nsIRunnable.h"
 #include "nsISupportsImpl.h"
 #include "nsPrintfCString.h"
 #include "nsThreadUtils.h"
 #include "mozilla/IOInterposer.h"
+#include "GeckoProfiler.h"
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
 #ifdef MOZ_TASK_TRACER
 #include "GeckoTaskTracer.h"
 #include "TracedTaskCommon.h"
@@ -432,16 +433,18 @@ already_AddRefed<nsIEventTarget> CacheIO
   }
 
   return target.forget();
 }
 
 // static
 void CacheIOThread::ThreadFunc(void* aClosure)
 {
+  // XXXmstange We'd like to register this thread with the profiler, but doing
+  // so causes leaks, see bug 1323100.
   PR_SetCurrentThreadName("Cache2 I/O");
   mozilla::IOInterposer::RegisterCurrentThread();
   CacheIOThread* thread = static_cast<CacheIOThread*>(aClosure);
   thread->ThreadFunc();
   mozilla::IOInterposer::UnregisterCurrentThread();
 }
 
 void CacheIOThread::ThreadFunc()
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -24,16 +24,17 @@
 #include "prerror.h"
 #include "prtime.h"
 #include "mozilla/Logging.h"
 #include "PLDHashTable.h"
 #include "plstr.h"
 #include "nsURLHelper.h"
 #include "nsThreadUtils.h"
 #include "GetAddrInfo.h"
+#include "GeckoProfiler.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/Preferences.h"
 
 using namespace mozilla;
@@ -1430,22 +1431,25 @@ nsHostResolver::SizeOfIncludingThis(Mall
     //   |mDB| is measured.
 
     return n;
 }
 
 void
 nsHostResolver::ThreadFunc(void *arg)
 {
+    char stackTop;
+
     LOG(("DNS lookup thread - starting execution.\n"));
 
     static nsThreadPoolNaming naming;
     nsCString name = naming.GetNextThreadName("DNS Resolver");
 
     PR_SetCurrentThreadName(name.BeginReading());
+    profiler_register_thread(name.BeginReading(), &stackTop);
 
 #if defined(RES_RETRY_ON_FAILURE)
     nsResState rs;
 #endif
     nsHostResolver *resolver = (nsHostResolver *)arg;
     nsHostRecord *rec  = nullptr;
     AddrInfo *ai = nullptr;
 
@@ -1506,16 +1510,18 @@ nsHostResolver::ThreadFunc(void *arg)
                  LOG_HOST(rec->host, rec->netInterface)));
         } else {
             rec = nullptr;
         }
     }
     resolver->mThreadCount--;
     NS_RELEASE(resolver);
     LOG(("DNS lookup thread - queue empty, thread finished.\n"));
+
+    profiler_unregister_thread();
 }
 
 nsresult
 nsHostResolver::Create(uint32_t maxCacheEntries,
                        uint32_t defaultCacheEntryLifetime,
                        uint32_t defaultGracePeriod,
                        nsHostResolver **result)
 {
--- a/security/manager/ssl/nsKeygenThread.cpp
+++ b/security/manager/ssl/nsKeygenThread.cpp
@@ -1,20 +1,23 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  *
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "PSMRunnable.h"
+#include "nsKeygenThread.h"
+
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
+
+#include "GeckoProfiler.h"
+#include "PSMRunnable.h"
 #include "nsCOMPtr.h"
 #include "nsIObserver.h"
-#include "nsKeygenThread.h"
 #include "nsNSSShutDown.h"
 #include "nsThreadUtils.h"
 #include "pk11func.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 NS_IMPL_ISUPPORTS(nsKeygenThread, nsIKeygenThread)
@@ -110,16 +113,17 @@ nsresult nsKeygenThread::ConsumeResult(
       rv = NS_ERROR_FAILURE;
     }
   
   return rv;
 }
 
 static void nsKeygenThreadRunner(void *arg)
 {
+  AutoProfilerRegister registerThread("Keygen");
   PR_SetCurrentThreadName("Keygen");
   nsKeygenThread *self = static_cast<nsKeygenThread *>(arg);
   self->Run();
 }
 
 nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
 {
   if (!NS_IsMainThread()) {
--- a/security/manager/ssl/nsProtectedAuthThread.cpp
+++ b/security/manager/ssl/nsProtectedAuthThread.cpp
@@ -2,29 +2,31 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PSMRunnable.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/RefPtr.h"
 #include "nsCOMPtr.h"
+#include "GeckoProfiler.h"
 #include "nsPKCS11Slot.h"
 #include "nsProtectedAuthThread.h"
 #include "nsReadableUtils.h"
 #include "nsString.h"
 #include "pk11func.h"
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 NS_IMPL_ISUPPORTS(nsProtectedAuthThread, nsIProtectedAuthThread)
 
 static void nsProtectedAuthThreadRunner(void *arg)
 {
+    AutoProfilerRegister registerThread("Protected Auth");
     PR_SetCurrentThreadName("Protected Auth");
 
     nsProtectedAuthThread *self = static_cast<nsProtectedAuthThread *>(arg);
     self->Run();
 }
 
 nsProtectedAuthThread::nsProtectedAuthThread()
 : mMutex("nsProtectedAuthThread.mMutex")
--- a/security/manager/ssl/nsSmartCardMonitor.cpp
+++ b/security/manager/ssl/nsSmartCardMonitor.cpp
@@ -5,16 +5,17 @@
 #include "nsSmartCardMonitor.h"
 
 #include "ScopedNSSTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/Unused.h"
 #include "nsIObserverService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
+#include "GeckoProfiler.h"
 #include "nspr.h"
 #include "pk11func.h"
 
 using namespace mozilla;
 
 //
 // The SmartCard monitoring thread should start up for each module we load
 // that has removable tokens. This code calls an NSS function which waits
@@ -385,12 +386,13 @@ void SmartCardMonitoringThread::Execute(
 const SECMODModule* SmartCardMonitoringThread::GetModule()
 {
   return mModule;
 }
 
 // C-like calling sequence to glue into PR_CreateThread.
 void SmartCardMonitoringThread::LaunchExecute(void* arg)
 {
+  AutoProfilerRegister registerThread("SmartCard");
   PR_SetCurrentThreadName("SmartCard");
 
   ((SmartCardMonitoringThread*)arg)->Execute();
 }
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -31,16 +31,17 @@
 #include "nsWeakReference.h"
 #include "nsZipArchive.h"
 #include "mozilla/Omnijar.h"
 #include "prenv.h"
 #include "mozilla/Telemetry.h"
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
 #include "nsIProtocolHandler.h"
+#include "GeckoProfiler.h"
 
 #ifdef IS_BIG_ENDIAN
 #define SC_ENDIAN "big"
 #else
 #define SC_ENDIAN "little"
 #endif
 
 #if PR_BYTES_PER_WORD == 4
@@ -498,16 +499,17 @@ StartupCache::WaitOnWriteThread()
 
   PR_JoinThread(mWriteThread);
   mWriteThread = nullptr;
 }
 
 void
 StartupCache::ThreadedWrite(void *aClosure)
 {
+  AutoProfilerRegister registerThread("StartupCache");
   PR_SetCurrentThreadName("StartupCache");
   mozilla::IOInterposer::RegisterCurrentThread();
   /*
    * It is safe to use the pointer passed in aClosure to reference the
    * StartupCache object because the thread's lifetime is tightly coupled to
    * the lifetime of the StartupCache object; this thread is joined in the
    * StartupCache destructor, guaranteeing that this function runs if and only
    * if the StartupCache object is valid.
--- a/toolkit/components/terminator/nsTerminator.cpp
+++ b/toolkit/components/terminator/nsTerminator.cpp
@@ -27,16 +27,17 @@
 #include "nsDirectoryServiceUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 
 #include "nsIObserverService.h"
 #include "nsIPrefService.h"
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
 #endif
+#include "GeckoProfiler.h"
 
 #if defined(XP_WIN)
 #include <windows.h>
 #else
 #include <unistd.h>
 #endif
 
 #include "mozilla/ArrayUtils.h"
@@ -209,16 +210,17 @@ public:
 // The data written by the writer thread will be read by another
 // module upon the next restart and fed to Telemetry.
 //
 Atomic<nsCString*> gWriteData(nullptr);
 PRMonitor* gWriteReady = nullptr;
 
 void RunWriter(void* arg)
 {
+  AutoProfilerRegister registerThread("Shutdown Statistics Writer");
   PR_SetCurrentThreadName("Shutdown Statistics Writer");
 
   MOZ_LSAN_INTENTIONALLY_LEAK_OBJECT(arg);
   // Shutdown will generally complete before we have a chance to
   // deallocate. This is not a leak.
 
   // Setup destinationPath and tmpFilePath
 
--- a/toolkit/xre/EventTracer.cpp
+++ b/toolkit/xre/EventTracer.cpp
@@ -117,16 +117,17 @@ class EventLoopLagDispatcher : public Ru
  * it will not send another event until the previous response is received.
  *
  * The output defaults to stdout, but can be redirected to a file by
  * settting the environment variable MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT
  * to the name of a file to use.
  */
 void TracerThread(void *arg)
 {
+  AutoProfilerRegister registerThread("Event Tracer");
   PR_SetCurrentThreadName("Event Tracer");
 
   TracerStartClosure* threadArgs = static_cast<TracerStartClosure*>(arg);
 
   // These are the defaults. They can be overridden by environment vars.
   // This should be set to the maximum latency we'd like to allow
   // for responsiveness.
   int32_t thresholdInterval = threadArgs->mThresholdInterval;
--- a/tools/profiler/public/GeckoProfiler.h
+++ b/tools/profiler/public/GeckoProfiler.h
@@ -243,16 +243,24 @@ static inline void profiler_js_operation
 static inline double profiler_time() { return 0; }
 static inline double profiler_time(const mozilla::TimeStamp& aTime) { return 0; }
 
 static inline bool profiler_in_privacy_mode() { return false; }
 
 static inline void profiler_log(const char *str) {}
 static inline void profiler_log(const char *fmt, va_list args) {}
 
+class AutoProfilerRegister final MOZ_STACK_CLASS
+{
+  AutoProfilerRegister(const char* aName) {}
+private:
+  AutoProfilerRegister(const AutoProfilerRegister&) = delete;
+  AutoProfilerRegister& operator=(const AutoProfilerRegister&) = delete;
+};
+
 #else
 
 #include "GeckoProfilerImpl.h"
 
 #endif
 
 class MOZ_RAII GeckoProfilerInitRAII {
 public:
--- a/tools/profiler/public/GeckoProfilerImpl.h
+++ b/tools/profiler/public/GeckoProfilerImpl.h
@@ -456,16 +456,36 @@ public:
   ~SamplerStackFramePrintfRAII() {
     mozilla_sampler_call_exit(mHandle);
   }
 private:
   char mDest[SAMPLER_MAX_STRING];
   void* mHandle;
 };
 
+/**
+ * Convenience class to register and unregister a thread with the profiler.
+ * Needs to be the first object on the stack of the thread.
+ */
+class MOZ_STACK_CLASS AutoProfilerRegister final
+{
+public:
+  explicit AutoProfilerRegister(const char* aName)
+  {
+    profiler_register_thread(aName, this);
+  }
+  ~AutoProfilerRegister()
+  {
+    profiler_unregister_thread();
+  }
+private:
+  AutoProfilerRegister(const AutoProfilerRegister&) = delete;
+  AutoProfilerRegister& operator=(const AutoProfilerRegister&) = delete;
+};
+
 } // namespace mozilla
 
 inline PseudoStack* mozilla_get_pseudo_stack(void)
 {
   if (!stack_key_initialized)
     return nullptr;
   return tlsPseudoStack.get();
 }
--- a/xpcom/build/MainThreadIOLogger.cpp
+++ b/xpcom/build/MainThreadIOLogger.cpp
@@ -109,16 +109,17 @@ MainThreadIOLoggerImpl::Init()
     return false;
   }
   return true;
 }
 
 /* static */ void
 MainThreadIOLoggerImpl::sIOThreadFunc(void* aArg)
 {
+  AutoProfilerRegister registerThread("MainThreadIOLogger");
   PR_SetCurrentThreadName("MainThreadIOLogger");
   MainThreadIOLoggerImpl* obj = static_cast<MainThreadIOLoggerImpl*>(aArg);
   obj->IOThreadFunc();
 }
 
 void
 MainThreadIOLoggerImpl::IOThreadFunc()
 {
--- a/xpcom/threads/BackgroundHangMonitor.cpp
+++ b/xpcom/threads/BackgroundHangMonitor.cpp
@@ -17,16 +17,17 @@
 
 #include "prinrval.h"
 #include "prthread.h"
 #include "ThreadStackHelper.h"
 #include "nsIObserverService.h"
 #include "nsIObserver.h"
 #include "mozilla/Services.h"
 #include "nsXULAppAPI.h"
+#include "GeckoProfiler.h"
 
 #include <algorithm>
 
 // Activate BHR only for one every BHR_BETA_MOD users.
 // This is now 100% of Beta population for the Beta 45/46 e10s A/B trials
 // It can be scaled back again in the future
 #define BHR_BETA_MOD 1;
 
@@ -49,16 +50,17 @@ namespace mozilla {
  * manages all instances of BackgroundHangThread.
  */
 class BackgroundHangManager : public nsIObserver
 {
 private:
   // Background hang monitor thread function
   static void MonitorThread(void* aData)
   {
+    AutoProfilerRegister registerThread("BgHangMonitor");
     PR_SetCurrentThreadName("BgHangManager");
 
     /* We do not hold a reference to BackgroundHangManager here
        because the monitor thread only exists as long as the
        BackgroundHangManager instance exists. We stop the monitor
        thread in the BackgroundHangManager destructor, and we can
        only get to the destructor if we don't hold a reference here. */
     static_cast<BackgroundHangManager*>(aData)->RunMonitorThread();
--- a/xpcom/threads/HangMonitor.cpp
+++ b/xpcom/threads/HangMonitor.cpp
@@ -16,16 +16,17 @@
 #include "mozilla/UniquePtr.h"
 #include "nsReadableUtils.h"
 #include "mozilla/StackWalk.h"
 #ifdef _WIN64
 #include "mozilla/StackWalk_windows.h"
 #endif
 #include "nsThreadUtils.h"
 #include "nsXULAppAPI.h"
+#include "GeckoProfiler.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
@@ -204,16 +205,17 @@ GetChromeHangReport(Telemetry::Processed
   }
 }
 
 #endif
 
 void
 ThreadMain(void*)
 {
+  AutoProfilerRegister registerThread("Hang Monitor");
   PR_SetCurrentThreadName("Hang Monitor");
 
   MonitorAutoLock lock(*gMonitor);
 
   // In order to avoid issues with the hang monitor incorrectly triggering
   // during a general system stop such as sleeping, the monitor thread must
   // run twice to trigger hang protection.
   PRIntervalTime lastTimestamp = 0;
--- a/xpcom/threads/nsProcessCommon.cpp
+++ b/xpcom/threads/nsProcessCommon.cpp
@@ -20,16 +20,17 @@
 #include "nsProcess.h"
 #include "prio.h"
 #include "prenv.h"
 #include "nsCRT.h"
 #include "nsThreadUtils.h"
 #include "nsIObserverService.h"
 #include "nsXULAppAPI.h"
 #include "mozilla/Services.h"
+#include "GeckoProfiler.h"
 
 #include <stdlib.h>
 
 #if defined(PROCESSMODEL_WINAPI)
 #include "prmem.h"
 #include "nsString.h"
 #include "nsLiteralString.h"
 #include "nsReadableUtils.h"
@@ -230,20 +231,23 @@ assembleCmdLine(char* const* aArgv, wcha
   PR_Free(cmdLine);
   return 0;
 }
 #endif
 
 void
 nsProcess::Monitor(void* aArg)
 {
+  char stackBaseGuess;
+
   RefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(aArg));
 
   if (!process->mBlocking) {
     PR_SetCurrentThreadName("RunProcess");
+    profiler_register_thread("RunProcess", &stackBaseGuess);
   }
 
 #if defined(PROCESSMODEL_WINAPI)
   DWORD dwRetVal;
   unsigned long exitCode = -1;
 
   dwRetVal = WaitForSingleObject(process->mProcess, INFINITE);
   if (dwRetVal != WAIT_FAILED) {
@@ -299,16 +303,20 @@ nsProcess::Monitor(void* aArg)
 
   // If we ran a background thread for the monitor then notify on the main
   // thread
   if (NS_IsMainThread()) {
     process->ProcessComplete();
   } else {
     NS_DispatchToMainThread(NewRunnableMethod(process, &nsProcess::ProcessComplete));
   }
+
+  if (!process->mBlocking) {
+    profiler_unregister_thread();
+  }
 }
 
 void
 nsProcess::ProcessComplete()
 {
   if (mThread) {
     nsCOMPtr<nsIObserverService> os =
       mozilla::services::GetObserverService();