From c41509e727a41b1cdaf9073ac92fcba74237da73 Mon Sep 17 00:00:00 2001 From: "darin%meer.net" Date: Tue, 14 Feb 2006 00:53:19 +0000 Subject: [PATCH] fix some bugs git-svn-id: svn://10.0.0.236/branches/THREADS_20060213_BRANCH@189907 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/xpcom/threads/nsTaskQueue.cpp | 14 +++-- mozilla/xpcom/threads/nsTaskQueue.h | 9 +++ mozilla/xpcom/threads/nsThread.cpp | 87 ++++++++++++++------------- 3 files changed, 61 insertions(+), 49 deletions(-) diff --git a/mozilla/xpcom/threads/nsTaskQueue.cpp b/mozilla/xpcom/threads/nsTaskQueue.cpp index bfc582f705f..e930c22f05b 100644 --- a/mozilla/xpcom/threads/nsTaskQueue.cpp +++ b/mozilla/xpcom/threads/nsTaskQueue.cpp @@ -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; } diff --git a/mozilla/xpcom/threads/nsTaskQueue.h b/mozilla/xpcom/threads/nsTaskQueue.h index 1740830a843..7c4216ed0e9 100644 --- a/mozilla/xpcom/threads/nsTaskQueue.h +++ b/mozilla/xpcom/threads/nsTaskQueue.h @@ -39,6 +39,7 @@ #ifndef nsTaskQueue_h__ #define nsTaskQueue_h__ +#include #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; diff --git a/mozilla/xpcom/threads/nsThread.cpp b/mozilla/xpcom/threads/nsThread.cpp index 4658c661c18..f7fb83336e7 100644 --- a/mozilla/xpcom/threads/nsThread.cpp +++ b/mozilla/xpcom/threads/nsThread.cpp @@ -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 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 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; }