diff --git a/mozilla/base/public/nsIThread.h b/mozilla/base/public/nsIThread.h index 4957301372d..f662e54897a 100644 --- a/mozilla/base/public/nsIThread.h +++ b/mozilla/base/public/nsIThread.h @@ -73,7 +73,6 @@ public: NS_IMETHOD Interrupt() = 0; NS_IMETHOD GetScope(PRThreadScope *result) = 0; - NS_IMETHOD GetType(PRThreadType *result) = 0; NS_IMETHOD GetState(PRThreadState *result) = 0; NS_IMETHOD GetPRThread(PRThread* *result) = 0; @@ -83,7 +82,6 @@ extern NS_BASE nsresult NS_NewThread(nsIThread* *result, nsIRunnable* runnable, PRUint32 stackSize = 0, - PRThreadType type = PR_USER_THREAD, PRThreadPriority priority = PR_PRIORITY_NORMAL, PRThreadScope scope = PR_GLOBAL_THREAD, PRThreadState state = PR_JOINABLE_THREAD); @@ -111,6 +109,8 @@ public: NS_IMETHOD DispatchRequest(nsIRunnable* runnable) = 0; + NS_IMETHOD ProcessPendingRequests() = 0; + NS_IMETHOD Shutdown() = 0; }; @@ -118,10 +118,8 @@ extern NS_BASE nsresult NS_NewThreadPool(nsIThreadPool* *result, PRUint32 minThreads, PRUint32 maxThreads, PRUint32 stackSize = 0, - PRThreadType type = PR_USER_THREAD, PRThreadPriority priority = PR_PRIORITY_NORMAL, - PRThreadScope scope = PR_GLOBAL_THREAD, - PRThreadState state = PR_JOINABLE_THREAD); + PRThreadScope scope = PR_GLOBAL_THREAD); //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/base/src/nsThread.cpp b/mozilla/base/src/nsThread.cpp index 383eb397919..f9a5630fe9a 100644 --- a/mozilla/base/src/nsThread.cpp +++ b/mozilla/base/src/nsThread.cpp @@ -18,13 +18,14 @@ #include "nsThread.h" #include "prmem.h" +//#include -PRUintn nsThread::kIThreadSelf = 0; +PRUintn nsThread::kIThreadSelfIndex = 0; //////////////////////////////////////////////////////////////////////////////// nsThread::nsThread() - : mThread(nsnull), mRunnable(nsnull) + : mThread(nsnull), mRunnable(nsnull), mDead(PR_FALSE) { NS_INIT_REFCNT(); } @@ -32,7 +33,6 @@ nsThread::nsThread() nsresult nsThread::Init(nsIRunnable* runnable, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, PRThreadScope scope, PRThreadState state) @@ -40,9 +40,12 @@ nsThread::Init(nsIRunnable* runnable, mRunnable = runnable; NS_ADDREF(mRunnable); - NS_ADDREF_THIS(); // released in nsIThread::Exit - mThread = PR_CreateThread(type, Main, this, - priority, scope, PR_JOINABLE_THREAD, stackSize); + NS_ADDREF_THIS(); // released in nsThread::Exit + if (state == PR_JOINABLE_THREAD) + NS_ADDREF_THIS(); // released in nsThread::Join + mThread = PR_CreateThread(PR_USER_THREAD, Main, this, + priority, scope, state, stackSize); +// printf("%x %x (%d) create\n", this, mThread, mRefCnt); if (mThread == nsnull) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; @@ -50,6 +53,7 @@ nsThread::Init(nsIRunnable* runnable, nsThread::~nsThread() { +// printf("%x %x (%d) destroy\n", this, mThread, mRefCnt); NS_IF_RELEASE(mRunnable); } @@ -62,14 +66,13 @@ nsThread::Main(void* arg) rv = self->RegisterThreadSelf(); NS_ASSERTION(rv == NS_OK, "failed to set thread self"); +// printf("%x %x (%d) start run\n", self, self->mThread, self->mRefCnt); rv = self->mRunnable->Run(); NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed"); PRThreadState state; rv = self->GetState(&state); - if (NS_SUCCEEDED(rv) && state == PR_UNJOINABLE_THREAD) { - Exit(arg); - } +// printf("%x %x (%d) end run\n", self, self->mThread, self->mRefCnt); } void @@ -77,7 +80,8 @@ nsThread::Exit(void* arg) { nsThread* self = (nsThread*)arg; nsresult rv = NS_OK; - self->mThread = nsnull; + self->mDead = PR_TRUE; +// printf("%x %x (%d) exit\n", self, self->mThread, self->mRefCnt - 1); NS_RELEASE(self); } @@ -86,16 +90,26 @@ NS_IMPL_ISUPPORTS(nsThread, nsIThread::GetIID()); NS_IMETHODIMP nsThread::Join() { - if (mThread == nsnull) - return NS_ERROR_FAILURE; + // don't check for mDead here because nspr calls Exit (cleaning up + // thread-local storage) before they let us join with the thread + +// printf("%x %x (%d) start join\n", this, mThread, mRefCnt); PRStatus status = PR_JoinThread(mThread); - return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; + // XXX can't use NS_RELEASE here because the macro wants to set + // this to null (bad c++) +// printf("%x %x (%d) end join\n", this, mThread, mRefCnt); + if (status == PR_SUCCESS) { + this->Release(); // most likely the final release of this thread + return NS_OK; + } + else + return NS_ERROR_FAILURE; } NS_IMETHODIMP nsThread::GetPriority(PRThreadPriority *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = PR_GetThreadPriority(mThread); return NS_OK; @@ -104,7 +118,7 @@ nsThread::GetPriority(PRThreadPriority *result) NS_IMETHODIMP nsThread::SetPriority(PRThreadPriority value) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; PR_SetThreadPriority(mThread, value); return NS_OK; @@ -113,7 +127,7 @@ nsThread::SetPriority(PRThreadPriority value) NS_IMETHODIMP nsThread::Interrupt() { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; PRStatus status = PR_Interrupt(mThread); return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; @@ -122,25 +136,16 @@ nsThread::Interrupt() NS_IMETHODIMP nsThread::GetScope(PRThreadScope *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = PR_GetThreadScope(mThread); return NS_OK; } -NS_IMETHODIMP -nsThread::GetType(PRThreadType *result) -{ - if (mThread == nsnull) - return NS_ERROR_FAILURE; - *result = PR_GetThreadType(mThread); - return NS_OK; -} - NS_IMETHODIMP nsThread::GetState(PRThreadState *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = PR_GetThreadState(mThread); return NS_OK; @@ -149,7 +154,7 @@ nsThread::GetState(PRThreadState *result) NS_IMETHODIMP nsThread::GetPRThread(PRThread* *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = mThread; return NS_OK; @@ -159,7 +164,6 @@ NS_BASE nsresult NS_NewThread(nsIThread* *result, nsIRunnable* runnable, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, PRThreadScope scope, PRThreadState state) @@ -169,7 +173,7 @@ NS_NewThread(nsIThread* *result, if (thread == nsnull) return NS_ERROR_OUT_OF_MEMORY; - rv = thread->Init(runnable, stackSize, type, priority, scope, state); + rv = thread->Init(runnable, stackSize, priority, scope, state); if (NS_FAILED(rv)) { delete thread; return rv; @@ -187,13 +191,13 @@ nsThread::RegisterThreadSelf() { PRStatus status; - if (kIThreadSelf == 0) { - status = PR_NewThreadPrivateIndex(&kIThreadSelf, Exit); + if (kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit); if (status != PR_SUCCESS) return NS_ERROR_FAILURE; - NS_ASSERTION(kIThreadSelf != 0, "couldn't get thread private index"); + NS_ASSERTION(kIThreadSelfIndex != 0, "couldn't get thread private index"); } - status = PR_SetThreadPrivate(kIThreadSelf, this); + status = PR_SetThreadPrivate(kIThreadSelfIndex, this); if (status != PR_SUCCESS) return NS_ERROR_FAILURE; return NS_OK; @@ -211,13 +215,13 @@ nsIThread::GetIThread(PRThread* prthread, nsIThread* *result) PRStatus status; nsThread* thread; - if (nsThread::kIThreadSelf == 0) { - status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelf, nsThread::Exit); + if (nsThread::kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit); if (status != PR_SUCCESS) return NS_ERROR_FAILURE; - NS_ASSERTION(nsThread::kIThreadSelf != 0, "couldn't get thread private index"); + NS_ASSERTION(nsThread::kIThreadSelfIndex != 0, "couldn't get thread private index"); } - thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelf); + thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex); if (thread == nsnull) { // if the current thread doesn't have an nsIThread associated // with it, make one @@ -245,10 +249,8 @@ nsThreadPool::nsThreadPool(PRUint32 minThreads, PRUint32 maxThreads) nsresult nsThreadPool::Init(PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state) + PRThreadScope scope) { nsresult rv; @@ -273,8 +275,8 @@ nsThreadPool::Init(PRUint32 stackSize, nsIThread* thread; - rv = NS_NewThread(&thread, runnable, stackSize, PR_SYSTEM_THREAD, - priority, scope, state); + rv = NS_NewThread(&thread, runnable, stackSize, priority, scope, + PR_JOINABLE_THREAD); // needed for Shutdown NS_RELEASE(runnable); if (NS_FAILED(rv)) goto exit; @@ -292,15 +294,8 @@ nsThreadPool::Init(PRUint32 stackSize, nsThreadPool::~nsThreadPool() { - Shutdown(); if (mThreads) { - // clean up the worker threads - PRUint32 count = mThreads->Count(); - for (PRUint32 i = 0; i < count; i++) { - nsIThread* thread = (nsIThread*)((*mThreads)[i]); - thread->Interrupt(); - thread->Join(); // XXX race? - } + Shutdown(); NS_RELEASE(mThreads); } @@ -331,8 +326,6 @@ nsThreadPool::DispatchRequest(nsIRunnable* runnable) return rv; } -#include - nsIRunnable* nsThreadPool::GetRequest() { @@ -367,14 +360,11 @@ nsThreadPool::GetRequest() } NS_IMETHODIMP -nsThreadPool::Shutdown() +nsThreadPool::ProcessPendingRequests() { - nsresult rv = NS_OK; - PRUint32 count; - PRUint32 i; - - // first wait for any outstanding requests to be processed + nsresult rv; PR_CEnterMonitor(this); + while (mRequests->Count() > 0) { PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT); if (status != PR_SUCCESS) { @@ -382,21 +372,38 @@ nsThreadPool::Shutdown() break; } } + PR_CExitMonitor(this); - if (NS_FAILED(rv)) return rv; + return rv; +} + +NS_IMETHODIMP +nsThreadPool::Shutdown() +{ + nsresult rv = NS_OK; + PRUint32 count; + PRUint32 i; mShuttingDown = PR_TRUE; + ProcessPendingRequests(); // then interrupt the threads and join them count = mThreads->Count(); for (i = 0; i < count; i++) { nsIThread* thread = (nsIThread*)((*mThreads)[0]); - rv = thread->Interrupt(); - if (NS_FAILED(rv)) return rv; + + // we don't care about the error from Interrupt, because the + // thread may have already terminated its event loop + (void)thread->Interrupt(); + rv = thread->Join(); - if (NS_FAILED(rv)) return rv; + // don't break out of the loop because of an error here + NS_ASSERTION(NS_SUCCEEDED(rv), "Join failed"); + + NS_RELEASE(thread); rv = mThreads->RemoveElementAt(0); - if (NS_FAILED(rv)) return rv; + // don't break out of the loop because of an error here + NS_ASSERTION(NS_SUCCEEDED(rv), "RemoveElementAt failed"); } return rv; @@ -406,17 +413,15 @@ NS_BASE nsresult NS_NewThreadPool(nsIThreadPool* *result, PRUint32 minThreads, PRUint32 maxThreads, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state) + PRThreadScope scope) { nsresult rv; nsThreadPool* pool = new nsThreadPool(minThreads, maxThreads); if (pool == nsnull) return NS_ERROR_OUT_OF_MEMORY; - rv = pool->Init(stackSize, type, priority, scope, state); + rv = pool->Init(stackSize, priority, scope); if (NS_FAILED(rv)) { delete pool; return rv; diff --git a/mozilla/base/src/nsThread.h b/mozilla/base/src/nsThread.h index 4f296aaa7cd..e3e902430cf 100644 --- a/mozilla/base/src/nsThread.h +++ b/mozilla/base/src/nsThread.h @@ -33,7 +33,6 @@ public: NS_IMETHOD SetPriority(PRThreadPriority value); NS_IMETHOD Interrupt(); NS_IMETHOD GetScope(PRThreadScope *result); - NS_IMETHOD GetType(PRThreadType *result); NS_IMETHOD GetState(PRThreadState *result); NS_IMETHOD GetPRThread(PRThread* *result); @@ -43,7 +42,6 @@ public: nsresult Init(nsIRunnable* runnable, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, PRThreadScope scope, PRThreadState state); @@ -53,11 +51,12 @@ public: static void Main(void* arg); static void Exit(void* arg); - static PRUintn kIThreadSelf; + static PRUintn kIThreadSelfIndex; protected: PRThread* mThread; nsIRunnable* mRunnable; + PRBool mDead; }; //////////////////////////////////////////////////////////////////////////////// @@ -69,6 +68,7 @@ public: // nsIThreadPool methods: NS_IMETHOD DispatchRequest(nsIRunnable* runnable); + NS_IMETHOD ProcessPendingRequests(); NS_IMETHOD Shutdown(); // nsThreadPool methods: @@ -76,10 +76,8 @@ public: virtual ~nsThreadPool(); nsresult Init(PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state); + PRThreadScope scope); nsIRunnable* GetRequest(); protected: diff --git a/mozilla/base/tests/TestThreads.cpp b/mozilla/base/tests/TestThreads.cpp index a9dc3c4b37a..11b983af568 100644 --- a/mozilla/base/tests/TestThreads.cpp +++ b/mozilla/base/tests/TestThreads.cpp @@ -95,7 +95,7 @@ TestThreads() //////////////////////////////////////////////////////////////////////////// // try an unjoinable thread - rv = NS_NewThread(&runner, new nsRunner(1), 0, PR_USER_THREAD, + rv = NS_NewThread(&runner, new nsRunner(1), 0, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD); if (NS_FAILED(rv)) { printf("failed to create thread\n"); @@ -124,7 +124,7 @@ TestThreadPools() for (PRUint32 i = 0; i < 100; i++) { rv = pool->DispatchRequest(new nsRunner(i+2)); } - rv = pool->Join(); + rv = pool->Shutdown(); return rv; } diff --git a/mozilla/xpcom/tests/TestThreads.cpp b/mozilla/xpcom/tests/TestThreads.cpp index a9dc3c4b37a..11b983af568 100644 --- a/mozilla/xpcom/tests/TestThreads.cpp +++ b/mozilla/xpcom/tests/TestThreads.cpp @@ -95,7 +95,7 @@ TestThreads() //////////////////////////////////////////////////////////////////////////// // try an unjoinable thread - rv = NS_NewThread(&runner, new nsRunner(1), 0, PR_USER_THREAD, + rv = NS_NewThread(&runner, new nsRunner(1), 0, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD); if (NS_FAILED(rv)) { printf("failed to create thread\n"); @@ -124,7 +124,7 @@ TestThreadPools() for (PRUint32 i = 0; i < 100; i++) { rv = pool->DispatchRequest(new nsRunner(i+2)); } - rv = pool->Join(); + rv = pool->Shutdown(); return rv; } diff --git a/mozilla/xpcom/threads/nsIThread.h b/mozilla/xpcom/threads/nsIThread.h index 4957301372d..f662e54897a 100644 --- a/mozilla/xpcom/threads/nsIThread.h +++ b/mozilla/xpcom/threads/nsIThread.h @@ -73,7 +73,6 @@ public: NS_IMETHOD Interrupt() = 0; NS_IMETHOD GetScope(PRThreadScope *result) = 0; - NS_IMETHOD GetType(PRThreadType *result) = 0; NS_IMETHOD GetState(PRThreadState *result) = 0; NS_IMETHOD GetPRThread(PRThread* *result) = 0; @@ -83,7 +82,6 @@ extern NS_BASE nsresult NS_NewThread(nsIThread* *result, nsIRunnable* runnable, PRUint32 stackSize = 0, - PRThreadType type = PR_USER_THREAD, PRThreadPriority priority = PR_PRIORITY_NORMAL, PRThreadScope scope = PR_GLOBAL_THREAD, PRThreadState state = PR_JOINABLE_THREAD); @@ -111,6 +109,8 @@ public: NS_IMETHOD DispatchRequest(nsIRunnable* runnable) = 0; + NS_IMETHOD ProcessPendingRequests() = 0; + NS_IMETHOD Shutdown() = 0; }; @@ -118,10 +118,8 @@ extern NS_BASE nsresult NS_NewThreadPool(nsIThreadPool* *result, PRUint32 minThreads, PRUint32 maxThreads, PRUint32 stackSize = 0, - PRThreadType type = PR_USER_THREAD, PRThreadPriority priority = PR_PRIORITY_NORMAL, - PRThreadScope scope = PR_GLOBAL_THREAD, - PRThreadState state = PR_JOINABLE_THREAD); + PRThreadScope scope = PR_GLOBAL_THREAD); //////////////////////////////////////////////////////////////////////////////// diff --git a/mozilla/xpcom/threads/nsThread.cpp b/mozilla/xpcom/threads/nsThread.cpp index 383eb397919..f9a5630fe9a 100644 --- a/mozilla/xpcom/threads/nsThread.cpp +++ b/mozilla/xpcom/threads/nsThread.cpp @@ -18,13 +18,14 @@ #include "nsThread.h" #include "prmem.h" +//#include -PRUintn nsThread::kIThreadSelf = 0; +PRUintn nsThread::kIThreadSelfIndex = 0; //////////////////////////////////////////////////////////////////////////////// nsThread::nsThread() - : mThread(nsnull), mRunnable(nsnull) + : mThread(nsnull), mRunnable(nsnull), mDead(PR_FALSE) { NS_INIT_REFCNT(); } @@ -32,7 +33,6 @@ nsThread::nsThread() nsresult nsThread::Init(nsIRunnable* runnable, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, PRThreadScope scope, PRThreadState state) @@ -40,9 +40,12 @@ nsThread::Init(nsIRunnable* runnable, mRunnable = runnable; NS_ADDREF(mRunnable); - NS_ADDREF_THIS(); // released in nsIThread::Exit - mThread = PR_CreateThread(type, Main, this, - priority, scope, PR_JOINABLE_THREAD, stackSize); + NS_ADDREF_THIS(); // released in nsThread::Exit + if (state == PR_JOINABLE_THREAD) + NS_ADDREF_THIS(); // released in nsThread::Join + mThread = PR_CreateThread(PR_USER_THREAD, Main, this, + priority, scope, state, stackSize); +// printf("%x %x (%d) create\n", this, mThread, mRefCnt); if (mThread == nsnull) return NS_ERROR_OUT_OF_MEMORY; return NS_OK; @@ -50,6 +53,7 @@ nsThread::Init(nsIRunnable* runnable, nsThread::~nsThread() { +// printf("%x %x (%d) destroy\n", this, mThread, mRefCnt); NS_IF_RELEASE(mRunnable); } @@ -62,14 +66,13 @@ nsThread::Main(void* arg) rv = self->RegisterThreadSelf(); NS_ASSERTION(rv == NS_OK, "failed to set thread self"); +// printf("%x %x (%d) start run\n", self, self->mThread, self->mRefCnt); rv = self->mRunnable->Run(); NS_ASSERTION(NS_SUCCEEDED(rv), "runnable failed"); PRThreadState state; rv = self->GetState(&state); - if (NS_SUCCEEDED(rv) && state == PR_UNJOINABLE_THREAD) { - Exit(arg); - } +// printf("%x %x (%d) end run\n", self, self->mThread, self->mRefCnt); } void @@ -77,7 +80,8 @@ nsThread::Exit(void* arg) { nsThread* self = (nsThread*)arg; nsresult rv = NS_OK; - self->mThread = nsnull; + self->mDead = PR_TRUE; +// printf("%x %x (%d) exit\n", self, self->mThread, self->mRefCnt - 1); NS_RELEASE(self); } @@ -86,16 +90,26 @@ NS_IMPL_ISUPPORTS(nsThread, nsIThread::GetIID()); NS_IMETHODIMP nsThread::Join() { - if (mThread == nsnull) - return NS_ERROR_FAILURE; + // don't check for mDead here because nspr calls Exit (cleaning up + // thread-local storage) before they let us join with the thread + +// printf("%x %x (%d) start join\n", this, mThread, mRefCnt); PRStatus status = PR_JoinThread(mThread); - return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; + // XXX can't use NS_RELEASE here because the macro wants to set + // this to null (bad c++) +// printf("%x %x (%d) end join\n", this, mThread, mRefCnt); + if (status == PR_SUCCESS) { + this->Release(); // most likely the final release of this thread + return NS_OK; + } + else + return NS_ERROR_FAILURE; } NS_IMETHODIMP nsThread::GetPriority(PRThreadPriority *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = PR_GetThreadPriority(mThread); return NS_OK; @@ -104,7 +118,7 @@ nsThread::GetPriority(PRThreadPriority *result) NS_IMETHODIMP nsThread::SetPriority(PRThreadPriority value) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; PR_SetThreadPriority(mThread, value); return NS_OK; @@ -113,7 +127,7 @@ nsThread::SetPriority(PRThreadPriority value) NS_IMETHODIMP nsThread::Interrupt() { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; PRStatus status = PR_Interrupt(mThread); return status == PR_SUCCESS ? NS_OK : NS_ERROR_FAILURE; @@ -122,25 +136,16 @@ nsThread::Interrupt() NS_IMETHODIMP nsThread::GetScope(PRThreadScope *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = PR_GetThreadScope(mThread); return NS_OK; } -NS_IMETHODIMP -nsThread::GetType(PRThreadType *result) -{ - if (mThread == nsnull) - return NS_ERROR_FAILURE; - *result = PR_GetThreadType(mThread); - return NS_OK; -} - NS_IMETHODIMP nsThread::GetState(PRThreadState *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = PR_GetThreadState(mThread); return NS_OK; @@ -149,7 +154,7 @@ nsThread::GetState(PRThreadState *result) NS_IMETHODIMP nsThread::GetPRThread(PRThread* *result) { - if (mThread == nsnull) + if (mDead) return NS_ERROR_FAILURE; *result = mThread; return NS_OK; @@ -159,7 +164,6 @@ NS_BASE nsresult NS_NewThread(nsIThread* *result, nsIRunnable* runnable, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, PRThreadScope scope, PRThreadState state) @@ -169,7 +173,7 @@ NS_NewThread(nsIThread* *result, if (thread == nsnull) return NS_ERROR_OUT_OF_MEMORY; - rv = thread->Init(runnable, stackSize, type, priority, scope, state); + rv = thread->Init(runnable, stackSize, priority, scope, state); if (NS_FAILED(rv)) { delete thread; return rv; @@ -187,13 +191,13 @@ nsThread::RegisterThreadSelf() { PRStatus status; - if (kIThreadSelf == 0) { - status = PR_NewThreadPrivateIndex(&kIThreadSelf, Exit); + if (kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&kIThreadSelfIndex, Exit); if (status != PR_SUCCESS) return NS_ERROR_FAILURE; - NS_ASSERTION(kIThreadSelf != 0, "couldn't get thread private index"); + NS_ASSERTION(kIThreadSelfIndex != 0, "couldn't get thread private index"); } - status = PR_SetThreadPrivate(kIThreadSelf, this); + status = PR_SetThreadPrivate(kIThreadSelfIndex, this); if (status != PR_SUCCESS) return NS_ERROR_FAILURE; return NS_OK; @@ -211,13 +215,13 @@ nsIThread::GetIThread(PRThread* prthread, nsIThread* *result) PRStatus status; nsThread* thread; - if (nsThread::kIThreadSelf == 0) { - status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelf, nsThread::Exit); + if (nsThread::kIThreadSelfIndex == 0) { + status = PR_NewThreadPrivateIndex(&nsThread::kIThreadSelfIndex, nsThread::Exit); if (status != PR_SUCCESS) return NS_ERROR_FAILURE; - NS_ASSERTION(nsThread::kIThreadSelf != 0, "couldn't get thread private index"); + NS_ASSERTION(nsThread::kIThreadSelfIndex != 0, "couldn't get thread private index"); } - thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelf); + thread = (nsThread*)PR_GetThreadPrivate(nsThread::kIThreadSelfIndex); if (thread == nsnull) { // if the current thread doesn't have an nsIThread associated // with it, make one @@ -245,10 +249,8 @@ nsThreadPool::nsThreadPool(PRUint32 minThreads, PRUint32 maxThreads) nsresult nsThreadPool::Init(PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state) + PRThreadScope scope) { nsresult rv; @@ -273,8 +275,8 @@ nsThreadPool::Init(PRUint32 stackSize, nsIThread* thread; - rv = NS_NewThread(&thread, runnable, stackSize, PR_SYSTEM_THREAD, - priority, scope, state); + rv = NS_NewThread(&thread, runnable, stackSize, priority, scope, + PR_JOINABLE_THREAD); // needed for Shutdown NS_RELEASE(runnable); if (NS_FAILED(rv)) goto exit; @@ -292,15 +294,8 @@ nsThreadPool::Init(PRUint32 stackSize, nsThreadPool::~nsThreadPool() { - Shutdown(); if (mThreads) { - // clean up the worker threads - PRUint32 count = mThreads->Count(); - for (PRUint32 i = 0; i < count; i++) { - nsIThread* thread = (nsIThread*)((*mThreads)[i]); - thread->Interrupt(); - thread->Join(); // XXX race? - } + Shutdown(); NS_RELEASE(mThreads); } @@ -331,8 +326,6 @@ nsThreadPool::DispatchRequest(nsIRunnable* runnable) return rv; } -#include - nsIRunnable* nsThreadPool::GetRequest() { @@ -367,14 +360,11 @@ nsThreadPool::GetRequest() } NS_IMETHODIMP -nsThreadPool::Shutdown() +nsThreadPool::ProcessPendingRequests() { - nsresult rv = NS_OK; - PRUint32 count; - PRUint32 i; - - // first wait for any outstanding requests to be processed + nsresult rv; PR_CEnterMonitor(this); + while (mRequests->Count() > 0) { PRStatus status = PR_CWait(this, PR_INTERVAL_NO_TIMEOUT); if (status != PR_SUCCESS) { @@ -382,21 +372,38 @@ nsThreadPool::Shutdown() break; } } + PR_CExitMonitor(this); - if (NS_FAILED(rv)) return rv; + return rv; +} + +NS_IMETHODIMP +nsThreadPool::Shutdown() +{ + nsresult rv = NS_OK; + PRUint32 count; + PRUint32 i; mShuttingDown = PR_TRUE; + ProcessPendingRequests(); // then interrupt the threads and join them count = mThreads->Count(); for (i = 0; i < count; i++) { nsIThread* thread = (nsIThread*)((*mThreads)[0]); - rv = thread->Interrupt(); - if (NS_FAILED(rv)) return rv; + + // we don't care about the error from Interrupt, because the + // thread may have already terminated its event loop + (void)thread->Interrupt(); + rv = thread->Join(); - if (NS_FAILED(rv)) return rv; + // don't break out of the loop because of an error here + NS_ASSERTION(NS_SUCCEEDED(rv), "Join failed"); + + NS_RELEASE(thread); rv = mThreads->RemoveElementAt(0); - if (NS_FAILED(rv)) return rv; + // don't break out of the loop because of an error here + NS_ASSERTION(NS_SUCCEEDED(rv), "RemoveElementAt failed"); } return rv; @@ -406,17 +413,15 @@ NS_BASE nsresult NS_NewThreadPool(nsIThreadPool* *result, PRUint32 minThreads, PRUint32 maxThreads, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state) + PRThreadScope scope) { nsresult rv; nsThreadPool* pool = new nsThreadPool(minThreads, maxThreads); if (pool == nsnull) return NS_ERROR_OUT_OF_MEMORY; - rv = pool->Init(stackSize, type, priority, scope, state); + rv = pool->Init(stackSize, priority, scope); if (NS_FAILED(rv)) { delete pool; return rv; diff --git a/mozilla/xpcom/threads/nsThread.h b/mozilla/xpcom/threads/nsThread.h index 4f296aaa7cd..e3e902430cf 100644 --- a/mozilla/xpcom/threads/nsThread.h +++ b/mozilla/xpcom/threads/nsThread.h @@ -33,7 +33,6 @@ public: NS_IMETHOD SetPriority(PRThreadPriority value); NS_IMETHOD Interrupt(); NS_IMETHOD GetScope(PRThreadScope *result); - NS_IMETHOD GetType(PRThreadType *result); NS_IMETHOD GetState(PRThreadState *result); NS_IMETHOD GetPRThread(PRThread* *result); @@ -43,7 +42,6 @@ public: nsresult Init(nsIRunnable* runnable, PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, PRThreadScope scope, PRThreadState state); @@ -53,11 +51,12 @@ public: static void Main(void* arg); static void Exit(void* arg); - static PRUintn kIThreadSelf; + static PRUintn kIThreadSelfIndex; protected: PRThread* mThread; nsIRunnable* mRunnable; + PRBool mDead; }; //////////////////////////////////////////////////////////////////////////////// @@ -69,6 +68,7 @@ public: // nsIThreadPool methods: NS_IMETHOD DispatchRequest(nsIRunnable* runnable); + NS_IMETHOD ProcessPendingRequests(); NS_IMETHOD Shutdown(); // nsThreadPool methods: @@ -76,10 +76,8 @@ public: virtual ~nsThreadPool(); nsresult Init(PRUint32 stackSize, - PRThreadType type, PRThreadPriority priority, - PRThreadScope scope, - PRThreadState state); + PRThreadScope scope); nsIRunnable* GetRequest(); protected: