fix some bugs
git-svn-id: svn://10.0.0.236/branches/THREADS_20060213_BRANCH@189907 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
nsTaskQueue::nsTaskQueue()
|
||||
: mMonitor(nsAutoMonitor::NewMonitor("TaskQueue"))
|
||||
: mMonitor(nsAutoMonitor::NewMonitor("xpcom.taskqueue"))
|
||||
, mHead(nsnull)
|
||||
, mTail(nsnull)
|
||||
, mOffsetHead(0)
|
||||
@@ -75,7 +75,7 @@ nsTaskQueue::GetPendingTask(PRBool wait, nsIRunnable **result)
|
||||
if (mOffsetHead == TASKS_PER_PAGE) {
|
||||
Page *dead = mHead;
|
||||
mHead = mHead->mNext;
|
||||
delete dead;
|
||||
FreePage(dead);
|
||||
mOffsetHead = 0;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ nsTaskQueue::PutTask(nsIRunnable *runnable)
|
||||
nsAutoMonitor mon(mMonitor);
|
||||
|
||||
if (!mHead) {
|
||||
mHead = new Page();
|
||||
mHead = NewPage();
|
||||
if (!mHead) {
|
||||
rv = PR_FALSE;
|
||||
} else {
|
||||
@@ -101,7 +101,7 @@ nsTaskQueue::PutTask(nsIRunnable *runnable)
|
||||
mOffsetTail = 0;
|
||||
}
|
||||
} else if (mOffsetTail == TASKS_PER_PAGE) {
|
||||
Page *page = new Page();
|
||||
Page *page = NewPage();
|
||||
if (!page) {
|
||||
rv = PR_FALSE;
|
||||
} else {
|
||||
@@ -110,8 +110,10 @@ nsTaskQueue::PutTask(nsIRunnable *runnable)
|
||||
mOffsetTail = 0;
|
||||
}
|
||||
}
|
||||
if (rv)
|
||||
task.swap(mTail->mTasks[mOffsetTail++]);
|
||||
if (rv) {
|
||||
task.swap(mTail->mTasks[mOffsetTail]);
|
||||
++mOffsetTail;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#ifndef nsTaskQueue_h__
|
||||
#define nsTaskQueue_h__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "prmon.h"
|
||||
#include "nsIRunnable.h"
|
||||
|
||||
@@ -84,6 +85,14 @@ private:
|
||||
Page() : mNext(nsnull) {}
|
||||
};
|
||||
|
||||
static Page *NewPage() {
|
||||
return NS_STATIC_CAST(Page *, calloc(1, sizeof(Page)));
|
||||
}
|
||||
|
||||
static void FreePage(Page *p) {
|
||||
free(p);
|
||||
}
|
||||
|
||||
PRMonitor *mMonitor;
|
||||
|
||||
Page *mHead;
|
||||
|
||||
@@ -176,33 +176,33 @@ private:
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This class is used to convey initialization info to the newly created thread.
|
||||
class nsThreadStartInfo {
|
||||
private:
|
||||
PRInt32 mRefCnt;
|
||||
|
||||
~nsThreadStartInfo() {
|
||||
nsAutoMonitor::DestroyMonitor(mMon);
|
||||
}
|
||||
class nsThreadStartup : public nsRunnable {
|
||||
public:
|
||||
PRMonitor *mMon;
|
||||
nsThread *mThread;
|
||||
PRBool mInitialized;
|
||||
|
||||
nsThreadStartInfo(nsThread *thr)
|
||||
: mRefCnt(0)
|
||||
, mMon(nsAutoMonitor::NewMonitor("nsThreadStartInfo"))
|
||||
, mThread(thr)
|
||||
nsThreadStartup()
|
||||
: mMon(nsAutoMonitor::NewMonitor("xpcom.threadstartup"))
|
||||
, mInitialized(PR_FALSE) {
|
||||
}
|
||||
|
||||
void AddRef() {
|
||||
PR_AtomicIncrement(&mRefCnt);
|
||||
NS_IMETHOD Run() {
|
||||
nsAutoMonitor mon(mMon);
|
||||
mInitialized = PR_TRUE;
|
||||
mon.Notify();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Release() {
|
||||
if (PR_AtomicDecrement(&mRefCnt) == 0)
|
||||
delete this;
|
||||
void Wait() {
|
||||
nsAutoMonitor mon(mMon);
|
||||
while (!mInitialized)
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~nsThreadStartup() {
|
||||
nsAutoMonitor::DestroyMonitor(mMon);
|
||||
}
|
||||
|
||||
PRMonitor *mMon;
|
||||
PRBool mInitialized;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -210,21 +210,18 @@ public:
|
||||
/*static*/ void
|
||||
nsThread::ThreadFunc(void *arg)
|
||||
{
|
||||
nsThreadStartInfo *si = NS_STATIC_CAST(nsThreadStartInfo *, arg);
|
||||
|
||||
nsThread *self = si->mThread;
|
||||
NS_ADDREF(self);
|
||||
nsThread *self = NS_STATIC_CAST(nsThread *, arg); // strong reference
|
||||
|
||||
// Inform the ThreadManager
|
||||
nsThreadManager::get()->SetCurrentThread(self, nsnull);
|
||||
|
||||
// Unblock nsThread::Init
|
||||
{
|
||||
nsAutoMonitor mon(si->mMon);
|
||||
si->mInitialized = PR_TRUE;
|
||||
mon.Notify();
|
||||
nsCOMPtr<nsIRunnable> task;
|
||||
self->mTasks.WaitPendingTask(getter_AddRefs(task));
|
||||
if (!task) {
|
||||
NS_NOTREACHED("WaitPendingTask failed");
|
||||
return;
|
||||
}
|
||||
NS_RELEASE(si);
|
||||
task->Run(); // unblocks nsThread::Init
|
||||
|
||||
// Now, process incoming tasks...
|
||||
while (self->mActive)
|
||||
@@ -253,27 +250,31 @@ nsresult
|
||||
nsThread::Init()
|
||||
{
|
||||
// spawn thread and wait until it is fully setup
|
||||
nsThreadStartInfo *si = new nsThreadStartInfo(this);
|
||||
if (!si)
|
||||
|
||||
nsRefPtr<nsThreadStartup> startup = new nsThreadStartup();
|
||||
if (!startup)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
NS_ADDREF(si);
|
||||
|
||||
NS_ADDREF_THIS();
|
||||
|
||||
mActive = PR_TRUE;
|
||||
mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, si, PR_PRIORITY_NORMAL,
|
||||
PR_GLOBAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
mThread = PR_CreateThread(PR_USER_THREAD, ThreadFunc, this,
|
||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
||||
PR_JOINABLE_THREAD, 0);
|
||||
if (!mThread) {
|
||||
NS_RELEASE(si);
|
||||
NS_RELEASE_THIS();
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
// Wait for thread to call ThreadManager::SetCurrentThread
|
||||
{
|
||||
nsAutoMonitor mon(si->mMon);
|
||||
while (!si->mInitialized)
|
||||
mon.Wait();
|
||||
}
|
||||
// ThreadFunc will wait for this task to be run before it tries to access
|
||||
// mThread. By delaying insertion of this task into the queue, we ensure
|
||||
// that mThread is set properly.
|
||||
mTasks.PutTask(startup);
|
||||
|
||||
// Wait for thread to call ThreadManager::SetCurrentThread, which completes
|
||||
// initialization of ThreadFunc.
|
||||
startup->Wait();
|
||||
|
||||
NS_RELEASE(si);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user