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:
darin%meer.net
2006-02-14 00:53:19 +00:00
parent 0028e4b5e2
commit c41509e727
3 changed files with 61 additions and 49 deletions

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}