Bug 720778 - Important threads should have a name for better debugability, r=bsmith, sr=bsmedberg+glandium
authorHonza Bambas <honzab.moz@firemni.cz>
Tue, 12 Jun 2012 19:06:20 +0200
changeset 98046 772d9d20cdf913568c154a6387d784a3c36dc622
parent 98045 dbf0598205cecbb35485f423c88595b1a34918a8
child 98047 22796d93c42e7b8b872adfee86af3945816aac2e
push idunknown
push userunknown
push dateunknown
reviewersbsmith, bsmedberg
bugs720778
milestone16.0a1
Bug 720778 - Important threads should have a name for better debugability, r=bsmith, sr=bsmedberg+glandium
content/media/nsAudioStream.cpp
content/media/nsBuiltinDecoderStateMachine.cpp
dom/bluetooth/BluetoothManager.cpp
dom/indexedDB/IndexedDatabaseManager.cpp
dom/indexedDB/TransactionThreadPool.cpp
dom/plugins/base/android/ANPAudio.cpp
dom/workers/RuntimeService.cpp
js/src/jsgc.cpp
js/src/shell/js.cpp
js/src/shell/jsworkers.cpp
js/xpconnect/src/XPCJSRuntime.cpp
netwerk/base/src/nsIOThreadPool.cpp
netwerk/base/src/nsSocketTransportService2.cpp
netwerk/base/src/nsStreamTransportService.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsDeleteDir.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/system/win32/nsNotifyAddrListener.cpp
netwerk/wifi/nsWifiMonitor.cpp
parser/html/nsHtml5Module.cpp
security/manager/ssl/src/SSLServerCertVerification.cpp
security/manager/ssl/src/nsKeygenThread.cpp
security/manager/ssl/src/nsNSSComponent.cpp
security/manager/ssl/src/nsPSMBackgroundThread.cpp
security/manager/ssl/src/nsPSMBackgroundThread.h
security/manager/ssl/src/nsProtectedAuthThread.cpp
security/manager/ssl/src/nsSmartCardMonitor.cpp
startupcache/StartupCache.cpp
storage/src/mozStorageConnection.cpp
toolkit/components/startup/nsAppStartup.cpp
toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
toolkit/xre/EventTracer.cpp
widget/windows/JumpListBuilder.cpp
widget/windows/LSPAnnotator.cpp
widget/windows/nsSound.cpp
xpcom/base/nsCycleCollector.cpp
xpcom/build/nsXPComInit.cpp
xpcom/glue/nsThreadUtils.cpp
xpcom/glue/nsThreadUtils.h
xpcom/threads/HangMonitor.cpp
xpcom/threads/LazyIdleThread.cpp
xpcom/threads/LazyIdleThread.h
xpcom/threads/TimerThread.cpp
xpcom/threads/nsIThreadPool.idl
xpcom/threads/nsProcessCommon.cpp
xpcom/threads/nsThreadPool.cpp
xpcom/threads/nsThreadPool.h
--- a/content/media/nsAudioStream.cpp
+++ b/content/media/nsAudioStream.cpp
@@ -378,19 +378,20 @@ void nsAudioStream::ShutdownLibrary()
   }
 #endif
 }
 
 nsIThread *
 nsAudioStream::GetThread()
 {
   if (!mAudioPlaybackThread) {
-    NS_NewThread(getter_AddRefs(mAudioPlaybackThread),
-                 nsnull,
-                 MEDIA_THREAD_STACK_SIZE);
+    NS_NewNamedThread("Audio Stream",
+                      getter_AddRefs(mAudioPlaybackThread),
+                      nsnull,
+                      MEDIA_THREAD_STACK_SIZE);
   }
   return mAudioPlaybackThread;
 }
 
 class AsyncShutdownPlaybackThread : public nsRunnable
 {
 public:
   AsyncShutdownPlaybackThread(nsIThread* aThread) : mThread(aThread) {}
--- a/content/media/nsBuiltinDecoderStateMachine.cpp
+++ b/content/media/nsBuiltinDecoderStateMachine.cpp
@@ -259,17 +259,17 @@ StateMachineTracker& StateMachineTracker
 }
 
 void StateMachineTracker::EnsureGlobalStateMachine() 
 {
   NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
   ReentrantMonitorAutoEnter mon(mMonitor);
   if (mStateMachineCount == 0) {
     NS_ASSERTION(!mStateMachineThread, "Should have null state machine thread!");
-    DebugOnly<nsresult> rv = NS_NewThread(&mStateMachineThread, nsnull);
+    DebugOnly<nsresult> rv = NS_NewNamedThread("Media State", &mStateMachineThread, nsnull);
     NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Can't create media state machine thread");
   }
   mStateMachineCount++;
 }
 
 #ifdef DEBUG
 bool StateMachineTracker::IsQueued(nsBuiltinDecoderStateMachine* aStateMachine)
 {
@@ -1612,19 +1612,20 @@ nsBuiltinDecoderStateMachine::StartDecod
   NS_ASSERTION(!StateMachineTracker::Instance().IsQueued(this),
     "Should not already have a pending request for a new decode thread.");
   NS_ASSERTION(OnStateMachineThread(), "Should be on state machine thread.");
   NS_ASSERTION(!mDecodeThread, "Should not have decode thread yet");
   NS_ASSERTION(mRequestedNewDecodeThread, "Should have requested this...");
 
   mRequestedNewDecodeThread = false;
 
-  nsresult rv = NS_NewThread(getter_AddRefs(mDecodeThread),
-                              nsnull,
-                              MEDIA_THREAD_STACK_SIZE);
+  nsresult rv = NS_NewNamedThread("Media Decode",
+                                  getter_AddRefs(mDecodeThread),
+                                  nsnull,
+                                  MEDIA_THREAD_STACK_SIZE);
   if (NS_FAILED(rv)) {
     // Give up, report error to media element.
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(mDecoder, &nsBuiltinDecoder::DecodeError);
     NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
     return rv;
   }
 
@@ -1639,24 +1640,26 @@ nsBuiltinDecoderStateMachine::StartDecod
 nsresult
 nsBuiltinDecoderStateMachine::StartAudioThread()
 {
   NS_ASSERTION(OnStateMachineThread() || OnDecodeThread(),
                "Should be on state machine or decode thread.");
   mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
   mStopAudioThread = false;
   if (HasAudio() && !mAudioThread && !mAudioCaptured) {
-    nsresult rv = NS_NewThread(getter_AddRefs(mAudioThread),
-                               nsnull,
-                               MEDIA_THREAD_STACK_SIZE);
+    nsresult rv = NS_NewNamedThread("Media Audio",
+                                    getter_AddRefs(mAudioThread),
+                                    nsnull,
+                                    MEDIA_THREAD_STACK_SIZE);
     if (NS_FAILED(rv)) {
       LOG(PR_LOG_DEBUG, ("%p Changed state to SHUTDOWN because failed to create audio thread", mDecoder.get()));
       mState = DECODER_STATE_SHUTDOWN;
       return rv;
     }
+
     nsCOMPtr<nsIRunnable> event =
       NS_NewRunnableMethod(this, &nsBuiltinDecoderStateMachine::AudioLoop);
     mAudioThread->Dispatch(event, NS_DISPATCH_NORMAL);
   }
   return NS_OK;
 }
 
 PRInt64 nsBuiltinDecoderStateMachine::AudioDecodedUsecs() const
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -205,17 +205,17 @@ BluetoothManager::SetEnabled(bool aEnabl
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDOMDOMRequest> request;
   nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (!mToggleBtThread) {
-    mToggleBtThread = new LazyIdleThread(15000);
+    mToggleBtThread = new LazyIdleThread(15000, NS_LITERAL_CSTRING("Bluetooth"));
   }
 
   nsCOMPtr<nsIRunnable> r = new ToggleBtTask(aEnabled, request, this);
 
   rv = mToggleBtThread->Dispatch(r, NS_DISPATCH_NORMAL);
   NS_ENSURE_SUCCESS(rv, rv);
 
   request.forget(aDomRequest);
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -221,17 +221,18 @@ IndexedDatabaseManager::GetOrCreate()
       NS_ENSURE_SUCCESS(rv, nsnull);
 
       rv = dbBaseDirectory->GetPath(instance->mDatabaseBasePath);
       NS_ENSURE_SUCCESS(rv, nsnull);
 
       // Make a lazy thread for any IO we need (like clearing or enumerating the
       // contents of indexedDB database directories).
       instance->mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
-                                                LazyIdleThread::ManualShutdown);
+                                               NS_LITERAL_CSTRING("IndexedDB I/O"),
+                                               LazyIdleThread::ManualShutdown);
 
       // We need one quota callback object to hand to SQLite.
       instance->mQuotaCallbackSingleton = new QuotaCallback();
 
       // Make a timer here to avoid potential failures later. We don't actually
       // initialize the timer until shutdown.
       instance->mShutdownTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
       NS_ENSURE_TRUE(instance->mShutdownTimer, nsnull);
--- a/dom/indexedDB/TransactionThreadPool.cpp
+++ b/dom/indexedDB/TransactionThreadPool.cpp
@@ -132,16 +132,19 @@ TransactionThreadPool::Init()
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mTransactionsInProgress.Init();
 
   nsresult rv;
   mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
+  rv = mThreadPool->SetName(NS_LITERAL_CSTRING("IndexedDB Trans"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
   rv = mThreadPool->SetThreadLimit(kThreadLimit);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mThreadPool->SetIdleThreadLimit(kIdleThreadLimit);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mThreadPool->SetIdleThreadTimeout(kIdleThreadTimeoutMs);
   NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/plugins/base/android/ANPAudio.cpp
+++ b/dom/plugins/base/android/ANPAudio.cpp
@@ -112,16 +112,18 @@ public:
   }
 
   ANPAudioTrack* mTrack;
 };
 
 NS_IMETHODIMP
 AudioRunnable::Run()
 {
+  PR_SetCurrentThreadName("Android Audio");
+
   JNIEnv* jenv = GetJNIForThread();
   if (!jenv)
     return NS_ERROR_FAILURE;
 
   mozilla::AutoLocalJNIFrame autoFrame(jenv, 2);
 
   jbyteArray bytearray = jenv->NewByteArray(mTrack->bufferSize);
   if (!bytearray) {
--- a/dom/workers/RuntimeService.cpp
+++ b/dom/workers/RuntimeService.cpp
@@ -776,18 +776,19 @@ RuntimeService::ScheduleWorker(JSContext
     if (!mIdleThreadArray.IsEmpty()) {
       PRUint32 index = mIdleThreadArray.Length() - 1;
       mIdleThreadArray[index].mThread.swap(thread);
       mIdleThreadArray.RemoveElementAt(index);
     }
   }
 
   if (!thread) {
-    if (NS_FAILED(NS_NewThread(getter_AddRefs(thread), nsnull,
-                               WORKER_STACK_SIZE))) {
+    if (NS_FAILED(NS_NewNamedThread("DOM Worker",
+                                    getter_AddRefs(thread), nsnull,
+                                    WORKER_STACK_SIZE))) {
       UnregisterWorker(aCx, aWorkerPrivate);
       JS_ReportError(aCx, "Could not create new thread!");
       return false;
     }
 
     nsCOMPtr<nsISupportsPriority> priority = do_QueryInterface(thread);
     if (!priority ||
         NS_FAILED(priority->SetPriority(nsISupportsPriority::PRIORITY_LOW))) {
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2686,16 +2686,17 @@ GCHelperThread::finish()
     if (done)
         PR_DestroyCondVar(done);
 }
 
 /* static */
 void
 GCHelperThread::threadMain(void *arg)
 {
+    PR_SetCurrentThreadName("JS GC Helper");
     static_cast<GCHelperThread *>(arg)->threadLoop();
 }
 
 void
 GCHelperThread::threadLoop()
 {
     AutoLockGC lock(rt);
 
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2922,16 +2922,18 @@ KillWatchdog()
     PR_DestroyCondVar(gSleepWakeup);
     PR_DestroyCondVar(gWatchdogWakeup);
     PR_DestroyLock(gWatchdogLock);
 }
 
 static void
 WatchdogMain(void *arg)
 {
+    PR_SetCurrentThreadName("JS Watchdog");
+
     JSRuntime *rt = (JSRuntime *) arg;
 
     PR_Lock(gWatchdogLock);
     while (gWatchdogThread) {
         PRIntervalTime now = PR_IntervalNow();
          if (gWatchdogHasTimeout && !IsBefore(now, gWatchdogTimeout)) {
             /*
              * The timeout has just expired. Trigger the operation callback
--- a/js/src/shell/jsworkers.cpp
+++ b/js/src/shell/jsworkers.cpp
@@ -429,16 +429,17 @@ class ThreadPool
     MainQueue *mq;
     WorkerQueue *wq;
     PRThread *threads[threadCount];
     int32_t terminating;
 
     static JSClass jsClass;
 
     static void start(void* arg) {
+        PR_SetCurrentThreadName("JS Worker");
         ((WorkerQueue *) arg)->work();
     }
 
     explicit ThreadPool(WorkerHooks *hooks) : hooks(hooks), mq(NULL), wq(NULL), terminating(0) {
         for (int i = 0; i < threadCount; i++)
             threads[i] = NULL;
     }
 
--- a/js/xpconnect/src/XPCJSRuntime.cpp
+++ b/js/xpconnect/src/XPCJSRuntime.cpp
@@ -880,16 +880,18 @@ class AutoLockWatchdog {
         PR_Unlock(mRuntime->mWatchdogLock);
     }
 };
 
 //static
 void
 XPCJSRuntime::WatchdogMain(void *arg)
 {
+    PR_SetCurrentThreadName("JS Watchdog");
+
     XPCJSRuntime* self = static_cast<XPCJSRuntime*>(arg);
 
     // Lock lasts until we return
     AutoLockWatchdog lock(self);
 
     PRIntervalTime sleepInterval;
     while (self->mWatchdogThread) {
         // Sleep only 1 second if recently (or currently) active; otherwise, hibernate
--- a/netwerk/base/src/nsIOThreadPool.cpp
+++ b/netwerk/base/src/nsIOThreadPool.cpp
@@ -58,16 +58,17 @@ private:
     // mLock protects all (exceptions during Init and Shutdown)
     PRLock    *mLock;
     PRCondVar *mIdleThreadCV;   // notified to wake up an idle thread
     PRCondVar *mExitThreadCV;   // notified when a thread exits
     PRUint32   mNumThreads;     // number of active + idle threads
     PRUint32   mNumIdleThreads; // number of idle threads
     PRCList    mEventQ;         // queue of PLEvent structs
     bool       mShutdown;       // set to true if shutting down
+    nsThreadPoolNaming mNaming; // thread name numbering
 };
 
 NS_IMPL_THREADSAFE_ISUPPORTS2(nsIOThreadPool, nsIEventTarget, nsIObserver)
 
 nsresult
 nsIOThreadPool::Init()
 {
 #if defined(PR_LOGGING)
@@ -197,16 +198,18 @@ nsIOThreadPool::Observe(nsISupports *, c
     return NS_OK;
 }
 
 void
 nsIOThreadPool::ThreadFunc(void *arg)
 {
     nsIOThreadPool *pool = (nsIOThreadPool *) arg;
 
+    pool->mNaming.SetThreadPoolName("IO Thread");
+
     LOG(("entering ThreadFunc\n"));
 
     {
         nsAutoLock lock(pool->mLock);
 
         for (;;) {
             PRIntervalTime start = PR_IntervalNow(), timeout = IDLE_TIMEOUT;
             //
--- a/netwerk/base/src/nsSocketTransportService2.cpp
+++ b/netwerk/base/src/nsSocketTransportService2.cpp
@@ -577,16 +577,18 @@ nsSocketTransportService::AfterProcessNe
                                                 PRUint32 depth)
 {
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsSocketTransportService::Run()
 {
+    PR_SetCurrentThreadName("Socket Thread");
+
     SOCKET_LOG(("STS thread init\n"));
 
     psm::InitializeSSLServerCertVerificationThreads();
 
     gSocketThread = PR_GetCurrentThread();
 
     // add thread event to poll list (mThreadEvent may be NULL)
     mPollList[0].fd = mThreadEvent;
--- a/netwerk/base/src/nsStreamTransportService.cpp
+++ b/netwerk/base/src/nsStreamTransportService.cpp
@@ -438,16 +438,17 @@ nsStreamTransportService::Init()
 {
     mPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
     NS_ENSURE_STATE(mPool);
 
     // Configure the pool
     mPool->SetThreadLimit(4);
     mPool->SetIdleThreadLimit(1);
     mPool->SetIdleThreadTimeout(PR_SecondsToInterval(60));
+    mPool->SetName(NS_LITERAL_CSTRING("StreamTrans"));
 
     nsCOMPtr<nsIObserverService> obsSvc =
         mozilla::services::GetObserverService();
     if (obsSvc)
         obsSvc->AddObserver(this, "xpcom-shutdown-threads", false);
     return NS_OK;
 }
 
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -1111,17 +1111,18 @@ nsCacheService::Init()
         return NS_ERROR_ALREADY_INITIALIZED;
 
     if (mozilla::net::IsNeckoChild()) {
         return NS_ERROR_UNEXPECTED;
     }
 
     CACHE_LOG_INIT();
 
-    nsresult rv = NS_NewThread(getter_AddRefs(mCacheIOThread));
+    nsresult rv = NS_NewNamedThread("Cache I/O",
+                                    getter_AddRefs(mCacheIOThread));
     if (NS_FAILED(rv)) {
         NS_RUNTIMEABORT("Can't create cache IO thread");
     }
 
     rv = nsDeleteDir::Init();
     if (NS_FAILED(rv)) {
         NS_WARNING("Can't initialize nsDeleteDir");
     }
--- a/netwerk/cache/nsDeleteDir.cpp
+++ b/netwerk/cache/nsDeleteDir.cpp
@@ -127,17 +127,17 @@ nsDeleteDir::Shutdown(bool finishDeletin
 }
 
 nsresult
 nsDeleteDir::InitThread()
 {
   if (mThread)
     return NS_OK;
 
-  nsresult rv = NS_NewThread(getter_AddRefs(mThread));
+  nsresult rv = NS_NewNamedThread("Cache Deleter", getter_AddRefs(mThread));
   if (NS_FAILED(rv)) {
     NS_WARNING("Can't create background thread");
     return rv;
   }
 
   nsCOMPtr<nsISupportsPriority> p = do_QueryInterface(mThread);
   if (p) {
     p->SetPriority(nsISupportsPriority::PRIORITY_LOWEST);
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -26,16 +26,17 @@
 #include "prthread.h"
 #include "prerror.h"
 #include "prtime.h"
 #include "prlong.h"
 #include "prlog.h"
 #include "pldhash.h"
 #include "plstr.h"
 #include "nsURLHelper.h"
+#include "nsThreadUtils.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 
@@ -948,16 +949,20 @@ nsHostResolver::CancelAsyncRequest(const
 }
 
 //----------------------------------------------------------------------------
 
 void
 nsHostResolver::ThreadFunc(void *arg)
 {
     LOG(("nsHostResolver::ThreadFunc entering\n"));
+
+    static nsThreadPoolNaming naming;
+    naming.SetThreadPoolName(NS_LITERAL_CSTRING("DNS Resolver"));
+
 #if defined(RES_RETRY_ON_FAILURE)
     nsResState rs;
 #endif
     nsHostResolver *resolver = (nsHostResolver *)arg;
     nsHostRecord *rec;
     PRAddrInfo *ai;
     while (resolver->GetHostToLookup(&rec)) {
         LOG(("resolving %s ...\n", rec->host));
--- a/netwerk/system/win32/nsNotifyAddrListener.cpp
+++ b/netwerk/system/win32/nsNotifyAddrListener.cpp
@@ -98,16 +98,18 @@ nsNotifyAddrListener::GetLinkType(PRUint
   // XXX This function has not yet been implemented for this platform
   *aLinkType = nsINetworkLinkService::LINK_TYPE_UNKNOWN;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsNotifyAddrListener::Run()
 {
+    PR_SetCurrentThreadName("Link Monitor");
+
     HANDLE ev = CreateEvent(nsnull, FALSE, FALSE, nsnull);
     NS_ENSURE_TRUE(ev, NS_ERROR_OUT_OF_MEMORY);
 
     HANDLE handles[2] = { ev, mShutdownEvent };
     OVERLAPPED overlapped = { 0 };
     bool shuttingDown = false;
 
     overlapped.hEvent = ev;
--- a/netwerk/wifi/nsWifiMonitor.cpp
+++ b/netwerk/wifi/nsWifiMonitor.cpp
@@ -139,16 +139,18 @@ NS_IMETHODIMP nsPassErrorToWifiListeners
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP nsWifiMonitor::Run()
 {
   LOG(("@@@@@ wifi monitor run called\n"));
 
+  PR_SetCurrentThreadName("Wifi Monitor");
+
   nsresult rv = DoScan();
 
   if (mKeepGoing && NS_FAILED(rv)) {
     nsAutoPtr<nsCOMArray<nsIWifiListener> > currentListeners(
                            new nsCOMArray<nsIWifiListener>(mListeners.Length()));
     if (!currentListeners)
       return NS_ERROR_OUT_OF_MEMORY;
 
--- a/parser/html/nsHtml5Module.cpp
+++ b/parser/html/nsHtml5Module.cpp
@@ -109,17 +109,17 @@ class nsHtml5ParserThreadTerminator : pu
 NS_IMPL_ISUPPORTS1(nsHtml5ParserThreadTerminator, nsIObserver)
 
 // static 
 nsIThread*
 nsHtml5Module::GetStreamParserThread()
 {
   if (sOffMainThread) {
     if (!sStreamParserThread) {
-      NS_NewThread(&sStreamParserThread);
+      NS_NewNamedThread("HTML5 Parser", &sStreamParserThread);
       NS_ASSERTION(sStreamParserThread, "Thread creation failed!");
       nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
       NS_ASSERTION(os, "do_GetService failed");
       os->AddObserver(new nsHtml5ParserThreadTerminator(sStreamParserThread), 
                       "xpcom-shutdown-threads",
                       false);
     }
     return sStreamParserThread;
--- a/security/manager/ssl/src/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/src/SSLServerCertVerification.cpp
@@ -153,16 +153,17 @@ InitializeSSLServerCertVerificationThrea
   if (NS_FAILED(rv)) {
     NS_WARNING("Failed to create SSL cert verification threads.");
     return;
   }
 
   (void) gCertVerificationThreadPool->SetIdleThreadLimit(5);
   (void) gCertVerificationThreadPool->SetIdleThreadTimeout(30 * 1000);
   (void) gCertVerificationThreadPool->SetThreadLimit(5);
+  (void) gCertVerificationThreadPool->SetName(NS_LITERAL_CSTRING("SSL Cert"));
 }
 
 // Called when the socket transport thread finishes, to destroy the thread
 // pool. Since the socket transport service has stopped processing events, it
 // will not attempt any more SSL I/O operations, so it is clearly safe to shut
 // down the SSL cert verification infrastructure. Also, the STS will not
 // dispatch many SSL verification result events at this point, so any pending
 // cert verifications will (correctly) fail at the point they are dispatched.
--- a/security/manager/ssl/src/nsKeygenThread.cpp
+++ b/security/manager/ssl/src/nsKeygenThread.cpp
@@ -108,16 +108,17 @@ nsresult nsKeygenThread::ConsumeResult(
       rv = NS_ERROR_FAILURE;
     }
   
   return rv;
 }
 
 static void PR_CALLBACK nsKeygenThreadRunner(void *arg)
 {
+  PR_SetCurrentThreadName("Keygen");
   nsKeygenThread *self = static_cast<nsKeygenThread *>(arg);
   self->Run();
 }
 
 nsresult nsKeygenThread::StartKeyGeneration(nsIObserver* aObserver)
 {
   if (!NS_IsMainThread()) {
     NS_ERROR("nsKeygenThread::StartKeyGeneration called off the main thread");
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -360,17 +360,19 @@ nsNSSComponent::deleteBackgroundThreads(
 
 void
 nsNSSComponent::createBackgroundThreads()
 {
   NS_ASSERTION(mCertVerificationThread == nsnull,
                "Cert verification thread already created.");
 
   mCertVerificationThread = new nsCertVerificationThread;
-  nsresult rv = mCertVerificationThread->startThread();
+  nsresult rv = mCertVerificationThread->startThread(
+    NS_LITERAL_CSTRING("Cert Verify"));
+
   if (NS_FAILED(rv)) {
     delete mCertVerificationThread;
     mCertVerificationThread = nsnull;
   }
 }
 
 nsNSSComponent::~nsNSSComponent()
 {
--- a/security/manager/ssl/src/nsPSMBackgroundThread.cpp
+++ b/security/manager/ssl/src/nsPSMBackgroundThread.cpp
@@ -5,29 +5,32 @@
 #include "nsPSMBackgroundThread.h"
 #include "nsThreadUtils.h"
 
 using namespace mozilla;
 
 void PR_CALLBACK nsPSMBackgroundThread::nsThreadRunner(void *arg)
 {
   nsPSMBackgroundThread *self = static_cast<nsPSMBackgroundThread *>(arg);
+  PR_SetCurrentThreadName(self->mName.BeginReading());
   self->Run();
 }
 
 nsPSMBackgroundThread::nsPSMBackgroundThread()
 : mThreadHandle(nsnull),
   mMutex("nsPSMBackgroundThread.mMutex"),
   mCond(mMutex, "nsPSMBackgroundThread.mCond"),
   mExitState(ePSMThreadRunning)
 {
 }
 
-nsresult nsPSMBackgroundThread::startThread()
+nsresult nsPSMBackgroundThread::startThread(const nsCSubstring & name)
 {
+  mName = name;
+
   mThreadHandle = PR_CreateThread(PR_USER_THREAD, nsThreadRunner, static_cast<void*>(this), 
     PR_PRIORITY_NORMAL, PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
 
   NS_ASSERTION(mThreadHandle, "Could not create nsPSMBackgroundThread\n");
   
   if (!mThreadHandle)
     return NS_ERROR_OUT_OF_MEMORY;
 
--- a/security/manager/ssl/src/nsPSMBackgroundThread.h
+++ b/security/manager/ssl/src/nsPSMBackgroundThread.h
@@ -36,18 +36,21 @@ protected:
 
 private:
   enum {
     ePSMThreadRunning = 0,
     ePSMThreadStopRequested = 1,
     ePSMThreadStopped = 2
   } mExitState;
 
+  // The thread's name.
+  nsCString mName;
+
 public:
   nsPSMBackgroundThread();
   virtual ~nsPSMBackgroundThread();
 
-  nsresult startThread();
+  nsresult startThread(const nsCSubstring & name);
   void requestExit();
 };
 
 
 #endif
--- a/security/manager/ssl/src/nsProtectedAuthThread.cpp
+++ b/security/manager/ssl/src/nsProtectedAuthThread.cpp
@@ -13,16 +13,18 @@
 
 using namespace mozilla;
 using namespace mozilla::psm;
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsProtectedAuthThread, nsIProtectedAuthThread)
 
 static void PR_CALLBACK nsProtectedAuthThreadRunner(void *arg)
 {
+    PR_SetCurrentThreadName("Protected Auth");
+
     nsProtectedAuthThread *self = static_cast<nsProtectedAuthThread *>(arg);
     self->Run();
 }
 
 nsProtectedAuthThread::nsProtectedAuthThread()
 : mMutex("nsProtectedAuthThread.mMutex")
 , mIAmRunning(false)
 , mLoginReady(false)
--- a/security/manager/ssl/src/nsSmartCardMonitor.cpp
+++ b/security/manager/ssl/src/nsSmartCardMonitor.cpp
@@ -320,11 +320,13 @@ void SmartCardMonitoringThread::Execute(
 const SECMODModule * SmartCardMonitoringThread::GetModule() 
 {
   return mModule;
 }
 
 // C-like calling sequence to glue into PR_CreateThread.
 void SmartCardMonitoringThread::LaunchExecute(void *arg)
 {
+  PR_SetCurrentThreadName("SmartCard");
+
   ((SmartCardMonitoringThread*)arg)->Execute();
 }
 
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -488,16 +488,17 @@ StartupCache::WaitOnWriteThread()
   NS_TIME_FUNCTION_MIN(30);
   PR_JoinThread(mWriteThread);
   mWriteThread = NULL;
 }
 
 void 
 StartupCache::ThreadedWrite(void *aClosure)
 {
+  PR_SetCurrentThreadName("StartupCache");
   gStartupCache->WriteToDisk();
 }
 
 /*
  * The write-thread is spawned on a timeout(which is reset with every write). This
  * can avoid a slow shutdown. After writing out the cache, the zipreader is
  * reloaded on the worker thread.
  */
--- a/storage/src/mozStorageConnection.cpp
+++ b/storage/src/mozStorageConnection.cpp
@@ -556,16 +556,19 @@ Connection::getAsyncExecutionTarget()
     return nsnull;
 
   if (!mAsyncExecutionThread) {
     nsresult rv = ::NS_NewThread(getter_AddRefs(mAsyncExecutionThread));
     if (NS_FAILED(rv)) {
       NS_WARNING("Failed to create async thread.");
       return nsnull;
     }
+    static nsThreadPoolNaming naming;
+    naming.SetThreadPoolName(NS_LITERAL_CSTRING("mozStorage"),
+                             mAsyncExecutionThread);
   }
 
   return mAsyncExecutionThread;
 }
 
 nsresult
 Connection::initialize(nsIFile *aDatabaseFile,
                        const char* aVFSName)
--- a/toolkit/components/startup/nsAppStartup.cpp
+++ b/toolkit/components/startup/nsAppStartup.cpp
@@ -704,16 +704,18 @@ JiffiesSinceBoot(const char *file)
   if (ret != 1 || !starttime)
     return 0;
   return starttime;
 }
 
 static void
 ThreadedCalculateProcessCreationTimestamp(void *aClosure)
 {
+  PR_SetCurrentThreadName("Startup Timer");
+
   PRTime now = PR_Now();
   long hz = sysconf(_SC_CLK_TCK);
   if (!hz)
     return;
 
   char thread_stat[40];
   sprintf(thread_stat, "/proc/self/task/%d/stat", (pid_t) syscall(__NR_gettid));
   
--- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
+++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp
@@ -4199,17 +4199,17 @@ nsUrlClassifierDBService::Init()
                   NS_SUCCEEDED(rv) ? tmpint : UPDATE_WORKING_TIME_DEFAULT);
 
     rv = prefs->GetIntPref(UPDATE_DELAY_TIME, &tmpint);
     PR_ATOMIC_SET(&gDelayTime,
                   NS_SUCCEEDED(rv) ? tmpint : UPDATE_DELAY_TIME_DEFAULT);
   }
 
   // Start the background thread.
-  rv = NS_NewThread(&gDbBackgroundThread);
+  rv = NS_NewNamedThread("URL Classifier", &gDbBackgroundThread);
   if (NS_FAILED(rv))
     return rv;
 
   mWorker = new nsUrlClassifierDBServiceWorker();
   if (!mWorker)
     return NS_ERROR_OUT_OF_MEMORY;
 
   rv = mWorker->Init(gethashNoise, mPrefixSet);
--- a/toolkit/xre/EventTracer.cpp
+++ b/toolkit/xre/EventTracer.cpp
@@ -78,16 +78,18 @@ bool sExit = false;
  * 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)
 {
+  PR_SetCurrentThreadName("Event Tracer");
+
   // 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.
   PRIntervalTime threshold = PR_MillisecondsToInterval(20);
   // This is the sampling interval.
   PRIntervalTime interval = PR_MillisecondsToInterval(10);
 
   sExit = false;
--- a/widget/windows/JumpListBuilder.cpp
+++ b/widget/windows/JumpListBuilder.cpp
@@ -51,17 +51,19 @@ JumpListBuilder::JumpListBuilder() :
   mHasCommit(false)
 {
   ::CoInitialize(NULL);
   
   CoCreateInstance(CLSID_DestinationList, NULL, CLSCTX_INPROC_SERVER,
                    IID_ICustomDestinationList, getter_AddRefs(mJumpListMgr));
 
   // Make a lazy thread for any IO
-  mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS, LazyIdleThread::ManualShutdown);
+  mIOThread = new LazyIdleThread(DEFAULT_THREAD_TIMEOUT_MS,
+                                 NS_LITERAL_CSTRING("Jump List"),
+                                 LazyIdleThread::ManualShutdown);
   Preferences::AddStrongObserver(this, kPrefTaskbarEnabled);
 }
 
 JumpListBuilder::~JumpListBuilder()
 {
   mIOThread->Shutdown();
   Preferences::RemoveObserver(this, kPrefTaskbarEnabled);
   mJumpListMgr = nsnull;
--- a/widget/windows/LSPAnnotator.cpp
+++ b/widget/windows/LSPAnnotator.cpp
@@ -44,16 +44,18 @@ LSPAnnotationGatherer::Annotate()
     cr->AnnotateCrashReport(NS_LITERAL_CSTRING("Winsock_LSP"), mString);
   }
   mThread->Shutdown();
 }
 
 NS_IMETHODIMP
 LSPAnnotationGatherer::Run()
 {
+  PR_SetCurrentThreadName("LSP Annotator");
+
   mThread = NS_GetCurrentThread();
 
   DWORD size = 0;
   int err;
   // Get the size of the buffer we need
   if (SOCKET_ERROR != WSCEnumProtocols(NULL, NULL, &size, &err) ||
       err != WSAENOBUFS) {
     // Er, what?
--- a/widget/windows/nsSound.cpp
+++ b/widget/windows/nsSound.cpp
@@ -69,16 +69,18 @@ protected:
   protected:
     nsSound *mSound;
   };
 };
 
 NS_IMETHODIMP
 nsSoundPlayer::Run()
 {
+  PR_SetCurrentThreadName("Play Sound");
+
   NS_PRECONDITION(!mSoundName.IsEmpty(), "Sound name should not be empty");
   ::PlaySoundW(mSoundName.get(), NULL, SND_NODEFAULT | SND_ALIAS | SND_ASYNC);
   nsCOMPtr<nsIRunnable> releaser = new SoundReleaser(mSound);
   // Don't release nsSound from here, because here is not an owning thread of
   // the nsSound. nsSound must be released in its owning thread.
   mThread->Dispatch(releaser, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
--- a/xpcom/base/nsCycleCollector.cpp
+++ b/xpcom/base/nsCycleCollector.cpp
@@ -3013,16 +3013,18 @@ class nsCycleCollectorRunner : public ns
     CondVar mReply;
     bool mRunning;
     bool mShutdown;
     bool mCollected;
 
 public:
     NS_IMETHOD Run()
     {
+        PR_SetCurrentThreadName("XPCOM CC");
+
 #ifdef XP_WIN
         TlsSetValue(gTLSThreadIDIndex,
                     (void*) mozilla::threads::CycleCollector);
 #elif defined(NS_TLS)
         gTLSThreadID = mozilla::threads::CycleCollector;
 #else
         gCycleCollectorThread = PR_GetCurrentThread();
 #endif
--- a/xpcom/build/nsXPComInit.cpp
+++ b/xpcom/build/nsXPComInit.cpp
@@ -307,16 +307,18 @@ NS_InitXPCOM(nsIServiceManager* *result,
 
 EXPORT_XPCOM_API(nsresult)
 NS_InitXPCOM2(nsIServiceManager* *result,
               nsIFile* binDirectory,
               nsIDirectoryServiceProvider* appFileLocationProvider)
 {
     NS_TIME_FUNCTION;
 
+    PR_SetCurrentThreadName("Main Thread");
+
     nsresult rv = NS_OK;
 
      // We are not shutting down
     gXPCOMShuttingDown = false;
 
     NS_TIME_FUNCTION_MARK("Next: AvailableMemoryTracker Init()");
 
     // Initialize the available memory tracker before other threads have had a
--- a/xpcom/glue/nsThreadUtils.cpp
+++ b/xpcom/glue/nsThreadUtils.cpp
@@ -13,16 +13,19 @@
 # include "nsIThreadManager.h"
 # include "nsServiceManagerUtils.h"
 #endif
 
 #ifdef XP_WIN
 #include <windows.h>
 #endif
 
+#include <pratom.h>
+#include <prthread.h>
+
 #ifndef XPCOM_GLUE_AVOID_NSPR
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsRunnable, nsIRunnable)
   
 NS_IMETHODIMP
 nsRunnable::Run()
 {
   // Do nothing
@@ -208,14 +211,80 @@ NS_ProcessNextEvent(nsIThread *thread, b
     NS_ENSURE_TRUE(current, false);
     thread = current.get();
   }
 #endif
   bool val;
   return NS_SUCCEEDED(thread->ProcessNextEvent(mayWait, &val)) && val;
 }
 
+#ifndef XPCOM_GLUE_AVOID_NSPR
+
+namespace {
+
+class nsNameThreadRunnable : public nsIRunnable
+{
+public:
+  nsNameThreadRunnable(const nsACString &name) : mName(name) { }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIRUNNABLE
+
+protected:
+  const nsCString mName;
+};
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(nsNameThreadRunnable, nsIRunnable)
+
+NS_IMETHODIMP
+nsNameThreadRunnable::Run()
+{
+  PR_SetCurrentThreadName(mName.BeginReading());
+  return NS_OK;
+}
+
+} // anonymous namespace
+
+void
+NS_SetThreadName(nsIThread *thread, const nsACString &name)
+{
+  if (!thread)
+    return;
+
+  thread->Dispatch(new nsNameThreadRunnable(name),
+                   nsIEventTarget::DISPATCH_NORMAL);
+}
+
+#else // !XPCOM_GLUE_AVOID_NSPR
+
+void
+NS_SetThreadName(nsIThread *thread, const nsACString &name)
+{
+  // No NSPR, no love.
+}
+
+#endif
+
 #ifdef MOZILLA_INTERNAL_API
 nsIThread *
 NS_GetCurrentThread() {
   return nsThreadManager::get()->GetCurrentThread();
 }
 #endif
+
+// nsThreadPoolNaming
+void
+nsThreadPoolNaming::SetThreadPoolName(const nsACString & aPoolName,
+                                      nsIThread * aThread)
+{
+  nsCString name(aPoolName);
+  name.Append(NS_LITERAL_CSTRING(" #"));
+  name.AppendInt(++mCounter, 10); // The counter is declared as volatile
+
+  if (aThread) {
+    // Set on the target thread
+    NS_SetThreadName(aThread, name);
+  }
+  else {
+    // Set on the current thread
+    PR_SetCurrentThreadName(name.BeginReading());
+  }
+}
--- a/xpcom/glue/nsThreadUtils.h
+++ b/xpcom/glue/nsThreadUtils.h
@@ -16,32 +16,53 @@
 #include "nsCOMPtr.h"
 #include "nsAutoPtr.h"
 #include "mozilla/threads/nsThreadIDs.h"
 
 // This is needed on some systems to prevent collisions between the symbols
 // appearing in xpcom_core and xpcomglue.  It may be unnecessary in the future
 // with better toolchain support.
 #ifdef MOZILLA_INTERNAL_API
+# define NS_SetThreadName NS_SetThreadName_P
 # define NS_NewThread NS_NewThread_P
+# define NS_NewNamedThread NS_NewNamedThread_P
 # define NS_GetCurrentThread NS_GetCurrentThread_P
 # define NS_GetMainThread NS_GetMainThread_P
 # define NS_IsMainThread NS_IsMainThread_P
 # define NS_DispatchToCurrentThread NS_DispatchToCurrentThread_P
 # define NS_DispatchToMainThread NS_DispatchToMainThread_P
 # define NS_ProcessPendingEvents NS_ProcessPendingEvents_P
 # define NS_HasPendingEvents NS_HasPendingEvents_P
 # define NS_ProcessNextEvent NS_ProcessNextEvent_P
 #endif
 
 //-----------------------------------------------------------------------------
 // These methods are alternatives to the methods on nsIThreadManager, provided
 // for convenience.
 
 /**
+ * Set name of the target thread.  This operation is asynchronous.
+ */
+extern NS_COM_GLUE void
+NS_SetThreadName(nsIThread *thread, const nsACString &name);
+
+/**
+ * Static length version of the above function checking length of the
+ * name at compile time.
+ */
+template <size_t LEN>
+inline NS_COM_GLUE void
+NS_SetThreadName(nsIThread *thread, const char (&name)[LEN])
+{
+  MOZ_STATIC_ASSERT(LEN <= 16,
+                    "Thread name must be no more than 16 characters");
+  NS_SetThreadName(thread, nsDependentCString(name));
+}
+
+/**
  * Create a new thread, and optionally provide an initial event for the thread.
  *
  * @param result
  *   The resulting nsIThread object.
  * @param initialEvent
  *   The initial event to run on this thread.  This parameter may be null.
  * @param stackSize
  *   The size in bytes to reserve for the thread's stack.
@@ -50,16 +71,31 @@
  *   Indicates that the given name is not unique.
  */
 extern NS_COM_GLUE NS_METHOD
 NS_NewThread(nsIThread **result,
              nsIRunnable *initialEvent = nsnull,
              PRUint32 stackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
 
 /**
+ * Creates a named thread, otherwise the same as NS_NewThread
+ */
+template <size_t LEN>
+inline NS_METHOD
+NS_NewNamedThread(const char (&name)[LEN],
+                  nsIThread **result,
+                  nsIRunnable *initialEvent = nsnull,
+                  PRUint32 stackSize = nsIThreadManager::DEFAULT_STACK_SIZE)
+{
+    nsresult rv = NS_NewThread(result, initialEvent, stackSize);
+    NS_SetThreadName<LEN>(*result, name);
+    return rv;
+}
+
+/**
  * Get a reference to the current thread.
  *
  * @param result
  *   The resulting nsIThread object.
  */
 extern NS_COM_GLUE NS_METHOD
 NS_GetCurrentThread(nsIThread **result);
 
@@ -429,9 +465,33 @@ public:
 private:
   // Not implemented
   nsRevocableEventPtr(const nsRevocableEventPtr&);
   nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
 
   nsRefPtr<T> mEvent;
 };
 
+/**
+ * A simple helper to suffix thread pool name
+ * with incremental numbers.
+ */
+class nsThreadPoolNaming
+{
+public:
+  nsThreadPoolNaming() : mCounter(0) {}
+
+  /**
+   * Creates and sets next thread name as "<aPoolName> #<n>"
+   * on the specified thread.  If no thread is specified (aThread
+   * is null) then the name is synchronously set on the current thread.
+   */
+  void SetThreadPoolName(const nsACString & aPoolName,
+                         nsIThread * aThread = nsnull);
+
+private:
+  volatile PRUint32 mCounter;
+
+  nsThreadPoolNaming(const nsThreadPoolNaming &) MOZ_DELETE;
+  void operator=(const nsThreadPoolNaming &) MOZ_DELETE;
+};
+
 #endif  // nsThreadUtils_h__
--- a/xpcom/threads/HangMonitor.cpp
+++ b/xpcom/threads/HangMonitor.cpp
@@ -173,16 +173,18 @@ GetChromeHangReport(Telemetry::HangStack
     moduleMap.RemoveEntries(moduleIndex + 1, moduleMap.GetSize());
   }
 }
 #endif
 
 void
 ThreadMain(void*)
 {
+  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;
   int waitCount = 0;
 
--- a/xpcom/threads/LazyIdleThread.cpp
+++ b/xpcom/threads/LazyIdleThread.cpp
@@ -25,29 +25,31 @@
   PR_END_MACRO
 #else
 #define ASSERT_OWNING_THREAD() /* nothing */
 #endif
 
 namespace mozilla {
 
 LazyIdleThread::LazyIdleThread(PRUint32 aIdleTimeoutMS,
+                               const nsCSubstring& aName,
                                ShutdownMethod aShutdownMethod,
                                nsIObserver* aIdleObserver)
 : mMutex("LazyIdleThread::mMutex"),
   mOwningThread(NS_GetCurrentThread()),
   mIdleObserver(aIdleObserver),
   mQueuedRunnables(nsnull),
   mIdleTimeoutMS(aIdleTimeoutMS),
   mPendingEventCount(0),
   mIdleNotificationCount(0),
   mShutdownMethod(aShutdownMethod),
   mShutdown(false),
   mThreadIsShuttingDown(false),
-  mIdleTimeoutEnabled(true)
+  mIdleTimeoutEnabled(true),
+  mName(aName)
 {
   NS_ASSERTION(mOwningThread, "This should never fail!");
 }
 
 LazyIdleThread::~LazyIdleThread()
 {
   ASSERT_OWNING_THREAD();
 
@@ -161,16 +163,18 @@ LazyIdleThread::EnsureThread()
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 void
 LazyIdleThread::InitThread()
 {
+  PR_SetCurrentThreadName(mName.BeginReading());
+
   // Happens on mThread but mThread may not be set yet...
 
   nsCOMPtr<nsIThreadInternal> thread(do_QueryInterface(NS_GetCurrentThread()));
   NS_ASSERTION(thread, "This should always succeed!");
 
   if (NS_FAILED(thread->SetObserver(this))) {
     NS_WARNING("Failed to set thread observer!");
   }
--- a/xpcom/threads/LazyIdleThread.h
+++ b/xpcom/threads/LazyIdleThread.h
@@ -13,16 +13,17 @@
 
 #include "nsIObserver.h"
 #include "nsIThreadInternal.h"
 #include "nsITimer.h"
 
 #include "mozilla/Mutex.h"
 #include "nsCOMPtr.h"
 #include "nsTArray.h"
+#include "nsString.h"
 
 #define IDLE_THREAD_TOPIC "thread-shutting-down"
 
 namespace mozilla {
 
 /**
  * This class provides a basic event target that creates its thread lazily and
  * destroys its thread after a period of inactivity. It may be created on any
@@ -48,16 +49,17 @@ public:
     ManualShutdown
   };
 
   /**
    * Create a new LazyIdleThread that will destroy its thread after the given
    * number of milliseconds.
    */
   LazyIdleThread(PRUint32 aIdleTimeoutMS,
+                 const nsCSubstring& aName,
                  ShutdownMethod aShutdownMethod = AutomaticShutdown,
                  nsIObserver* aIdleObserver = nsnull);
 
   /**
    * Add an observer that will be notified when the thread is idle and about to
    * be shut down. The aSubject argument can be QueryInterface'd to an nsIThread
    * that can be used to post cleanup events. The aTopic argument will be
    * IDLE_THREAD_TOPIC, and aData will be null. The LazyIdleThread does not add
@@ -200,13 +202,18 @@ private:
    * further idle notifications during the shutdown process.
    */
   bool mThreadIsShuttingDown;
 
   /**
    * Whether or not the idle timeout is enabled.
    */
   bool mIdleTimeoutEnabled;
+
+  /**
+   * Name of the thread, set on the actual thread after it gets created.
+   */
+  nsCString mName;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_lazyidlethread_h__
--- a/xpcom/threads/TimerThread.cpp
+++ b/xpcom/threads/TimerThread.cpp
@@ -211,16 +211,18 @@ void TimerThread::UpdateFilter(PRUint32 
          ("UpdateFilter: smoothSlack = %g, filterLength = %u\n",
           smoothSlack, filterLength));
 #endif
 }
 
 /* void Run(); */
 NS_IMETHODIMP TimerThread::Run()
 {
+  PR_SetCurrentThreadName("Timer");
+
   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
   PRInt32 low = 0, high = 1;
   while (PR_MicrosecondsToInterval(high) == 0)
     high <<= 1;
--- a/xpcom/threads/nsIThreadPool.idl
+++ b/xpcom/threads/nsIThreadPool.idl
@@ -22,17 +22,17 @@ interface nsIThreadPoolListener : nsISup
   void onThreadShuttingDown();
 };
 
 /**
  * An interface to a thread pool.  A thread pool creates a limited number of
  * anonymous (unnamed) worker threads.  An event dispatched to the thread pool
  * will be run on the next available worker thread.
  */
-[scriptable, uuid(d628159b-1a03-4985-aa77-43122eb23bfc)]
+[scriptable, uuid(ba9a466b-8d4a-4b33-ae5c-6ed751068c90)]
 interface nsIThreadPool : nsIEventTarget
 {
   /**
    * Shutdown the thread pool.  This method may not be executed from any thread
    * in the thread pool.  Instead, it is meant to be executed from another
    * thread (usually the thread that created this thread pool).  When this
    * function returns, the thread pool and all of its threads will be shutdown,
    * and it will no longer be possible to dispatch tasks to the thread pool.
@@ -66,9 +66,15 @@ interface nsIThreadPool : nsIEventTarget
    * corresponding onThreadShuttingDown() notification.
    *
    * The thread pool takes ownership of the listener and releases it when the
    * shutdown() method is called. Threads created after the listener is set will
    * also take ownership of the listener so that the listener will be kept alive
    * long enough to receive the guaranteed onThreadShuttingDown() notification.
    */
   attribute nsIThreadPoolListener listener;
+
+  /**
+   * Set the label for threads in the pool. All threads will be named
+   * "<aName> #<n>", where <n> is a serial number.
+   */
+  void setName(in ACString aName);
 };
--- a/xpcom/threads/nsProcessCommon.cpp
+++ b/xpcom/threads/nsProcessCommon.cpp
@@ -217,16 +217,18 @@ static int assembleCmdLine(char *const *
     MultiByteToWideChar(codePage, 0, cmdLine, -1, *wideCmdLine, numChars); 
     PR_Free(cmdLine);
     return 0;
 }
 #endif
 
 void PR_CALLBACK nsProcess::Monitor(void *arg)
 {
+    PR_SetCurrentThreadName("RunProcess");
+
     nsRefPtr<nsProcess> process = dont_AddRef(static_cast<nsProcess*>(arg));
 #if defined(PROCESSMODEL_WINAPI)
     DWORD dwRetVal;
     unsigned long exitCode = -1;
 
     dwRetVal = WaitForSingleObject(process->mProcess, INFINITE);
     if (dwRetVal != WAIT_FAILED) {
         if (GetExitCodeProcess(process->mProcess, &exitCode) == FALSE)
--- a/xpcom/threads/nsThreadPool.cpp
+++ b/xpcom/threads/nsThreadPool.cpp
@@ -115,16 +115,18 @@ nsThreadPool::ShutdownThread(nsIThread *
   NS_DispatchToMainThread(r);
 }
 
 NS_IMETHODIMP
 nsThreadPool::Run()
 {
   LOG(("THRD-P(%p) enter\n", this));
 
+  mThreadNaming.SetThreadPoolName(mName);
+
   nsCOMPtr<nsIThread> current;
   nsThreadManager::get()->GetCurrentThread(getter_AddRefs(current));
 
   bool shutdownThreadOnExit = false;
   bool exitThread = false;
   bool wasIdle = false;
   PRIntervalTime idleSince;
 
@@ -327,8 +329,21 @@ nsThreadPool::SetListener(nsIThreadPoolL
 {
   nsCOMPtr<nsIThreadPoolListener> swappedListener(aListener);
   {
     ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
     mListener.swap(swappedListener);
   }
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsThreadPool::SetName(const nsACString& aName)
+{
+  {
+    ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor());
+    if (mThreads.Count())
+      return NS_ERROR_NOT_AVAILABLE;
+  }
+
+  mName = aName;
+  return NS_OK;
+}
--- a/xpcom/threads/nsThreadPool.h
+++ b/xpcom/threads/nsThreadPool.h
@@ -8,16 +8,17 @@
 #define nsThreadPool_h__
 
 #include "nsIThreadPool.h"
 #include "nsIThread.h"
 #include "nsIRunnable.h"
 #include "nsEventQueue.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
+#include "nsThreadUtils.h"
 
 class nsThreadPool : public nsIThreadPool, public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIEVENTTARGET
   NS_DECL_NSITHREADPOOL
   NS_DECL_NSIRUNNABLE
@@ -33,16 +34,18 @@ private:
   nsCOMArray<nsIThread> mThreads;
   nsEventQueue          mEvents;
   PRUint32              mThreadLimit;
   PRUint32              mIdleThreadLimit;
   PRUint32              mIdleThreadTimeout;
   PRUint32              mIdleCount;
   nsCOMPtr<nsIThreadPoolListener> mListener;
   bool                  mShutdown;
+  nsCString             mName;
+  nsThreadPoolNaming    mThreadNaming;
 };
 
 #define NS_THREADPOOL_CLASSNAME "nsThreadPool"
 #define NS_THREADPOOL_CID                          \
 { /* 547ec2a8-315e-4ec4-888e-6e4264fe90eb */       \
   0x547ec2a8,                                      \
   0x315e,                                          \
   0x4ec4,                                          \