diff --git a/xpcom/threads/nsIThread.idl b/xpcom/threads/nsIThread.idl index d4370d489b8..7b91c221175 100644 --- a/xpcom/threads/nsIThread.idl +++ b/xpcom/threads/nsIThread.idl @@ -53,18 +53,44 @@ interface nsIRunnable; [scriptable, uuid(6be5e380-6886-11d3-9382-00104ba0fd40)] interface nsIThread : nsISupports { - void Join(); - void Interrupt(); - attribute PRThreadPriority Priority; - readonly attribute PRThreadScope Scope; - readonly attribute PRThreadState State; + // These must all match the values used in prthread.h + const PRUint32 PRIORITY_LOW = 0; + const PRUint32 PRIORITY_NORMAL = 1; + const PRUint32 PRIORITY_HIGH = 2; + const PRUint32 PRIORITY_URGENT = 3; + + const PRUint32 SCOPE_LOCAL = 0; + const PRUint32 SCOPE_GLOBAL = 1; + const PRUint32 SCOPE_BOUND = 2; + + const PRUint32 STATE_JOINABLE = 0; + const PRUint32 STATE_UNJOINABLE = 1; + + void join(); + void interrupt(); + + attribute PRThreadPriority priority; + readonly attribute PRThreadScope scope; + readonly attribute PRThreadState state; + [noscript] PRThread GetPRThread(); - void Init(in nsIRunnable aRunnable, - in unsigned long aStackSize, + + void init(in nsIRunnable aRunnable, + in PRUint32 aStackSize, in PRThreadPriority aPriority, in PRThreadScope aScope, in PRThreadState aState); + /* + * Get the currently running thread (really a static method sort of thing). + */ + readonly attribute nsIThread currentThread; + + /* + * Sleep to at least this many milliseconds (only works on currrent thread). + */ + void sleep(in PRUint32 msec); + %{C++ // returns the nsIThread for the current thread: static NS_COM nsresult GetCurrent(nsIThread* *result); diff --git a/xpcom/threads/nsThread.cpp b/xpcom/threads/nsThread.cpp index 7dd0c7ea1f0..652069afaca 100644 --- a/xpcom/threads/nsThread.cpp +++ b/xpcom/threads/nsThread.cpp @@ -49,7 +49,7 @@ PRLogModuleInfo* nsIThreadLog = nsnull; //////////////////////////////////////////////////////////////////////////////// nsThread::nsThread() - : mThread(nsnull), mDead(PR_FALSE) + : mThread(nsnull), mDead(PR_FALSE), mStartLock(nsnull) { NS_INIT_REFCNT(); @@ -62,10 +62,24 @@ nsThread::nsThread() nsIThreadLog = PR_NewLogModule("nsIThread"); } #endif /* PR_LOGGING */ + +// enforce matching of constants to enums in prthread.h +NS_ASSERTION(nsIThread::PRIORITY_LOW == PR_PRIORITY_LOW && + nsIThread::PRIORITY_NORMAL == PRIORITY_NORMAL && + nsIThread::PRIORITY_HIGH == PRIORITY_HIGH && + nsIThread::PRIORITY_URGENT == PRIORITY_URGENT && + nsIThread::SCOPE_LOCAL == PR_LOCAL_THREAD && + nsIThread::SCOPE_GLOBAL == PR_GLOBAL_THREAD && + nsIThread::STATE_JOINABLE == PR_JOINABLE_THREAD && + nsIThread::STATE_UNJOINABLE == PR_UNJOINABLE_THREAD, + "Bad constant in nsIThread!"); } nsThread::~nsThread() { + if (mStartLock) + PR_DestroyLock(mStartLock); + PR_LOG(nsIThreadLog, PR_LOG_DEBUG, ("nsIThread %p destroyed\n", this)); } @@ -75,6 +89,8 @@ nsThread::Main(void* arg) { nsThread* self = (nsThread*)arg; + self->WaitUntilReadyToStartMain(); + nsresult rv = NS_OK; rv = self->RegisterThreadSelf(); NS_ASSERTION(rv == NS_OK, "failed to set thread self"); @@ -212,8 +228,13 @@ nsThread::Init(nsIRunnable* runnable, NS_ADDREF_THIS(); // released in nsThread::Exit if (state == PR_JOINABLE_THREAD) NS_ADDREF_THIS(); // released in nsThread::Join + mStartLock = PR_NewLock(); + if (mStartLock == nsnull) + return NS_ERROR_OUT_OF_MEMORY; + PR_Lock(mStartLock); mThread = PR_CreateThread(PR_USER_THREAD, Main, this, priority, scope, state, stackSize); + PR_Unlock(mStartLock); PR_LOG(nsIThreadLog, PR_LOG_DEBUG, ("nsIThread %p created\n", this)); if (mThread == nsnull) @@ -221,6 +242,26 @@ nsThread::Init(nsIRunnable* runnable, return NS_OK; } +/* readonly attribute nsIThread currentThread; */ +NS_IMETHODIMP +nsThread::GetCurrentThread(nsIThread * *aCurrentThread) +{ + return GetIThread(PR_CurrentThread(), aCurrentThread); +} + +/* void sleep (in PRUint32 msec); */ +NS_IMETHODIMP +nsThread::Sleep(PRUint32 msec) +{ + if (PR_CurrentThread() != mThread) + return NS_ERROR_FAILURE; + + if (PR_Sleep(PR_MillisecondsToInterval(msec)) != PR_SUCCESS) + return NS_ERROR_FAILURE; + + return NS_OK; +} + NS_COM nsresult NS_NewThread(nsIThread* *result, nsIRunnable* runnable, @@ -279,6 +320,15 @@ nsThread::RegisterThreadSelf() return NS_OK; } +void +nsThread::WaitUntilReadyToStartMain() +{ + PR_Lock(mStartLock); + PR_Unlock(mStartLock); + PR_DestroyLock(mStartLock); + mStartLock = nsnull; +} + NS_COM nsresult nsIThread::GetCurrent(nsIThread* *result) { diff --git a/xpcom/threads/nsThread.h b/xpcom/threads/nsThread.h index b07b79e1977..dc40ecca2f2 100644 --- a/xpcom/threads/nsThread.h +++ b/xpcom/threads/nsThread.h @@ -56,6 +56,7 @@ public: nsresult RegisterThreadSelf(); void SetPRThread(PRThread* thread) { mThread = thread; } + void WaitUntilReadyToStartMain(); static void PR_CALLBACK Main(void* arg); static void PR_CALLBACK Exit(void* arg); @@ -70,6 +71,7 @@ protected: PRThread* mThread; nsCOMPtr mRunnable; PRBool mDead; + PRLock* mStartLock; }; ////////////////////////////////////////////////////////////////////////////////