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 101778 772d9d20cdf913568c154a6387d784a3c36dc622
parent 101777 dbf0598205cecbb35485f423c88595b1a34918a8
child 101779 22796d93c42e7b8b872adfee86af3945816aac2e
push id191
push userlsblakk@mozilla.com
push dateFri, 05 Oct 2012 17:12:53 +0000
treeherdermozilla-release@ddb22ac6c03b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmith, bsmedberg
bugs720778
milestone16.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 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,                                          \