Adding dynamic thread allocation to thread pool. Fixes 27736.
Also fixing warning in plevent.c r=damn, a=chofmann git-svn-id: svn://10.0.0.236/trunk@62241 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
8abdfda22f
commit
20d9d73374
@ -23,6 +23,10 @@
|
||||
#include "nsThread.h"
|
||||
#include "prmem.h"
|
||||
#include "prlog.h"
|
||||
#include "nsAutoLock.h"
|
||||
|
||||
#define NS_THREADPOOL_WAIT_INTERVAL 5000
|
||||
|
||||
|
||||
PRUintn nsThread::kIThreadSelfIndex = 0;
|
||||
static nsIThread *gMainThread = 0;
|
||||
@ -329,6 +333,7 @@ nsThreadPool::nsThreadPool(PRUint32 minThreads, PRUint32 maxThreads)
|
||||
: mMinThreads(minThreads), mMaxThreads(maxThreads), mShuttingDown(PR_FALSE)
|
||||
{
|
||||
NS_INIT_REFCNT();
|
||||
if (mMinThreads==0) mMinThreads=1;
|
||||
}
|
||||
|
||||
nsThreadPool::~nsThreadPool()
|
||||
@ -348,7 +353,7 @@ NS_IMETHODIMP
|
||||
nsThreadPool::DispatchRequest(nsIRunnable* runnable)
|
||||
{
|
||||
nsresult rv;
|
||||
PR_EnterMonitor(mRequestMonitor);
|
||||
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
nsCOMPtr<nsIThread> th;
|
||||
@ -358,30 +363,48 @@ nsThreadPool::DispatchRequest(nsIRunnable* runnable)
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
else {
|
||||
// XXX for now AppendElement returns a PRBool
|
||||
|
||||
PRUint32 requestCnt = 0, threadCount = 0;
|
||||
nsAutoMonitor mon(mRequestMonitor);
|
||||
|
||||
rv = mRequests->Count(&requestCnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
rv = mThreads->Count(&threadCount);
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
|
||||
if ((requestCnt >= threadCount) && (threadCount < mMaxThreads))
|
||||
{
|
||||
rv = AddThread();
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
}
|
||||
|
||||
rv = ((PRBool) mRequests->AppendElement(runnable)) ? NS_OK : NS_ERROR_FAILURE;
|
||||
if (NS_SUCCEEDED(rv))
|
||||
PR_Notify(mRequestMonitor);
|
||||
}
|
||||
|
||||
exit:
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThreadPool thread %p dispatching %p status %x\n", th.get(), runnable, rv));
|
||||
PR_ExitMonitor(mRequestMonitor);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsIRunnable*
|
||||
nsThreadPool::GetRequest()
|
||||
nsThreadPool::GetRequest(nsIThread *thread)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
nsIRunnable* request = nsnull;
|
||||
|
||||
PR_EnterMonitor(mRequestMonitor);
|
||||
nsAutoMonitor mon(mRequestMonitor);
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
nsCOMPtr<nsIThread> th;
|
||||
nsIThread::GetCurrent(getter_AddRefs(th));
|
||||
#endif
|
||||
|
||||
PRUint32 cnt;
|
||||
PRUint32 threadCnt;
|
||||
while (PR_TRUE) {
|
||||
rv = mRequests->Count(&cnt);
|
||||
if (NS_FAILED(rv) || cnt != 0)
|
||||
@ -391,9 +414,41 @@ nsThreadPool::GetRequest()
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThreadPool thread %p waiting\n", th.get()));
|
||||
PRStatus status = PR_Wait(mRequestMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
("nsIThreadPool thread %p waiting for %d\n", th.get(),
|
||||
NS_THREADPOOL_WAIT_INTERVAL));
|
||||
|
||||
PRStatus status = PR_Wait( mRequestMonitor,
|
||||
PR_MillisecondsToInterval(NS_THREADPOOL_WAIT_INTERVAL));
|
||||
|
||||
if (status != PR_SUCCESS || mShuttingDown) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( NS_SUCCEEDED(mRequests->Count(&cnt)) && cnt > 0 )
|
||||
break;
|
||||
|
||||
// no requests yet. check to see if we should go away.
|
||||
rv = mThreads->Count(&threadCnt);
|
||||
|
||||
if (NS_FAILED(rv)) break;
|
||||
|
||||
if (threadCnt > mMinThreads )
|
||||
{
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThreadPool thread %p being removed\n", th.get()));
|
||||
|
||||
RemoveThread(thread);
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThreadPool thread %p waiting indefinite\n", th.get()));
|
||||
|
||||
status = PR_Wait(mRequestMonitor, PR_INTERVAL_NO_TIMEOUT);
|
||||
if (status != PR_SUCCESS || mShuttingDown) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
break;
|
||||
@ -411,7 +466,7 @@ nsThreadPool::GetRequest()
|
||||
}
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThreadPool thread %p got request %p\n", th.get(), request));
|
||||
PR_ExitMonitor(mRequestMonitor);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
@ -493,8 +548,12 @@ nsThreadPool::Init(PRUint32 stackSize,
|
||||
PRThreadPriority priority,
|
||||
PRThreadScope scope)
|
||||
{
|
||||
nsresult rv;
|
||||
mStackSize = stackSize;
|
||||
mPriority = priority;
|
||||
mScope = scope;
|
||||
|
||||
nsresult rv;
|
||||
|
||||
rv = NS_NewISupportsArray(getter_AddRefs(mThreads));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
@ -505,35 +564,70 @@ nsThreadPool::Init(PRUint32 stackSize,
|
||||
if (mRequestMonitor == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
PR_CEnterMonitor(this);
|
||||
|
||||
for (PRUint32 i = 0; i < mMinThreads; i++) {
|
||||
nsThreadPoolRunnable* runnable =
|
||||
new nsThreadPoolRunnable(this);
|
||||
if (runnable == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(runnable);
|
||||
|
||||
nsIThread* thread;
|
||||
|
||||
rv = NS_NewThread(&thread, runnable, stackSize,
|
||||
PR_JOINABLE_THREAD, /* needed for Shutdown */
|
||||
priority, scope);
|
||||
NS_RELEASE(runnable);
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
|
||||
rv = mThreads->AppendElement(thread) ? NS_OK : NS_ERROR_FAILURE;
|
||||
NS_RELEASE(thread);
|
||||
if (NS_FAILED(rv)) goto exit;
|
||||
}
|
||||
// wait for some worker thread to be ready
|
||||
PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
exit:
|
||||
PR_CExitMonitor(this);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsThreadPool::AddThread()
|
||||
{
|
||||
PRUint32 cnt;
|
||||
nsresult rv = mThreads->Count(&cnt);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (cnt >= mMaxThreads)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
nsThreadPoolRunnable* runnable = new nsThreadPoolRunnable(this);
|
||||
if (runnable == nsnull)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
NS_ADDREF(runnable);
|
||||
|
||||
nsIThread* thread;
|
||||
|
||||
rv = NS_NewThread(&thread,
|
||||
runnable,
|
||||
mStackSize,
|
||||
PR_JOINABLE_THREAD, /* needed for Shutdown */
|
||||
mPriority,
|
||||
mScope);
|
||||
|
||||
// wait for worker thread to be ready
|
||||
PR_CWait(this, PR_INTERVAL_NO_TIMEOUT);
|
||||
|
||||
NS_RELEASE(runnable);
|
||||
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mThreads->AppendElement(thread) ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
||||
NS_RELEASE(thread);
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsThreadPool::RemoveThread(nsIThread *inThread)
|
||||
{
|
||||
PRUint32 count, i;
|
||||
|
||||
nsresult rv = mThreads->Count(&count);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "Count failed");
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
nsIThread* thread = (nsIThread*)(mThreads->ElementAt(i));
|
||||
if (thread == inThread)
|
||||
{
|
||||
NS_RELEASE(thread);
|
||||
rv = mThreads->RemoveElementAt(i);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "RemoveElementAt failed");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
NS_COM nsresult
|
||||
NS_NewThreadPool(nsIThreadPool* *result,
|
||||
PRUint32 minThreads, PRUint32 maxThreads,
|
||||
@ -584,11 +678,10 @@ nsThreadPoolRunnable::Run()
|
||||
PR_CNotify(mPool);
|
||||
PR_CExitMonitor(mPool);
|
||||
|
||||
#if defined(PR_LOGGING)
|
||||
nsCOMPtr<nsIThread> th;
|
||||
nsIThread::GetCurrent(getter_AddRefs(th));
|
||||
#endif
|
||||
while ((request = mPool->GetRequest()) != nsnull) {
|
||||
|
||||
while ((request = mPool->GetRequest(th)) != nsnull) {
|
||||
PR_LOG(nsIThreadLog, PR_LOG_DEBUG,
|
||||
("nsIThreadPool thread %p running %p\n", th.get(), request));
|
||||
rv = request->Run();
|
||||
|
||||
@ -72,7 +72,7 @@ public:
|
||||
nsThreadPool(PRUint32 minThreads, PRUint32 maxThreads);
|
||||
virtual ~nsThreadPool();
|
||||
|
||||
nsIRunnable* GetRequest();
|
||||
nsIRunnable* GetRequest(nsIThread* thread);
|
||||
|
||||
static NS_METHOD Create(nsISupports* outer, const nsIID& aIID, void* *aInstancePtr);
|
||||
|
||||
@ -80,9 +80,17 @@ protected:
|
||||
nsCOMPtr<nsISupportsArray> mThreads;
|
||||
nsCOMPtr<nsISupportsArray> mRequests;
|
||||
PRMonitor* mRequestMonitor;
|
||||
|
||||
PRUint32 mStackSize;
|
||||
PRThreadPriority mPriority;
|
||||
PRThreadScope mScope;
|
||||
|
||||
PRUint32 mMinThreads;
|
||||
PRUint32 mMaxThreads;
|
||||
PRBool mShuttingDown;
|
||||
|
||||
nsresult AddThread();
|
||||
nsresult RemoveThread(nsIThread *inThread);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -465,7 +465,10 @@ PR_IMPLEMENT(void)
|
||||
PL_ProcessPendingEvents(PLEventQueue* self)
|
||||
{
|
||||
PRInt32 count;
|
||||
|
||||
#ifdef XP_UNIX
|
||||
PRCList* node;
|
||||
#endif
|
||||
|
||||
if (self == NULL)
|
||||
return;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user