diff --git a/dom/storage/StorageDBThread.cpp b/dom/storage/StorageDBThread.cpp index af605480590c..dc42e2ab1de7 100644 --- a/dom/storage/StorageDBThread.cpp +++ b/dom/storage/StorageDBThread.cpp @@ -25,12 +25,8 @@ #include "mozilla/BasePrincipal.h" #include "mozilla/ipc/BackgroundParent.h" #include "nsIObserverService.h" -#include "nsThread.h" -#include "nsThreadManager.h" #include "nsVariant.h" -#include "mozilla/EventQueue.h" #include "mozilla/IOInterposer.h" -#include "mozilla/ThreadEventQueue.h" #include "mozilla/Services.h" #include "mozilla/Tokenizer.h" #include "GeckoProfiler.h" @@ -492,12 +488,6 @@ StorageDBThread::SetDefaultPriority() void StorageDBThread::ThreadFunc(void* aArg) { - { - auto queue = MakeRefPtr>(MakeUnique()); - Unused << - nsThreadManager::get().CreateCurrentThread(queue, nsThread::NOT_MAIN_THREAD); - } - AUTO_PROFILER_REGISTER_THREAD("localStorage DB"); NS_SetCurrentThreadName("localStorage DB"); mozilla::IOInterposer::RegisterCurrentThread(); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 46663e576f7c..4855312b8855 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -5354,13 +5354,22 @@ WorkerPrivate::CreateDebuggerGlobalScope(JSContext* aCx) bool WorkerPrivate::IsOnWorkerThread() const { - // We can't use mThread because it must be protected by mMutex and sometimes - // this method is called when mMutex is already locked. This method should - // always work. + // This is much more complicated than it needs to be but we can't use mThread + // because it must be protected by mMutex and sometimes this method is called + // when mMutex is already locked. This method should always work. MOZ_ASSERT(mPRThread, "AssertIsOnWorkerThread() called before a thread was assigned!"); - return mPRThread == PR_GetCurrentThread(); + nsCOMPtr thread; + nsresult rv = + nsThreadManager::get().GetThreadFromPRThread(mPRThread, + getter_AddRefs(thread)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + MOZ_ASSERT(thread); + + bool current; + rv = thread->IsOnCurrentThread(¤t); + return NS_SUCCEEDED(rv) && current; } #ifdef DEBUG diff --git a/ipc/chromium/src/base/platform_thread_posix.cc b/ipc/chromium/src/base/platform_thread_posix.cc index 3984778a315c..1c6410453fcf 100644 --- a/ipc/chromium/src/base/platform_thread_posix.cc +++ b/ipc/chromium/src/base/platform_thread_posix.cc @@ -35,6 +35,10 @@ void InitThreading(); #endif static void* ThreadFunc(void* closure) { + // Create a nsThread wrapper for the current platform thread, and register it + // with the thread manager. + (void) NS_GetCurrentThread(); + PlatformThread::Delegate* delegate = static_cast(closure); delegate->ThreadMain(); diff --git a/ipc/chromium/src/base/platform_thread_win.cc b/ipc/chromium/src/base/platform_thread_win.cc index e9e84751b2a8..762aa7e305e3 100644 --- a/ipc/chromium/src/base/platform_thread_win.cc +++ b/ipc/chromium/src/base/platform_thread_win.cc @@ -25,6 +25,10 @@ typedef struct tagTHREADNAME_INFO { } THREADNAME_INFO; DWORD __stdcall ThreadFunc(void* closure) { + // Create a nsThread wrapper for the current platform thread, and register it + // with the thread manager. + (void) NS_GetCurrentThread(); + PlatformThread::Delegate* delegate = static_cast(closure); delegate->ThreadMain(); diff --git a/ipc/chromium/src/base/thread.cc b/ipc/chromium/src/base/thread.cc index 5a67140a7bf5..79519ea47ab7 100644 --- a/ipc/chromium/src/base/thread.cc +++ b/ipc/chromium/src/base/thread.cc @@ -10,11 +10,8 @@ #include "base/thread_local.h" #include "base/waitable_event.h" #include "GeckoProfiler.h" -#include "mozilla/EventQueue.h" #include "mozilla/IOInterposer.h" -#include "mozilla/ThreadEventQueue.h" #include "nsThreadUtils.h" -#include "nsThreadManager.h" #ifdef MOZ_TASK_TRACER #include "GeckoTaskTracer.h" @@ -157,24 +154,12 @@ void Thread::StopSoon() { } void Thread::ThreadMain() { - nsCOMPtr xpcomThread; - if (startup_data_->options.message_loop_type == MessageLoop::TYPE_MOZILLA_NONMAINTHREAD) { - auto queue = mozilla::MakeRefPtr>( - mozilla::MakeUnique()); - xpcomThread = - nsThreadManager::get().CreateCurrentThread(queue, nsThread::NOT_MAIN_THREAD); - } else { - xpcomThread = NS_GetCurrentThread(); - } - AUTO_PROFILER_REGISTER_THREAD(name_.c_str()); mozilla::IOInterposer::RegisterCurrentThread(); // The message loop for this thread. MessageLoop message_loop(startup_data_->options.message_loop_type, - xpcomThread); - - xpcomThread = nullptr; + NS_GetCurrentThread()); // Complete the initialization of our Thread object. thread_id_ = PlatformThread::CurrentId(); diff --git a/netwerk/cache2/CacheIOThread.cpp b/netwerk/cache2/CacheIOThread.cpp index f03e61885736..8a2b0d868506 100644 --- a/netwerk/cache2/CacheIOThread.cpp +++ b/netwerk/cache2/CacheIOThread.cpp @@ -8,12 +8,8 @@ #include "nsIRunnable.h" #include "nsISupportsImpl.h" #include "nsPrintfCString.h" -#include "nsThread.h" -#include "nsThreadManager.h" #include "nsThreadUtils.h" -#include "mozilla/EventQueue.h" #include "mozilla/IOInterposer.h" -#include "mozilla/ThreadEventQueue.h" #include "GeckoProfiler.h" #ifdef XP_WIN @@ -465,10 +461,8 @@ void CacheIOThread::ThreadFunc() MOZ_ASSERT(mBlockingIOWatcher); mBlockingIOWatcher->InitThread(); - auto queue = MakeRefPtr>( - MakeUnique()); - nsCOMPtr xpcomThread = - nsThreadManager::get().CreateCurrentThread(queue, nsThread::NOT_MAIN_THREAD); + // This creates nsThread for this PRThread + nsCOMPtr xpcomThread = NS_GetCurrentThread(); threadInternal = do_QueryInterface(xpcomThread); if (threadInternal) diff --git a/security/sandbox/linux/broker/SandboxBroker.cpp b/security/sandbox/linux/broker/SandboxBroker.cpp index 73e62ff1450f..3a55c98ef52d 100644 --- a/security/sandbox/linux/broker/SandboxBroker.cpp +++ b/security/sandbox/linux/broker/SandboxBroker.cpp @@ -31,7 +31,6 @@ #include "mozilla/ipc/FileDescriptor.h" #include "nsDirectoryServiceDefs.h" #include "nsAppDirectoryServiceDefs.h" -#include "nsThreadUtils.h" #include "SpecialSystemDirectory.h" #include "sandbox/linux/system_headers/linux_syscalls.h" @@ -664,10 +663,6 @@ SandboxBroker::SymlinkPermissions(const char* aPath, const size_t aPathLen) void SandboxBroker::ThreadMain(void) { - // Create a nsThread wrapper for the current platform thread, and register it - // with the thread manager. - (void) NS_GetCurrentThread(); - char threadName[16]; SprintfLiteral(threadName, "FS Broker %d", mChildPid); PlatformThread::SetName(threadName); diff --git a/security/sandbox/linux/reporter/SandboxReporter.cpp b/security/sandbox/linux/reporter/SandboxReporter.cpp index 86db888648bc..6403c0500c90 100644 --- a/security/sandbox/linux/reporter/SandboxReporter.cpp +++ b/security/sandbox/linux/reporter/SandboxReporter.cpp @@ -237,10 +237,6 @@ SandboxReporter::AddOne(const SandboxReport& aReport) void SandboxReporter::ThreadMain(void) { - // Create a nsThread wrapper for the current platform thread, and register it - // with the thread manager. - (void) NS_GetCurrentThread(); - for (;;) { SandboxReport rep; struct iovec iov; diff --git a/storage/test/gtest/storage_test_harness.h b/storage/test/gtest/storage_test_harness.h index 31447e1f99b8..09a01c7f9da5 100644 --- a/storage/test/gtest/storage_test_harness.h +++ b/storage/test/gtest/storage_test_harness.h @@ -225,7 +225,7 @@ PRThread *watched_thread = nullptr; * When the thread a mutex is invoked on isn't watched_thread we save it to this * variable. */ -nsIThread* last_non_watched_thread = nullptr; +PRThread *last_non_watched_thread = nullptr; /** * Set a flag if the mutex is used on the thread we are watching, but always @@ -233,10 +233,11 @@ nsIThread* last_non_watched_thread = nullptr; */ extern "C" void wrapped_MutexEnter(sqlite3_mutex *mutex) { - if (PR_GetCurrentThread() == watched_thread) + PRThread *curThread = ::PR_GetCurrentThread(); + if (curThread == watched_thread) mutex_used_on_watched_thread = true; else - last_non_watched_thread = NS_GetCurrentThread(); + last_non_watched_thread = curThread; orig_mutex_methods.xMutexEnter(mutex); } @@ -350,13 +351,19 @@ get_conn_async_thread(mozIStorageConnection *db) blocking_async_execute(stmt); stmt->Finalize(); - nsCOMPtr asyncThread = last_non_watched_thread; + nsCOMPtr threadMan = + do_GetService("@mozilla.org/thread-manager;1"); + nsCOMPtr asyncThread; + threadMan->GetThreadFromPRThread(last_non_watched_thread, + getter_AddRefs(asyncThread)); // Additionally, check that the thread we get as the background thread is the // same one as the one we report from getInterface. nsCOMPtr target = do_GetInterface(db); nsCOMPtr allegedAsyncThread = do_QueryInterface(target); - do_check_eq(allegedAsyncThread, asyncThread); + PRThread *allegedPRThread; + (void)allegedAsyncThread->GetPRThread(&allegedPRThread); + do_check_eq(allegedPRThread, last_non_watched_thread); return asyncThread.forget(); } diff --git a/xpcom/threads/nsIThreadManager.idl b/xpcom/threads/nsIThreadManager.idl index bd0917204748..89d67081f822 100644 --- a/xpcom/threads/nsIThreadManager.idl +++ b/xpcom/threads/nsIThreadManager.idl @@ -84,6 +84,19 @@ interface nsIThreadManager : nsISupports */ [noscript] nsIThread newNamedThread(in ACString name, [optional] in unsigned long stackSize); + /** + * Get the nsIThread object (if any) corresponding to the given PRThread. + * This method returns null if there is no corresponding nsIThread. + * + * @param prthread + * The PRThread of the nsIThread being requested. + * + * @returns + * The nsIThread object corresponding to the given PRThread or null if no + * such nsIThread exists. + */ + [noscript] nsIThread getThreadFromPRThread(in PRThread prthread); + /** * Get the main thread. */ diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index a4eb95283726..a023114176e1 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -115,9 +115,6 @@ NS_DECL_CI_INTERFACE_GETTER(nsThread) Array nsThread::sMainThreadRunnableName; -uint32_t nsThread::sActiveThreads; -uint32_t nsThread::sMaxActiveThreads; - //----------------------------------------------------------------------------- // Because we do not have our own nsIFactory, we have to implement nsIClassInfo // somewhat manually. @@ -419,40 +416,6 @@ nsThread::Enumerate() return {}; } -/* static */ uint32_t -nsThread::MaxActiveThreads() -{ - OffTheBooksMutexAutoLock mal(ThreadListMutex()); - return sMaxActiveThreads; -} - -void -nsThread::AddToThreadList() -{ - OffTheBooksMutexAutoLock mal(ThreadListMutex()); - MOZ_ASSERT(!isInList()); - - sActiveThreads++; - sMaxActiveThreads = std::max(sActiveThreads, sMaxActiveThreads); - - ThreadList().insertBack(this); -} - -void -nsThread::MaybeRemoveFromThreadList() -{ - // We shouldn't need to lock before checking isInList at this point. We're - // destroying the last reference to this object, so there's no way for anyone - // else to remove it in the middle of our check. And the not-in-list state is - // determined the element's next and previous members pointing to itself, so a - // non-atomic update to an adjacent member won't affect the outcome either. - if (isInList()) { - OffTheBooksMutexAutoLock mal(ThreadListMutex()); - sActiveThreads--; - removeFrom(ThreadList()); - } -} - /*static*/ void nsThread::ThreadFunc(void* aArg) { @@ -461,9 +424,6 @@ nsThread::ThreadFunc(void* aArg) ThreadInitData* initData = static_cast(aArg); nsThread* self = initData->thread; // strong reference - MOZ_ASSERT(self->mEventTarget); - MOZ_ASSERT(self->mEvents); - self->mThread = PR_GetCurrentThread(); self->mVirtualThread = GetCurrentVirtualThread(); self->mEventTarget->SetCurrentThread(); @@ -625,7 +585,8 @@ nsThread::InitCommon() #endif } - AddToThreadList(); + OffTheBooksMutexAutoLock mal(ThreadListMutex()); + ThreadList().insertBack(this); } //----------------------------------------------------------------------------- @@ -655,33 +616,20 @@ nsThread::nsThread(NotNull aQueue, { } - -nsThread::nsThread() - : mEvents(nullptr) - , mEventTarget(nullptr) - , mShutdownContext(nullptr) - , mScriptObserver(nullptr) - , mThread(nullptr) - , mStackSize(0) - , mNestedEventLoopDepth(0) - , mCurrentEventLoopDepth(-1) - , mShutdownRequired(false) - , mPriority(PRIORITY_NORMAL) - , mIsMainThread(NOT_MAIN_THREAD) - , mCanInvokeJS(false) - , mCurrentEvent(nullptr) - , mCurrentEventStart(TimeStamp::Now()) - , mCurrentPerformanceCounter(nullptr) -{ - MOZ_ASSERT(!NS_IsMainThread()); -} - nsThread::~nsThread() { NS_ASSERTION(mRequestedShutdownContexts.IsEmpty(), "shouldn't be waiting on other threads to shutdown"); - MaybeRemoveFromThreadList(); + // We shouldn't need to lock before checking isInList at this point. We're + // destroying the last reference to this object, so there's no way for anyone + // else to remove it in the middle of our check. And the not-in-list state is + // determined the element's next and previous members pointing to itself, so a + // non-atomic update to an adjacent member won't affect the outcome either. + if (isInList()) { + OffTheBooksMutexAutoLock mal(ThreadListMutex()); + removeFrom(ThreadList()); + } #ifdef DEBUG // We deliberately leak these so they can be tracked by the leak checker. @@ -699,9 +647,6 @@ nsThread::~nsThread() nsresult nsThread::Init(const nsACString& aName) { - MOZ_ASSERT(mEvents); - MOZ_ASSERT(mEventTarget); - // spawn thread and wait until it is fully setup RefPtr startup = new nsThreadStartupEvent(); @@ -750,9 +695,6 @@ nsThread::InitCurrentThread() NS_IMETHODIMP nsThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags) { - MOZ_ASSERT(mEventTarget); - NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_IMPLEMENTED); - nsCOMPtr event(aEvent); return mEventTarget->Dispatch(event.forget(), aFlags); } @@ -760,9 +702,6 @@ nsThread::DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags) NS_IMETHODIMP nsThread::Dispatch(already_AddRefed aEvent, uint32_t aFlags) { - MOZ_ASSERT(mEventTarget); - NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_IMPLEMENTED); - LOG(("THRD(%p) Dispatch [%p %x]\n", this, /* XXX aEvent */nullptr, aFlags)); return mEventTarget->Dispatch(std::move(aEvent), aFlags); @@ -771,20 +710,13 @@ nsThread::Dispatch(already_AddRefed aEvent, uint32_t aFlags) NS_IMETHODIMP nsThread::DelayedDispatch(already_AddRefed aEvent, uint32_t aDelayMs) { - MOZ_ASSERT(mEventTarget); - NS_ENSURE_TRUE(mEventTarget, NS_ERROR_NOT_IMPLEMENTED); - return mEventTarget->DelayedDispatch(std::move(aEvent), aDelayMs); } NS_IMETHODIMP nsThread::IsOnCurrentThread(bool* aResult) { - if (mEventTarget) { - return mEventTarget->IsOnCurrentThread(aResult); - } - *aResult = GetCurrentVirtualThread() == mVirtualThread; - return NS_OK; + return mEventTarget->IsOnCurrentThread(aResult); } NS_IMETHODIMP_(bool) @@ -836,8 +768,6 @@ nsThread::AsyncShutdown() nsThreadShutdownContext* nsThread::ShutdownInternal(bool aSync) { - MOZ_ASSERT(mEvents); - MOZ_ASSERT(mEventTarget); MOZ_ASSERT(mThread); MOZ_ASSERT(mThread != PR_GetCurrentThread()); if (NS_WARN_IF(mThread == PR_GetCurrentThread())) { @@ -849,7 +779,12 @@ nsThread::ShutdownInternal(bool aSync) return nullptr; } - MaybeRemoveFromThreadList(); + { + OffTheBooksMutexAutoLock mal(ThreadListMutex()); + if (isInList()) { + removeFrom(ThreadList()); + } + } NotNull currentThread = WrapNotNull(nsThreadManager::get().GetCurrentThread()); @@ -874,12 +809,15 @@ nsThread::ShutdownInternal(bool aSync) void nsThread::ShutdownComplete(NotNull aContext) { - MOZ_ASSERT(mEvents); - MOZ_ASSERT(mEventTarget); MOZ_ASSERT(mThread); MOZ_ASSERT(aContext->mTerminatingThread == this); - MaybeRemoveFromThreadList(); + { + OffTheBooksMutexAutoLock mal(ThreadListMutex()); + if (isInList()) { + removeFrom(ThreadList()); + } + } if (aContext->mAwaitingShutdownAck) { // We're in a synchronous shutdown, so tell whatever is up the stack that @@ -1094,9 +1032,6 @@ nsThread::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const NS_IMETHODIMP nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) { - MOZ_ASSERT(mEvents); - NS_ENSURE_TRUE(mEvents, NS_ERROR_NOT_IMPLEMENTED); - LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, aMayWait, mNestedEventLoopDepth)); @@ -1329,9 +1264,6 @@ nsThread::AdjustPriority(int32_t aDelta) NS_IMETHODIMP nsThread::GetObserver(nsIThreadObserver** aObs) { - MOZ_ASSERT(mEvents); - NS_ENSURE_TRUE(mEvents, NS_ERROR_NOT_IMPLEMENTED); - nsCOMPtr obs = mEvents->GetObserver(); obs.forget(aObs); return NS_OK; @@ -1340,9 +1272,6 @@ nsThread::GetObserver(nsIThreadObserver** aObs) NS_IMETHODIMP nsThread::SetObserver(nsIThreadObserver* aObs) { - MOZ_ASSERT(mEvents); - NS_ENSURE_TRUE(mEvents, NS_ERROR_NOT_IMPLEMENTED); - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) { return NS_ERROR_NOT_SAME_THREAD; } @@ -1361,9 +1290,6 @@ nsThread::RecursionDepth() const NS_IMETHODIMP nsThread::AddObserver(nsIThreadObserver* aObserver) { - MOZ_ASSERT(mEvents); - NS_ENSURE_TRUE(mEvents, NS_ERROR_NOT_IMPLEMENTED); - if (NS_WARN_IF(!aObserver)) { return NS_ERROR_INVALID_ARG; } @@ -1379,9 +1305,6 @@ nsThread::AddObserver(nsIThreadObserver* aObserver) NS_IMETHODIMP nsThread::RemoveObserver(nsIThreadObserver* aObserver) { - MOZ_ASSERT(mEvents); - NS_ENSURE_TRUE(mEvents, NS_ERROR_NOT_IMPLEMENTED); - if (NS_WARN_IF(PR_GetCurrentThread() != mThread)) { return NS_ERROR_NOT_SAME_THREAD; } diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index a447f27fef0f..4d4573bf0f92 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -60,10 +60,6 @@ public: MainThreadFlag aMainThread, uint32_t aStackSize); -private: - nsThread(); - -public: // Initialize this as a wrapper for a new PRThread, and optionally give it a name. nsresult Init(const nsACString& aName = NS_LITERAL_CSTRING("")); @@ -150,8 +146,6 @@ public: static nsThreadEnumerator Enumerate(); - static uint32_t MaxActiveThreads(); - private: void DoMainThreadSpecificProcessing(bool aReallyWait); @@ -180,21 +174,6 @@ protected: static mozilla::LinkedList& ThreadList(); static void ClearThreadList(); - // The current number of active threads. - static uint32_t sActiveThreads; - // The maximum current number of active threads we've had in this session. - static uint32_t sMaxActiveThreads; - - void AddToThreadList(); - void MaybeRemoveFromThreadList(); - - - // Whether or not these members have a value determines whether the nsThread - // is treated as a full XPCOM thread or as a thin wrapper. - // - // For full nsThreads, they will always contain valid pointers. For thin - // wrappers around non-XPCOM threads, they will be null, and event dispatch - // methods which rely on them will fail (and assert) if called. RefPtr mEvents; RefPtr mEventTarget; diff --git a/xpcom/threads/nsThreadManager.cpp b/xpcom/threads/nsThreadManager.cpp index 27a46acec6b5..7df2d9ed86f7 100644 --- a/xpcom/threads/nsThreadManager.cpp +++ b/xpcom/threads/nsThreadManager.cpp @@ -109,6 +109,8 @@ nsThreadManager::ReleaseThread(void* aData) auto* thread = static_cast(aData); + get().UnregisterCurrentThread(*thread, true); + if (thread->mHasTLSEntry) { thread->mHasTLSEntry = false; thread->Release(); @@ -319,11 +321,14 @@ nsThreadManager::Shutdown() { // We gather the threads from the hashtable into a list, so that we avoid - // holding the enumerator lock while calling nsIThread::Shutdown. - nsTArray> threadsToShutdown; - for (auto* thread : nsThread::Enumerate()) { - if (thread->ShutdownRequired()) { - threadsToShutdown.AppendElement(thread); + // holding the hashtable lock while calling nsIThread::Shutdown. + nsThreadArray threads; + { + OffTheBooksMutexAutoLock lock(mLock); + for (auto iter = mThreadsByPRThread.Iter(); !iter.Done(); iter.Next()) { + RefPtr& thread = iter.Data(); + threads.AppendElement(WrapNotNull(thread)); + iter.Remove(); } } @@ -337,8 +342,11 @@ nsThreadManager::Shutdown() // world until such time as the threads exit. // Shutdown all threads that require it (join with threads that we created). - for (auto& thread : threadsToShutdown) { - thread->Shutdown(); + for (uint32_t i = 0; i < threads.Length(); ++i) { + NotNull thread = threads[i]; + if (thread->ShutdownRequired()) { + thread->Shutdown(); + } } } @@ -353,6 +361,12 @@ nsThreadManager::Shutdown() // There are no more background threads at this point. + // Clear the table of threads. + { + OffTheBooksMutexAutoLock lock(mLock); + mThreadsByPRThread.Clear(); + } + // Normally thread shutdown clears the observer for the thread, but since the // main thread is special we do it manually here after we're sure all events // have been processed. @@ -388,15 +402,35 @@ nsThreadManager::RegisterCurrentThread(nsThread& aThread) { MOZ_ASSERT(aThread.GetPRThread() == PR_GetCurrentThread(), "bad aThread"); + OffTheBooksMutexAutoLock lock(mLock); + + ++mCurrentNumberOfThreads; + if (mCurrentNumberOfThreads > mHighestNumberOfThreads) { + mHighestNumberOfThreads = mCurrentNumberOfThreads; + } + + mThreadsByPRThread.Put(aThread.GetPRThread(), &aThread); // XXX check OOM? + aThread.AddRef(); // for TLS entry aThread.mHasTLSEntry = true; PR_SetThreadPrivate(mCurThreadIndex, &aThread); } void -nsThreadManager::UnregisterCurrentThread(nsThread& aThread) +nsThreadManager::UnregisterCurrentThread(nsThread& aThread, bool aIfExists) { - MOZ_ASSERT(aThread.GetPRThread() == PR_GetCurrentThread(), "bad aThread"); + { + OffTheBooksMutexAutoLock lock(mLock); + + if (aIfExists && !mThreadsByPRThread.GetWeak(aThread.GetPRThread())) { + return; + } + + MOZ_ASSERT(aThread.GetPRThread() == PR_GetCurrentThread(), "bad aThread"); + + --mCurrentNumberOfThreads; + mThreadsByPRThread.Remove(aThread.GetPRThread()); + } PR_SetThreadPrivate(mCurThreadIndex, nullptr); // Ref-count balanced via ReleaseThread @@ -413,6 +447,7 @@ nsThreadManager::CreateCurrentThread(SynchronizedEventQueue* aQueue, return nullptr; } + // OK, that's fine. We'll dynamically create one :-) RefPtr thread = new nsThread(WrapNotNull(aQueue), aMainThread, 0); if (!thread || NS_FAILED(thread->InitCurrentThread())) { return nullptr; @@ -435,11 +470,9 @@ nsThreadManager::GetCurrentThread() } // OK, that's fine. We'll dynamically create one :-) - // - // We assume that if we're implicitly creating a thread here that it doesn't - // want an event queue. Any thread which wants an event queue should - // explicitly create its nsThread wrapper. - RefPtr thread = new nsThread(); + RefPtr> queue = + new ThreadEventQueue(MakeUnique()); + RefPtr thread = new nsThread(WrapNotNull(queue), nsThread::NOT_MAIN_THREAD, 0); if (!thread || NS_FAILED(thread->InitCurrentThread())) { return nullptr; } @@ -454,7 +487,7 @@ nsThreadManager::IsNSThread() const return false; } if (auto* thread = (nsThread*)PR_GetThreadPrivate(mCurThreadIndex)) { - return thread->EventQueue(); + return thread->mShutdownRequired; } return false; } @@ -503,6 +536,27 @@ nsThreadManager::NewNamedThread(const nsACString& aName, return NS_OK; } +NS_IMETHODIMP +nsThreadManager::GetThreadFromPRThread(PRThread* aThread, nsIThread** aResult) +{ + // Keep this functioning during Shutdown + if (NS_WARN_IF(!mMainThread)) { + return NS_ERROR_NOT_INITIALIZED; + } + if (NS_WARN_IF(!aThread)) { + return NS_ERROR_INVALID_ARG; + } + + RefPtr temp; + { + OffTheBooksMutexAutoLock lock(mLock); + mThreadsByPRThread.Get(aThread, getter_AddRefs(temp)); + } + + NS_IF_ADDREF(*aResult = temp); + return NS_OK; +} + NS_IMETHODIMP nsThreadManager::GetMainThread(nsIThread** aResult) { @@ -605,7 +659,8 @@ nsThreadManager::GetSystemGroupEventTarget(nsIEventTarget** aTarget) uint32_t nsThreadManager::GetHighestNumberOfThreads() { - return nsThread::MaxActiveThreads(); + OffTheBooksMutexAutoLock lock(mLock); + return mHighestNumberOfThreads; } NS_IMETHODIMP diff --git a/xpcom/threads/nsThreadManager.h b/xpcom/threads/nsThreadManager.h index 547c1c16a777..dd936be11081 100644 --- a/xpcom/threads/nsThreadManager.h +++ b/xpcom/threads/nsThreadManager.h @@ -9,6 +9,7 @@ #include "mozilla/Mutex.h" #include "nsIThreadManager.h" +#include "nsRefPtrHashtable.h" #include "nsThread.h" class nsIRunnable; @@ -35,7 +36,7 @@ public: // Called by nsThread to inform the ThreadManager it is going away. This // method must be called when the given thread is the current thread. - void UnregisterCurrentThread(nsThread& aThread); + void UnregisterCurrentThread(nsThread& aThread, bool aIfExists = false); // Returns the current thread. Returns null if OOM or if ThreadManager isn't // initialized. Creates the nsThread if one does not exist yet. @@ -73,7 +74,10 @@ private: nsThreadManager() : mCurThreadIndex(0) , mMainPRThread(nullptr) + , mLock("nsThreadManager.mLock") , mInitialized(false) + , mCurrentNumberOfThreads(1) + , mHighestNumberOfThreads(1) { } @@ -83,12 +87,19 @@ private: static void ReleaseThread(void* aData); + nsRefPtrHashtable, nsThread> mThreadsByPRThread; unsigned mCurThreadIndex; // thread-local-storage index RefPtr mMainThread; PRThread* mMainPRThread; + mozilla::OffTheBooksMutex mLock; // protects tables mozilla::Atomic mInitialized; + + // The current number of threads + uint32_t mCurrentNumberOfThreads; + // The highest number of threads encountered so far during the session + uint32_t mHighestNumberOfThreads; }; #define NS_THREADMANAGER_CID \