From 7babe734dcafb5247d7b7798be59536d7eca6e4b Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Fri, 2 Aug 2013 13:19:36 -0700 Subject: [PATCH] Bug 900711 - '~nsIThreadPool can run the event loop if shutdown has not been called'. r=ehsan. --- xpcom/threads/nsThreadPool.cpp | 55 +++++++++++++++++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/xpcom/threads/nsThreadPool.cpp b/xpcom/threads/nsThreadPool.cpp index 281bd83072a..d7c128a5cc4 100644 --- a/xpcom/threads/nsThreadPool.cpp +++ b/xpcom/threads/nsThreadPool.cpp @@ -37,6 +37,24 @@ GetThreadPoolLog() #define DEFAULT_IDLE_THREAD_LIMIT 1 #define DEFAULT_IDLE_THREAD_TIMEOUT PR_SecondsToInterval(60) +class ShutdownHelper MOZ_FINAL : public nsRunnable +{ +public: + NS_DECL_NSIRUNNABLE + + ShutdownHelper(nsCOMArray& aThreads, + already_AddRefed& aListener) + : mListener(aListener) + { + MOZ_ASSERT(!aThreads.IsEmpty()); + mThreads.SwapElements(aThreads); + } + +private: + nsCOMArray mThreads; + nsCOMPtr mListener; +}; + NS_IMPL_ADDREF(nsThreadPool) NS_IMPL_RELEASE(nsThreadPool) NS_IMPL_CLASSINFO(nsThreadPool, NULL, nsIClassInfo::THREADSAFE, @@ -56,7 +74,28 @@ nsThreadPool::nsThreadPool() nsThreadPool::~nsThreadPool() { - Shutdown(); + // Calling Shutdown() directly is not safe since it will spin the event loop + // (perhaps during a GC). Instead we try to delay-shutdown each thread that is + // still alive. + nsCOMArray threads; + nsCOMPtr listener; + { + ReentrantMonitorAutoEnter mon(mEvents.GetReentrantMonitor()); + if (!mShutdown) { + NS_WARNING("nsThreadPool destroyed before Shutdown() was called!"); + + mThreads.SwapElements(threads); + mListener.swap(listener); + } + } + + if (!threads.IsEmpty()) { + nsRefPtr helper = + new ShutdownHelper(threads, listener.forget()); + if (NS_FAILED(NS_DispatchToMainThread(helper, NS_DISPATCH_NORMAL))) { + NS_WARNING("Unable to shut down threads in this thread pool!"); + } + } } nsresult @@ -374,3 +413,17 @@ nsThreadPool::SetName(const nsACString& aName) mName = aName; return NS_OK; } + +NS_IMETHODIMP +ShutdownHelper::Run() +{ + MOZ_ASSERT(!mThreads.IsEmpty()); + + for (int32_t i = 0; i < mThreads.Count(); ++i) + mThreads[i]->Shutdown(); + + mThreads.Clear(); + + mListener = nullptr; + return NS_OK; +}