diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 5b81c0dae0a7..3ad1e31d3336 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -376,6 +376,26 @@ struct ThreadInitData { } +/* static */ mozilla::OffTheBooksMutex& +nsThread::ThreadListMutex() +{ + static OffTheBooksMutex sMutex("nsThread::ThreadListMutex"); + return sMutex; +} + +/* static */ LinkedList& +nsThread::ThreadList() +{ + static LinkedList sList; + return sList; +} + +/* static */ nsThreadEnumerator +nsThread::Enumerate() +{ + return {}; +} + /*static*/ void nsThread::ThreadFunc(void* aArg) { @@ -568,6 +588,7 @@ nsThread::~nsThread() { NS_ASSERTION(mRequestedShutdownContexts.IsEmpty(), "shouldn't be waiting on other threads to shutdown"); + MOZ_ASSERT(!isInList()); #ifdef DEBUG // We deliberately leak these so they can be tracked by the leak checker. // If you're having nsThreadShutdownContext leaks, you can set: @@ -601,6 +622,11 @@ nsThread::Init(const nsACString& aName) return NS_ERROR_OUT_OF_MEMORY; } + { + OffTheBooksMutexAutoLock mal(ThreadListMutex()); + ThreadList().insertBack(this); + } + // ThreadFunc will wait for this event to be run before it tries to access // mThread. By delaying insertion of this event into the queue, we ensure // that mThread is set properly. @@ -715,6 +741,13 @@ nsThread::ShutdownInternal(bool aSync) return nullptr; } + { + OffTheBooksMutexAutoLock mal(ThreadListMutex()); + if (isInList()) { + removeFrom(ThreadList()); + } + } + NotNull currentThread = WrapNotNull(nsThreadManager::get().GetCurrentThread()); diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index aeacc2d9312f..8cb6aa3f99c6 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -15,6 +15,7 @@ #include "nsString.h" #include "nsTObserverArray.h" #include "mozilla/Attributes.h" +#include "mozilla/LinkedList.h" #include "mozilla/SynchronizedEventQueue.h" #include "mozilla/NotNull.h" #include "mozilla/TimeStamp.h" @@ -31,11 +32,16 @@ class ThreadEventTarget; using mozilla::NotNull; +class nsThreadEnumerator; + // A native thread class nsThread : public nsIThreadInternal , public nsISupportsPriority + , private mozilla::LinkedListElement { + friend mozilla::LinkedList; + friend mozilla::LinkedListElement; public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIEVENTTARGET_FULL @@ -132,12 +138,16 @@ public: virtual mozilla::PerformanceCounter* GetPerformanceCounter(nsIRunnable* aEvent); + static nsThreadEnumerator Enumerate(); + private: void DoMainThreadSpecificProcessing(bool aReallyWait); protected: friend class nsThreadShutdownEvent; + friend class nsThreadEnumerator; + virtual ~nsThread(); static void ThreadFunc(void* aArg); @@ -152,6 +162,9 @@ protected: struct nsThreadShutdownContext* ShutdownInternal(bool aSync); + static mozilla::OffTheBooksMutex& ThreadListMutex(); + static mozilla::LinkedList& ThreadList(); + RefPtr mEvents; RefPtr mEventTarget; @@ -184,6 +197,20 @@ protected: RefPtr mCurrentPerformanceCounter; }; +class MOZ_STACK_CLASS nsThreadEnumerator final +{ +public: + nsThreadEnumerator() + : mMal(nsThread::ThreadListMutex()) + {} + + auto begin() { return nsThread::ThreadList().begin(); } + auto end() { return nsThread::ThreadList().end(); } + +private: + mozilla::OffTheBooksMutexAutoLock mMal; +}; + #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM \ && defined(_GNU_SOURCE) # define MOZ_CANARY