Back to index

lightning-sunbird  0.9+nobinonly
pruthr.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 #include <signal.h>
00040 #include <string.h>
00041 
00042 #if defined(WIN95)                                                                         
00043 /*
00044 ** Some local variables report warnings on Win95 because the code paths
00045 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
00046 ** The pragma suppresses the warning.
00047 **
00048 */
00049 #pragma warning(disable : 4101)
00050 #endif          
00051 
00052 #if defined(XP_MAC)
00053 #include <LowMem.h>
00054 #endif
00055 
00056 /* _pr_activeLock protects the following global variables */
00057 PRLock *_pr_activeLock;
00058 PRInt32 _pr_primordialExitCount;   /* In PR_Cleanup(), the primordial thread
00059                     * waits until all other user (non-system)
00060                     * threads have terminated before it exits.
00061                     * So whenever we decrement _pr_userActive,
00062                     * it is compared with
00063                     * _pr_primordialExitCount.
00064                     * If the primordial thread is a system
00065                     * thread, then _pr_primordialExitCount
00066                     * is 0.  If the primordial thread is
00067                     * itself a user thread, then 
00068                     * _pr_primordialThread is 1.
00069                     */
00070 PRCondVar *_pr_primordialExitCVar; /* When _pr_userActive is decremented to
00071                     * _pr_primordialExitCount, this condition
00072                     * variable is notified.
00073                     */
00074 
00075 PRLock *_pr_deadQLock;
00076 PRUint32 _pr_numNativeDead;
00077 PRUint32 _pr_numUserDead;
00078 PRCList _pr_deadNativeQ;
00079 PRCList _pr_deadUserQ;
00080 
00081 PRUint32 _pr_join_counter;
00082 
00083 PRUint32 _pr_local_threads;
00084 PRUint32 _pr_global_threads;
00085 
00086 PRBool suspendAllOn = PR_FALSE;
00087 PRThread *suspendAllThread = NULL;
00088 
00089 extern PRCList _pr_active_global_threadQ;
00090 extern PRCList _pr_active_local_threadQ;
00091 
00092 static void _PR_DecrActiveThreadCount(PRThread *thread);
00093 static PRThread *_PR_AttachThread(PRThreadType, PRThreadPriority, PRThreadStack *);
00094 static void _PR_InitializeNativeStack(PRThreadStack *ts);
00095 static void _PR_InitializeRecycledThread(PRThread *thread);
00096 static void _PR_UserRunThread(void);
00097 
00098 void _PR_InitThreads(PRThreadType type, PRThreadPriority priority,
00099     PRUintn maxPTDs)
00100 {
00101 #if defined(XP_MAC)
00102 #pragma unused (maxPTDs)
00103 #endif
00104 
00105     PRThread *thread;
00106     PRThreadStack *stack;
00107 
00108     _pr_terminationCVLock = PR_NewLock();
00109     _pr_activeLock = PR_NewLock();
00110 
00111 #ifndef HAVE_CUSTOM_USER_THREADS
00112     stack = PR_NEWZAP(PRThreadStack);
00113 #ifdef HAVE_STACK_GROWING_UP
00114     stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift)
00115                   << _pr_pageShift);
00116 #else
00117 #if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS)
00118     stack->stackTop = (char*) &thread;
00119 #elif defined(XP_MAC)
00120     stack->stackTop = (char*) LMGetCurStackBase();
00121 #else
00122     stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1)
00123                 >> _pr_pageShift) << _pr_pageShift);
00124 #endif
00125 #endif
00126 #else
00127     /* If stack is NULL, we're using custom user threads like NT fibers. */
00128     stack = PR_NEWZAP(PRThreadStack);
00129     if (stack) {
00130         stack->stackSize = 0;
00131         _PR_InitializeNativeStack(stack);
00132     }
00133 #endif /* HAVE_CUSTOM_USER_THREADS */
00134 
00135     thread = _PR_AttachThread(type, priority, stack);
00136     if (thread) {
00137         _PR_MD_SET_CURRENT_THREAD(thread);
00138 
00139         if (type == PR_SYSTEM_THREAD) {
00140             thread->flags = _PR_SYSTEM;
00141             _pr_systemActive++;
00142             _pr_primordialExitCount = 0;
00143         } else {
00144             _pr_userActive++;
00145             _pr_primordialExitCount = 1;
00146         }
00147     thread->no_sched = 1;
00148     _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock);
00149     }
00150 
00151     if (!thread) PR_Abort();
00152 #ifdef _PR_LOCAL_THREADS_ONLY
00153     thread->flags |= _PR_PRIMORDIAL;
00154 #else
00155     thread->flags |= _PR_PRIMORDIAL | _PR_GLOBAL_SCOPE;
00156 #endif
00157 
00158     /*
00159      * Needs _PR_PRIMORDIAL flag set before calling
00160      * _PR_MD_INIT_THREAD()
00161      */
00162     if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
00163         /*
00164          * XXX do what?
00165          */
00166     }
00167 
00168     if (_PR_IS_NATIVE_THREAD(thread)) {
00169         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
00170         _pr_global_threads++;
00171     } else {
00172         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
00173         _pr_local_threads++;
00174     }
00175 
00176     _pr_recycleThreads = 0;
00177     _pr_deadQLock = PR_NewLock();
00178     _pr_numNativeDead = 0;
00179     _pr_numUserDead = 0;
00180     PR_INIT_CLIST(&_pr_deadNativeQ);
00181     PR_INIT_CLIST(&_pr_deadUserQ);
00182 }
00183 
00184 void _PR_CleanupThreads(void)
00185 {
00186     if (_pr_terminationCVLock) {
00187         PR_DestroyLock(_pr_terminationCVLock);
00188         _pr_terminationCVLock = NULL;
00189     }
00190     if (_pr_activeLock) {
00191         PR_DestroyLock(_pr_activeLock);
00192         _pr_activeLock = NULL;
00193     }
00194     if (_pr_primordialExitCVar) {
00195         PR_DestroyCondVar(_pr_primordialExitCVar);
00196         _pr_primordialExitCVar = NULL;
00197     }
00198     /* TODO _pr_dead{Native,User}Q need to be deleted */
00199     if (_pr_deadQLock) {
00200         PR_DestroyLock(_pr_deadQLock);
00201         _pr_deadQLock = NULL;
00202     }
00203 }
00204 
00205 /*
00206 ** Initialize a stack for a native thread
00207 */
00208 static void _PR_InitializeNativeStack(PRThreadStack *ts)
00209 {
00210     if( ts && (ts->stackTop == 0) ) {
00211         ts->allocSize = ts->stackSize;
00212 
00213         /*
00214         ** Setup stackTop and stackBottom values.
00215         */
00216 #ifdef HAVE_STACK_GROWING_UP
00217     ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift)
00218                   << _pr_pageShift);
00219         ts->stackBottom = ts->allocBase + ts->stackSize;
00220         ts->stackTop = ts->allocBase;
00221 #else
00222         ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1)
00223                 >> _pr_pageShift) << _pr_pageShift);
00224         ts->stackTop    = ts->allocBase;
00225         ts->stackBottom = ts->allocBase - ts->stackSize;
00226 #endif
00227     }
00228 }
00229 
00230 void _PR_NotifyJoinWaiters(PRThread *thread)
00231 {
00232     /*
00233     ** Handle joinable threads.  Change the state to waiting for join.
00234     ** Remove from our run Q and put it on global waiting to join Q.
00235     ** Notify on our "termination" condition variable so that joining
00236     ** thread will know about our termination.  Switch our context and
00237     ** come back later on to continue the cleanup.
00238     */    
00239     PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
00240     if (thread->term != NULL) {
00241         PR_Lock(_pr_terminationCVLock);
00242         _PR_THREAD_LOCK(thread);
00243         thread->state = _PR_JOIN_WAIT;
00244         if ( !_PR_IS_NATIVE_THREAD(thread) ) {
00245             _PR_MISCQ_LOCK(thread->cpu);
00246             _PR_ADD_JOINQ(thread, thread->cpu);
00247             _PR_MISCQ_UNLOCK(thread->cpu);
00248         }
00249         _PR_THREAD_UNLOCK(thread);
00250         PR_NotifyCondVar(thread->term);
00251         PR_Unlock(_pr_terminationCVLock);
00252         _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
00253         PR_ASSERT(thread->state != _PR_JOIN_WAIT);
00254     }
00255 
00256 }
00257 
00258 /*
00259  * Zero some of the data members of a recycled thread.
00260  *
00261  * Note that we can do this either when a dead thread is added to
00262  * the dead thread queue or when it is reused.  Here, we are doing
00263  * this lazily, when the thread is reused in _PR_CreateThread().
00264  */
00265 static void _PR_InitializeRecycledThread(PRThread *thread)
00266 {
00267     /*
00268      * Assert that the following data members are already zeroed
00269      * by _PR_CleanupThread().
00270      */
00271 #ifdef DEBUG
00272     if (thread->privateData) {
00273         unsigned int i;
00274         for (i = 0; i < thread->tpdLength; i++) {
00275             PR_ASSERT(thread->privateData[i] == NULL);
00276         }
00277     }
00278 #endif
00279     PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0);
00280     PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0);
00281     PR_ASSERT(thread->errorStringLength == 0);
00282 
00283     /* Reset data members in thread structure */
00284     thread->errorCode = thread->osErrorCode = 0;
00285     thread->io_pending = thread->io_suspended = PR_FALSE;
00286     thread->environment = 0;
00287     PR_INIT_CLIST(&thread->lockList);
00288 }
00289 
00290 PRStatus _PR_RecycleThread(PRThread *thread)
00291 {
00292     if ( _PR_IS_NATIVE_THREAD(thread) &&
00293             _PR_NUM_DEADNATIVE < _pr_recycleThreads) {
00294         _PR_DEADQ_LOCK;
00295         PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ);
00296         _PR_INC_DEADNATIVE;
00297         _PR_DEADQ_UNLOCK;
00298     return (PR_SUCCESS);
00299     } else if ( !_PR_IS_NATIVE_THREAD(thread) &&
00300                 _PR_NUM_DEADUSER < _pr_recycleThreads) {
00301         _PR_DEADQ_LOCK;
00302         PR_APPEND_LINK(&thread->links, &_PR_DEADUSERQ);
00303         _PR_INC_DEADUSER;
00304         _PR_DEADQ_UNLOCK;
00305     return (PR_SUCCESS);
00306     }
00307     return (PR_FAILURE);
00308 }
00309 
00310 /*
00311  * Decrement the active thread count, either _pr_systemActive or
00312  * _pr_userActive, depending on whether the thread is a system thread
00313  * or a user thread.  If all the user threads, except possibly
00314  * the primordial thread, have terminated, we notify the primordial
00315  * thread of this condition.
00316  *
00317  * Since this function will lock _pr_activeLock, do not call this
00318  * function while holding the _pr_activeLock lock, as this will result
00319  * in a deadlock.
00320  */
00321 
00322 static void
00323 _PR_DecrActiveThreadCount(PRThread *thread)
00324 {
00325     PR_Lock(_pr_activeLock);
00326     if (thread->flags & _PR_SYSTEM) {
00327         _pr_systemActive--;
00328     } else {
00329         _pr_userActive--;
00330         if (_pr_userActive == _pr_primordialExitCount) {
00331             PR_NotifyCondVar(_pr_primordialExitCVar);
00332         }
00333     }
00334     PR_Unlock(_pr_activeLock);
00335 }
00336 
00337 /*
00338 ** Detach thread structure
00339 */
00340 static void
00341 _PR_DestroyThread(PRThread *thread)
00342 {
00343     _PR_MD_FREE_LOCK(&thread->threadLock);
00344     PR_DELETE(thread);
00345 }
00346 
00347 void
00348 _PR_NativeDestroyThread(PRThread *thread)
00349 {
00350     if(thread->term) {
00351         PR_DestroyCondVar(thread->term);
00352         thread->term = 0;
00353     }
00354     if (NULL != thread->privateData) {
00355         PR_ASSERT(0 != thread->tpdLength);
00356         PR_DELETE(thread->privateData);
00357         thread->tpdLength = 0;
00358     }
00359     PR_DELETE(thread->stack);
00360     _PR_DestroyThread(thread);
00361 }
00362 
00363 void
00364 _PR_UserDestroyThread(PRThread *thread)
00365 {
00366     if(thread->term) {
00367         PR_DestroyCondVar(thread->term);
00368         thread->term = 0;
00369     }
00370     if (NULL != thread->privateData) {
00371         PR_ASSERT(0 != thread->tpdLength);
00372         PR_DELETE(thread->privateData);
00373         thread->tpdLength = 0;
00374     }
00375     _PR_MD_FREE_LOCK(&thread->threadLock);
00376     if (thread->threadAllocatedOnStack == 1) {
00377         _PR_MD_CLEAN_THREAD(thread);
00378         /*
00379          *  Because the no_sched field is set, this thread/stack will
00380          *  will not be re-used until the flag is cleared by the thread
00381          *  we will context switch to.
00382          */
00383         _PR_FreeStack(thread->stack);
00384     } else {
00385 #ifdef WINNT
00386         _PR_MD_CLEAN_THREAD(thread);
00387 #else
00388         /*
00389          * This assertion does not apply to NT.  On NT, every fiber
00390          * has its threadAllocatedOnStack equal to 0.  Elsewhere,
00391          * only the primordial thread has its threadAllocatedOnStack
00392          * equal to 0.
00393          */
00394         PR_ASSERT(thread->flags & _PR_PRIMORDIAL);
00395 #endif
00396     }
00397 }
00398 
00399 
00400 /*
00401 ** Run a thread's start function. When the start function returns the
00402 ** thread is done executing and no longer needs the CPU. If there are no
00403 ** more user threads running then we can exit the program.
00404 */
00405 void _PR_NativeRunThread(void *arg)
00406 {
00407     PRThread *thread = (PRThread *)arg;
00408 
00409     _PR_MD_SET_CURRENT_THREAD(thread);
00410 
00411     _PR_MD_SET_CURRENT_CPU(NULL);
00412 
00413     /* Set up the thread stack information */
00414     _PR_InitializeNativeStack(thread->stack);
00415 
00416     /* Set up the thread md information */
00417     if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
00418         /*
00419          * thread failed to initialize itself, possibly due to
00420          * failure to allocate per-thread resources
00421          */
00422         return;
00423     }
00424 
00425     while(1) {
00426         thread->state = _PR_RUNNING;
00427 
00428         /*
00429          * Add to list of active threads
00430          */
00431         PR_Lock(_pr_activeLock);
00432         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
00433         _pr_global_threads++;
00434         PR_Unlock(_pr_activeLock);
00435 
00436         (*thread->startFunc)(thread->arg);
00437 
00438         /*
00439          * The following two assertions are meant for NT asynch io.
00440          *
00441          * The thread should have no asynch io in progress when it
00442          * exits, otherwise the overlapped buffer, which is part of
00443          * the thread structure, would become invalid.
00444          */
00445         PR_ASSERT(thread->io_pending == PR_FALSE);
00446         /*
00447          * This assertion enforces the programming guideline that
00448          * if an io function times out or is interrupted, the thread
00449          * should close the fd to force the asynch io to abort
00450          * before it exits.  Right now, closing the fd is the only
00451          * way to clear the io_suspended flag.
00452          */
00453         PR_ASSERT(thread->io_suspended == PR_FALSE);
00454 
00455         /*
00456          * remove thread from list of active threads
00457          */
00458         PR_Lock(_pr_activeLock);
00459         PR_REMOVE_LINK(&thread->active);
00460         _pr_global_threads--;
00461         PR_Unlock(_pr_activeLock);
00462 
00463         PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));
00464 
00465         /* All done, time to go away */
00466         _PR_CleanupThread(thread);
00467 
00468         _PR_NotifyJoinWaiters(thread);
00469 
00470         _PR_DecrActiveThreadCount(thread);
00471 
00472         thread->state = _PR_DEAD_STATE;
00473 
00474         if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
00475                         PR_FAILURE)) {
00476             /*
00477              * thread not recycled
00478              * platform-specific thread exit processing
00479              *        - for stuff like releasing native-thread resources, etc.
00480              */
00481             _PR_MD_EXIT_THREAD(thread);
00482             /*
00483              * Free memory allocated for the thread
00484              */
00485             _PR_NativeDestroyThread(thread);
00486             /*
00487              * thread gone, cannot de-reference thread now
00488              */
00489             return;
00490         }
00491 
00492         /* Now wait for someone to activate us again... */
00493         _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
00494     }
00495 }
00496 
00497 static void _PR_UserRunThread(void)
00498 {
00499     PRThread *thread = _PR_MD_CURRENT_THREAD();
00500     PRIntn is;
00501 
00502     if (_MD_LAST_THREAD())
00503     _MD_LAST_THREAD()->no_sched = 0;
00504 
00505 #ifdef HAVE_CUSTOM_USER_THREADS
00506     if (thread->stack == NULL) {
00507         thread->stack = PR_NEWZAP(PRThreadStack);
00508         _PR_InitializeNativeStack(thread->stack);
00509     }
00510 #endif /* HAVE_CUSTOM_USER_THREADS */
00511 
00512     while(1) {
00513         /* Run thread main */
00514         if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_MD_SET_INTSOFF(0);
00515 
00516     /*
00517      * Add to list of active threads
00518      */
00519     if (!(thread->flags & _PR_IDLE_THREAD)) {
00520         PR_Lock(_pr_activeLock);
00521         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
00522         _pr_local_threads++;
00523         PR_Unlock(_pr_activeLock);
00524     }
00525 
00526         (*thread->startFunc)(thread->arg);
00527 
00528         /*
00529          * The following two assertions are meant for NT asynch io.
00530          *
00531          * The thread should have no asynch io in progress when it
00532          * exits, otherwise the overlapped buffer, which is part of
00533          * the thread structure, would become invalid.
00534          */
00535         PR_ASSERT(thread->io_pending == PR_FALSE);
00536         /*
00537          * This assertion enforces the programming guideline that
00538          * if an io function times out or is interrupted, the thread
00539          * should close the fd to force the asynch io to abort
00540          * before it exits.  Right now, closing the fd is the only
00541          * way to clear the io_suspended flag.
00542          */
00543         PR_ASSERT(thread->io_suspended == PR_FALSE);
00544 
00545         PR_Lock(_pr_activeLock);
00546     /*
00547      * remove thread from list of active threads
00548      */
00549     if (!(thread->flags & _PR_IDLE_THREAD)) {
00550            PR_REMOVE_LINK(&thread->active);
00551         _pr_local_threads--;
00552     }
00553     PR_Unlock(_pr_activeLock);
00554         PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));
00555 
00556         /* All done, time to go away */
00557         _PR_CleanupThread(thread);
00558 
00559         _PR_INTSOFF(is);    
00560 
00561         _PR_NotifyJoinWaiters(thread);
00562 
00563     _PR_DecrActiveThreadCount(thread);
00564 
00565         thread->state = _PR_DEAD_STATE;
00566 
00567         if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
00568                         PR_FAILURE)) {
00569             /*
00570             ** Destroy the thread resources
00571             */
00572         _PR_UserDestroyThread(thread);
00573         }
00574 
00575         /*
00576         ** Find another user thread to run. This cpu has finished the
00577         ** previous threads main and is now ready to run another thread.
00578         */
00579         {
00580             PRInt32 is;
00581             _PR_INTSOFF(is);
00582             _PR_MD_SWITCH_CONTEXT(thread);
00583         }
00584 
00585         /* Will land here when we get scheduled again if we are recycling... */
00586     }
00587 }
00588 
00589 void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri)
00590 {
00591     PRThread *me = _PR_MD_CURRENT_THREAD();
00592     PRIntn is;
00593 
00594     if ( _PR_IS_NATIVE_THREAD(thread) ) {
00595         _PR_MD_SET_PRIORITY(&(thread->md), newPri);
00596         return;
00597     }
00598 
00599     if (!_PR_IS_NATIVE_THREAD(me))
00600     _PR_INTSOFF(is);
00601     _PR_THREAD_LOCK(thread);
00602     if (newPri != thread->priority) {
00603     _PRCPU *cpu = thread->cpu;
00604 
00605     switch (thread->state) {
00606       case _PR_RUNNING:
00607         /* Change my priority */
00608 
00609             _PR_RUNQ_LOCK(cpu);
00610         thread->priority = newPri;
00611         if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) {
00612             if (!_PR_IS_NATIVE_THREAD(me))
00613                     _PR_SET_RESCHED_FLAG();
00614         }
00615             _PR_RUNQ_UNLOCK(cpu);
00616         break;
00617 
00618       case _PR_RUNNABLE:
00619 
00620         _PR_RUNQ_LOCK(cpu);
00621             /* Move to different runQ */
00622             _PR_DEL_RUNQ(thread);
00623             thread->priority = newPri;
00624             PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00625             _PR_ADD_RUNQ(thread, cpu, newPri);
00626         _PR_RUNQ_UNLOCK(cpu);
00627 
00628             if (newPri > me->priority) {
00629             if (!_PR_IS_NATIVE_THREAD(me))
00630                     _PR_SET_RESCHED_FLAG();
00631             }
00632 
00633         break;
00634 
00635       case _PR_LOCK_WAIT:
00636       case _PR_COND_WAIT:
00637       case _PR_IO_WAIT:
00638       case _PR_SUSPENDED:
00639 
00640         thread->priority = newPri;
00641         break;
00642     }
00643     }
00644     _PR_THREAD_UNLOCK(thread);
00645     if (!_PR_IS_NATIVE_THREAD(me))
00646     _PR_INTSON(is);
00647 }
00648 
00649 /*
00650 ** Suspend the named thread and copy its gc registers into regBuf
00651 */
00652 static void _PR_Suspend(PRThread *thread)
00653 {
00654     PRIntn is;
00655     PRThread *me = _PR_MD_CURRENT_THREAD();
00656 
00657     PR_ASSERT(thread != me);
00658     PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu));
00659 
00660     if (!_PR_IS_NATIVE_THREAD(me))
00661         _PR_INTSOFF(is);
00662     _PR_THREAD_LOCK(thread);
00663     switch (thread->state) {
00664       case _PR_RUNNABLE:
00665         if (!_PR_IS_NATIVE_THREAD(thread)) {
00666             _PR_RUNQ_LOCK(thread->cpu);
00667             _PR_DEL_RUNQ(thread);
00668             _PR_RUNQ_UNLOCK(thread->cpu);
00669 
00670             _PR_MISCQ_LOCK(thread->cpu);
00671             _PR_ADD_SUSPENDQ(thread, thread->cpu);
00672             _PR_MISCQ_UNLOCK(thread->cpu);
00673         } else {
00674             /*
00675              * Only LOCAL threads are suspended by _PR_Suspend
00676              */
00677              PR_ASSERT(0);
00678         }
00679         thread->state = _PR_SUSPENDED;
00680         break;
00681 
00682       case _PR_RUNNING:
00683         /*
00684          * The thread being suspended should be a LOCAL thread with
00685          * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
00686          */
00687         PR_ASSERT(0);
00688         break;
00689 
00690       case _PR_LOCK_WAIT:
00691       case _PR_IO_WAIT:
00692       case _PR_COND_WAIT:
00693         if (_PR_IS_NATIVE_THREAD(thread)) {
00694             _PR_MD_SUSPEND_THREAD(thread);
00695     }
00696         thread->flags |= _PR_SUSPENDING;
00697         break;
00698 
00699       default:
00700         PR_Abort();
00701     }
00702     _PR_THREAD_UNLOCK(thread);
00703     if (!_PR_IS_NATIVE_THREAD(me))
00704     _PR_INTSON(is);
00705 }
00706 
00707 static void _PR_Resume(PRThread *thread)
00708 {
00709     PRThreadPriority pri;
00710     PRIntn is;
00711     PRThread *me = _PR_MD_CURRENT_THREAD();
00712 
00713     if (!_PR_IS_NATIVE_THREAD(me))
00714     _PR_INTSOFF(is);
00715     _PR_THREAD_LOCK(thread);
00716     switch (thread->state) {
00717       case _PR_SUSPENDED:
00718         thread->state = _PR_RUNNABLE;
00719         thread->flags &= ~_PR_SUSPENDING;
00720         if (!_PR_IS_NATIVE_THREAD(thread)) {
00721             _PR_MISCQ_LOCK(thread->cpu);
00722             _PR_DEL_SUSPENDQ(thread);
00723             _PR_MISCQ_UNLOCK(thread->cpu);
00724 
00725             pri = thread->priority;
00726 
00727             _PR_RUNQ_LOCK(thread->cpu);
00728             _PR_ADD_RUNQ(thread, thread->cpu, pri);
00729             _PR_RUNQ_UNLOCK(thread->cpu);
00730 
00731             if (pri > _PR_MD_CURRENT_THREAD()->priority) {
00732                 if (!_PR_IS_NATIVE_THREAD(me))
00733                     _PR_SET_RESCHED_FLAG();
00734             }
00735         } else {
00736             PR_ASSERT(0);
00737         }
00738         break;
00739 
00740       case _PR_IO_WAIT:
00741       case _PR_COND_WAIT:
00742         thread->flags &= ~_PR_SUSPENDING;
00743 /*      PR_ASSERT(thread->wait.monitor->stickyCount == 0); */
00744         break;
00745 
00746       case _PR_LOCK_WAIT: 
00747       {
00748         PRLock *wLock = thread->wait.lock;
00749 
00750         thread->flags &= ~_PR_SUSPENDING;
00751  
00752         _PR_LOCK_LOCK(wLock);
00753         if (thread->wait.lock->owner == 0) {
00754             _PR_UnblockLockWaiter(thread->wait.lock);
00755         }
00756         _PR_LOCK_UNLOCK(wLock);
00757         break;
00758       }
00759       case _PR_RUNNABLE:
00760         break;
00761       case _PR_RUNNING:
00762         /*
00763          * The thread being suspended should be a LOCAL thread with
00764          * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
00765          */
00766         PR_ASSERT(0);
00767         break;
00768 
00769       default:
00770     /*
00771      * thread should have been in one of the above-listed blocked states
00772      * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE)
00773      */
00774         PR_Abort();
00775     }
00776     _PR_THREAD_UNLOCK(thread);
00777     if (!_PR_IS_NATIVE_THREAD(me))
00778         _PR_INTSON(is);
00779 
00780 }
00781 
00782 #if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
00783 static PRThread *get_thread(_PRCPU *cpu, PRBool *wakeup_cpus)
00784 {
00785     PRThread *thread;
00786     PRIntn pri;
00787     PRUint32 r;
00788     PRCList *qp;
00789     PRIntn priMin, priMax;
00790 
00791     _PR_RUNQ_LOCK(cpu);
00792     r = _PR_RUNQREADYMASK(cpu);
00793     if (r==0) {
00794         priMin = priMax = PR_PRIORITY_FIRST;
00795     } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
00796         priMin = priMax = PR_PRIORITY_NORMAL;
00797     } else {
00798         priMin = PR_PRIORITY_FIRST;
00799         priMax = PR_PRIORITY_LAST;
00800     }
00801     thread = NULL;
00802     for (pri = priMax; pri >= priMin ; pri-- ) {
00803     if (r & (1 << pri)) {
00804             for (qp = _PR_RUNQ(cpu)[pri].next; 
00805                  qp != &_PR_RUNQ(cpu)[pri];
00806                  qp = qp->next) {
00807                 thread = _PR_THREAD_PTR(qp);
00808                 /*
00809                 * skip non-schedulable threads
00810                 */
00811                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00812                 if (thread->no_sched) {
00813                     thread = NULL;
00814                     /*
00815                      * Need to wakeup cpus to avoid missing a
00816                      * runnable thread
00817                      * Waking up all CPU's need happen only once.
00818                      */
00819 
00820                     *wakeup_cpus = PR_TRUE;
00821                     continue;
00822                 } else if (thread->flags & _PR_BOUND_THREAD) {
00823                     /*
00824                      * Thread bound to cpu 0
00825                      */
00826 
00827                     thread = NULL;
00828 #ifdef IRIX
00829                                    _PR_MD_WAKEUP_PRIMORDIAL_CPU();
00830 #endif
00831                     continue;
00832                 } else if (thread->io_pending == PR_TRUE) {
00833                     /*
00834                      * A thread that is blocked for I/O needs to run
00835                      * on the same cpu on which it was blocked. This is because
00836                      * the cpu's ioq is accessed without lock protection and scheduling
00837                      * the thread on a different cpu would preclude this optimization.
00838                      */
00839                     thread = NULL;
00840                     continue;
00841                 } else {
00842                     /* Pull thread off of its run queue */
00843                     _PR_DEL_RUNQ(thread);
00844                     _PR_RUNQ_UNLOCK(cpu);
00845                     return(thread);
00846                 }
00847             }
00848         }
00849         thread = NULL;
00850     }
00851     _PR_RUNQ_UNLOCK(cpu);
00852     return(thread);
00853 }
00854 #endif /* !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX) */
00855 
00856 /*
00857 ** Schedule this native thread by finding the highest priority nspr
00858 ** thread that is ready to run.
00859 **
00860 ** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls
00861 **       PR_Schedule() rather than calling PR_Schedule.  Otherwise if there
00862 **       is initialization required for switching from SWITCH_CONTEXT,
00863 **       it will not get done!
00864 */
00865 void _PR_Schedule(void)
00866 {
00867     PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
00868     _PRCPU *cpu = _PR_MD_CURRENT_CPU();
00869     PRIntn pri;
00870     PRUint32 r;
00871     PRCList *qp;
00872     PRIntn priMin, priMax;
00873 #if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
00874     PRBool wakeup_cpus;
00875 #endif
00876 
00877     /* Interrupts must be disabled */
00878     PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
00879 
00880     /* Since we are rescheduling, we no longer want to */
00881     _PR_CLEAR_RESCHED_FLAG();
00882 
00883     /*
00884     ** Find highest priority thread to run. Bigger priority numbers are
00885     ** higher priority threads
00886     */
00887     _PR_RUNQ_LOCK(cpu);
00888     /*
00889      *  if we are in SuspendAll mode, can schedule only the thread
00890      *    that called PR_SuspendAll
00891      *
00892      *  The thread may be ready to run now, after completing an I/O
00893      *  operation, for example
00894      */
00895     if ((thread = suspendAllThread) != 0) {
00896     if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) {
00897             /* Pull thread off of its run queue */
00898             _PR_DEL_RUNQ(thread);
00899             _PR_RUNQ_UNLOCK(cpu);
00900             goto found_thread;
00901     } else {
00902             thread = NULL;
00903             _PR_RUNQ_UNLOCK(cpu);
00904             goto idle_thread;
00905     }
00906     }
00907     r = _PR_RUNQREADYMASK(cpu);
00908     if (r==0) {
00909         priMin = priMax = PR_PRIORITY_FIRST;
00910     } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
00911         priMin = priMax = PR_PRIORITY_NORMAL;
00912     } else {
00913         priMin = PR_PRIORITY_FIRST;
00914         priMax = PR_PRIORITY_LAST;
00915     }
00916     thread = NULL;
00917     for (pri = priMax; pri >= priMin ; pri-- ) {
00918     if (r & (1 << pri)) {
00919             for (qp = _PR_RUNQ(cpu)[pri].next; 
00920                  qp != &_PR_RUNQ(cpu)[pri];
00921                  qp = qp->next) {
00922                 thread = _PR_THREAD_PTR(qp);
00923                 /*
00924                 * skip non-schedulable threads
00925                 */
00926 #if !defined(XP_MAC)
00927                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00928 #endif
00929                 if ((thread->no_sched) && (me != thread)){
00930                     thread = NULL;
00931                     continue;
00932                 } else {
00933                     /* Pull thread off of its run queue */
00934                     _PR_DEL_RUNQ(thread);
00935                     _PR_RUNQ_UNLOCK(cpu);
00936                     goto found_thread;
00937                 }
00938             }
00939         }
00940         thread = NULL;
00941     }
00942     _PR_RUNQ_UNLOCK(cpu);
00943 
00944 #if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
00945 
00946     wakeup_cpus = PR_FALSE;
00947     _PR_CPU_LIST_LOCK();
00948     for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
00949         if (cpu != _PR_CPU_PTR(qp)) {
00950             if ((thread = get_thread(_PR_CPU_PTR(qp), &wakeup_cpus))
00951                                         != NULL) {
00952                 thread->cpu = cpu;
00953                 _PR_CPU_LIST_UNLOCK();
00954                 if (wakeup_cpus == PR_TRUE)
00955                     _PR_MD_WAKEUP_CPUS();
00956                 goto found_thread;
00957             }
00958         }
00959     }
00960     _PR_CPU_LIST_UNLOCK();
00961     if (wakeup_cpus == PR_TRUE)
00962         _PR_MD_WAKEUP_CPUS();
00963 
00964 #endif        /* _PR_LOCAL_THREADS_ONLY */
00965 
00966 idle_thread:
00967    /*
00968     ** There are no threads to run. Switch to the idle thread
00969     */
00970     PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing"));
00971     thread = _PR_MD_CURRENT_CPU()->idle_thread;
00972 
00973 found_thread:
00974     PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) &&
00975                     (!(thread->no_sched))));
00976 
00977     /* Resume the thread */
00978     PR_LOG(_pr_sched_lm, PR_LOG_MAX,
00979        ("switching to %d[%p]", thread->id, thread));
00980     PR_ASSERT(thread->state != _PR_RUNNING);
00981     thread->state = _PR_RUNNING;
00982  
00983     /* If we are on the runq, it just means that we went to sleep on some
00984      * resource, and by the time we got here another real native thread had
00985      * already given us the resource and put us back on the runqueue 
00986      */
00987        PR_ASSERT(thread->cpu == _PR_MD_CURRENT_CPU());
00988     if (thread != me) 
00989         _PR_MD_RESTORE_CONTEXT(thread);
00990 #if 0
00991     /* XXXMB; with setjmp/longjmp it is impossible to land here, but 
00992      * it is not with fibers... Is this a bad thing?  I believe it is 
00993      * still safe.
00994      */
00995     PR_NOT_REACHED("impossible return from schedule");
00996 #endif
00997 }
00998 
00999 /*
01000 ** Attaches a thread.  
01001 ** Does not set the _PR_MD_CURRENT_THREAD.  
01002 ** Does not specify the scope of the thread.
01003 */
01004 static PRThread *
01005 _PR_AttachThread(PRThreadType type, PRThreadPriority priority,
01006     PRThreadStack *stack)
01007 {
01008 #if defined(XP_MAC)
01009 #pragma unused (type)
01010 #endif
01011 
01012     PRThread *thread;
01013     char *mem;
01014 
01015     if (priority > PR_PRIORITY_LAST) {
01016         priority = PR_PRIORITY_LAST;
01017     } else if (priority < PR_PRIORITY_FIRST) {
01018         priority = PR_PRIORITY_FIRST;
01019     }
01020 
01021     mem = (char*) PR_CALLOC(sizeof(PRThread));
01022     if (mem) {
01023         thread = (PRThread*) mem;
01024         thread->priority = priority;
01025         thread->stack = stack;
01026         thread->state = _PR_RUNNING;
01027         PR_INIT_CLIST(&thread->lockList);
01028         if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
01029         PR_DELETE(thread);
01030         return 0;
01031     }
01032 
01033         return thread;
01034     }
01035     return 0;
01036 }
01037 
01038 
01039 
01040 PR_IMPLEMENT(PRThread*) 
01041 _PR_NativeCreateThread(PRThreadType type,
01042                      void (*start)(void *arg),
01043                      void *arg,
01044                      PRThreadPriority priority,
01045                      PRThreadScope scope,
01046                      PRThreadState state,
01047                      PRUint32 stackSize,
01048                      PRUint32 flags)
01049 {
01050 #if defined(XP_MAC)
01051 #pragma unused (scope)
01052 #endif
01053 
01054     PRThread *thread;
01055 
01056     thread = _PR_AttachThread(type, priority, NULL);
01057 
01058     if (thread) {
01059         PR_Lock(_pr_activeLock);
01060         thread->flags = (flags | _PR_GLOBAL_SCOPE);
01061         thread->id = ++_pr_utid;
01062         if (type == PR_SYSTEM_THREAD) {
01063             thread->flags |= _PR_SYSTEM;
01064             _pr_systemActive++;
01065         } else {
01066             _pr_userActive++;
01067         }
01068         PR_Unlock(_pr_activeLock);
01069 
01070         thread->stack = PR_NEWZAP(PRThreadStack);
01071         if (!thread->stack) {
01072             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01073             goto done;
01074         }
01075         thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE;
01076         thread->stack->thr = thread;
01077         thread->startFunc = start;
01078         thread->arg = arg;
01079 
01080         /* 
01081           Set thread flags related to scope and joinable state. If joinable
01082           thread, allocate a "termination" conidition variable.
01083          */
01084         if (state == PR_JOINABLE_THREAD) {
01085             thread->term = PR_NewCondVar(_pr_terminationCVLock);
01086         if (thread->term == NULL) {
01087         PR_DELETE(thread->stack);
01088         goto done;
01089         }
01090         }
01091 
01092     thread->state = _PR_RUNNING;
01093         if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority,
01094             scope,state,stackSize) == PR_SUCCESS) {
01095             return thread;
01096         }
01097         if (thread->term) {
01098             PR_DestroyCondVar(thread->term);
01099             thread->term = NULL;
01100         }
01101     PR_DELETE(thread->stack);
01102     }
01103 
01104 done:
01105     if (thread) {
01106     _PR_DecrActiveThreadCount(thread);
01107         _PR_DestroyThread(thread);
01108     }
01109     return NULL;
01110 }
01111 
01112 /************************************************************************/
01113 
01114 PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type,
01115                      void (*start)(void *arg),
01116                      void *arg,
01117                      PRThreadPriority priority,
01118                      PRThreadScope scope,
01119                      PRThreadState state,
01120                      PRUint32 stackSize,
01121                      PRUint32 flags)
01122 {
01123     PRThread *me;
01124     PRThread *thread = NULL;
01125     PRThreadStack *stack;
01126     char *top;
01127     PRIntn is;
01128     PRIntn native = 0;
01129     PRIntn useRecycled = 0;
01130     PRBool status;
01131 
01132     /* 
01133     First, pin down the priority.  Not all compilers catch passing out of
01134     range enum here.  If we let bad values thru, priority queues won't work.
01135     */
01136     if (priority > PR_PRIORITY_LAST) {
01137         priority = PR_PRIORITY_LAST;
01138     } else if (priority < PR_PRIORITY_FIRST) {
01139         priority = PR_PRIORITY_FIRST;
01140     }
01141         
01142     if (!_pr_initialized) _PR_ImplicitInitialization();
01143 
01144     if (! (flags & _PR_IDLE_THREAD))
01145         me = _PR_MD_CURRENT_THREAD();
01146 
01147 #if    defined(_PR_GLOBAL_THREADS_ONLY)
01148        /*
01149         * can create global threads only
01150         */
01151     if (scope == PR_LOCAL_THREAD)
01152        scope = PR_GLOBAL_THREAD;
01153 #endif
01154 
01155        if (_native_threads_only)
01156               scope = PR_GLOBAL_THREAD;
01157 
01158     native = (((scope == PR_GLOBAL_THREAD)|| (scope == PR_GLOBAL_BOUND_THREAD))
01159                                                  && _PR_IS_NATIVE_THREAD_SUPPORTED());
01160 
01161     _PR_ADJUST_STACKSIZE(stackSize);
01162 
01163     if (native) {
01164     /*
01165      * clear the IDLE_THREAD flag which applies to LOCAL
01166      * threads only
01167      */
01168     flags &= ~_PR_IDLE_THREAD;
01169         flags |= _PR_GLOBAL_SCOPE;
01170         if (_PR_NUM_DEADNATIVE > 0) {
01171             _PR_DEADQ_LOCK;
01172 
01173             if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */
01174                 _PR_DEADQ_UNLOCK;
01175             } else {
01176                 thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next);
01177                 PR_REMOVE_LINK(&thread->links);
01178                 _PR_DEC_DEADNATIVE;
01179                 _PR_DEADQ_UNLOCK;
01180 
01181                 _PR_InitializeRecycledThread(thread);
01182                 thread->startFunc = start;
01183                 thread->arg = arg;
01184             thread->flags = (flags | _PR_GLOBAL_SCOPE);
01185             if (type == PR_SYSTEM_THREAD)
01186             {
01187                 thread->flags |= _PR_SYSTEM;
01188                 PR_AtomicIncrement(&_pr_systemActive);
01189             }
01190             else PR_AtomicIncrement(&_pr_userActive);
01191 
01192             if (state == PR_JOINABLE_THREAD) {
01193                 if (!thread->term) 
01194                        thread->term = PR_NewCondVar(_pr_terminationCVLock);
01195             }
01196         else {
01197                 if(thread->term) {
01198                     PR_DestroyCondVar(thread->term);
01199                         thread->term = 0;
01200             }
01201             }
01202 
01203                 thread->priority = priority;
01204         _PR_MD_SET_PRIORITY(&(thread->md), priority);
01205         /* XXX what about stackSize? */
01206         thread->state = _PR_RUNNING;
01207                 _PR_MD_WAKEUP_WAITER(thread);
01208         return thread;
01209             }
01210         }
01211         thread = _PR_NativeCreateThread(type, start, arg, priority, 
01212                                             scope, state, stackSize, flags);
01213     } else {
01214         if (_PR_NUM_DEADUSER > 0) {
01215             _PR_DEADQ_LOCK;
01216 
01217             if (_PR_NUM_DEADUSER == 0) {  /* thread safe check */
01218                 _PR_DEADQ_UNLOCK;
01219             } else {
01220                 PRCList *ptr;
01221 
01222                 /* Go down list checking for a recycled thread with a 
01223                  * large enough stack.  XXXMB - this has a bad degenerate case.
01224                  */
01225                 ptr = _PR_DEADUSERQ.next;
01226                 while( ptr != &_PR_DEADUSERQ ) {
01227                     thread = _PR_THREAD_PTR(ptr);
01228                     if ((thread->stack->stackSize >= stackSize) &&
01229                 (!thread->no_sched)) {
01230                         PR_REMOVE_LINK(&thread->links);
01231                         _PR_DEC_DEADUSER;
01232                         break;
01233                     } else {
01234                         ptr = ptr->next;
01235                         thread = NULL;
01236                     }
01237                 } 
01238 
01239                 _PR_DEADQ_UNLOCK;
01240 
01241                if (thread) {
01242                     _PR_InitializeRecycledThread(thread);
01243                     thread->startFunc = start;
01244                     thread->arg = arg;
01245                     thread->priority = priority;
01246             if (state == PR_JOINABLE_THREAD) {
01247             if (!thread->term) 
01248                thread->term = PR_NewCondVar(_pr_terminationCVLock);
01249             } else {
01250             if(thread->term) {
01251                PR_DestroyCondVar(thread->term);
01252                 thread->term = 0;
01253             }
01254             }
01255                     useRecycled++;
01256                 }
01257             }
01258         } 
01259         if (thread == NULL) {
01260 #ifndef HAVE_CUSTOM_USER_THREADS
01261             stack = _PR_NewStack(stackSize);
01262             if (!stack) {
01263                 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01264                 return NULL;
01265             }
01266 
01267             /* Allocate thread object and per-thread data off the top of the stack*/
01268             top = stack->stackTop;
01269 #ifdef HAVE_STACK_GROWING_UP
01270             thread = (PRThread*) top;
01271             top = top + sizeof(PRThread);
01272             /*
01273              * Make stack 64-byte aligned
01274              */
01275             if ((PRUptrdiff)top & 0x3f) {
01276                 top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f);
01277             }
01278 #else
01279             top = top - sizeof(PRThread);
01280             thread = (PRThread*) top;
01281             /*
01282              * Make stack 64-byte aligned
01283              */
01284             if ((PRUptrdiff)top & 0x3f) {
01285                 top = (char*)((PRUptrdiff)top & ~0x3f);
01286             }
01287 #endif
01288 #if defined(GC_LEAK_DETECTOR)
01289             /*
01290              * sorry, it is not safe to allocate the thread on the stack,
01291              * because we assign to this object before the GC can learn
01292              * about this thread. we'll just leak thread objects instead.
01293              */
01294             thread = PR_NEW(PRThread);
01295 #endif
01296             stack->thr = thread;
01297             memset(thread, 0, sizeof(PRThread));
01298             thread->threadAllocatedOnStack = 1;
01299 #else
01300             thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg);
01301             if (!thread) {
01302                 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
01303                 return NULL;
01304             }
01305             thread->threadAllocatedOnStack = 0;
01306             stack = NULL;
01307             top = NULL;
01308 #endif
01309 
01310             /* Initialize thread */
01311             thread->tpdLength = 0;
01312             thread->privateData = NULL;
01313             thread->stack = stack;
01314             thread->priority = priority;
01315             thread->startFunc = start;
01316             thread->arg = arg;
01317             PR_INIT_CLIST(&thread->lockList);
01318 
01319             if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
01320                 if (thread->threadAllocatedOnStack == 1)
01321                     _PR_FreeStack(thread->stack);
01322                 else {
01323                     PR_DELETE(thread);
01324                 }
01325                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01326                 return NULL;
01327             }
01328 
01329             if (_PR_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
01330                 if (thread->threadAllocatedOnStack == 1)
01331                     _PR_FreeStack(thread->stack);
01332                 else {
01333                     PR_DELETE(thread->privateData);
01334                     PR_DELETE(thread);
01335                 }
01336                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
01337                 return NULL;
01338             }
01339 
01340             _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status);
01341 
01342             if (status == PR_FALSE) {
01343                 _PR_MD_FREE_LOCK(&thread->threadLock);
01344                 if (thread->threadAllocatedOnStack == 1)
01345                     _PR_FreeStack(thread->stack);
01346                 else {
01347                     PR_DELETE(thread->privateData);
01348                     PR_DELETE(thread);
01349                 }
01350                 return NULL;
01351             }
01352 
01353             /* 
01354               Set thread flags related to scope and joinable state. If joinable
01355               thread, allocate a "termination" condition variable.
01356             */
01357             if (state == PR_JOINABLE_THREAD) {
01358                 thread->term = PR_NewCondVar(_pr_terminationCVLock);
01359                 if (thread->term == NULL) {
01360                     _PR_MD_FREE_LOCK(&thread->threadLock);
01361                     if (thread->threadAllocatedOnStack == 1)
01362                         _PR_FreeStack(thread->stack);
01363                     else {
01364                         PR_DELETE(thread->privateData);
01365                         PR_DELETE(thread);
01366                     }
01367                     return NULL;
01368                 }
01369             }
01370   
01371         }
01372   
01373         /* Update thread type counter */
01374         PR_Lock(_pr_activeLock);
01375         thread->flags = flags;
01376         thread->id = ++_pr_utid;
01377         if (type == PR_SYSTEM_THREAD) {
01378             thread->flags |= _PR_SYSTEM;
01379             _pr_systemActive++;
01380         } else {
01381             _pr_userActive++;
01382         }
01383 
01384         /* Make thread runnable */
01385         thread->state = _PR_RUNNABLE;
01386     /*
01387      * Add to list of active threads
01388      */
01389         PR_Unlock(_pr_activeLock);
01390 
01391         if ((! (thread->flags & _PR_IDLE_THREAD)) && _PR_IS_NATIVE_THREAD(me) )
01392             thread->cpu = _PR_GetPrimordialCPU();
01393         else
01394             thread->cpu = _PR_MD_CURRENT_CPU();
01395 
01396         PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
01397 
01398         if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me)) {
01399             _PR_INTSOFF(is);
01400             _PR_RUNQ_LOCK(thread->cpu);
01401             _PR_ADD_RUNQ(thread, thread->cpu, priority);
01402             _PR_RUNQ_UNLOCK(thread->cpu);
01403         }
01404 
01405         if (thread->flags & _PR_IDLE_THREAD) {
01406             /*
01407             ** If the creating thread is a kernel thread, we need to
01408             ** awaken the user thread idle thread somehow; potentially
01409             ** it could be sleeping in its idle loop, and we need to poke
01410             ** it.  To do so, wake the idle thread...  
01411             */
01412             _PR_MD_WAKEUP_WAITER(NULL);
01413         } else if (_PR_IS_NATIVE_THREAD(me)) {
01414             _PR_MD_WAKEUP_WAITER(thread);
01415         }
01416         if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) )
01417             _PR_INTSON(is);
01418     }
01419 
01420     return thread;
01421 }
01422 
01423 PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type,
01424                      void (*start)(void *arg),
01425                      void *arg,
01426                      PRThreadPriority priority,
01427                      PRThreadScope scope,
01428                      PRThreadState state,
01429                      PRUint32 stackSize)
01430 {
01431     return _PR_CreateThread(type, start, arg, priority, scope, state, 
01432                             stackSize, 0);
01433 }
01434 
01435 /*
01436 ** Associate a thread object with an existing native thread.
01437 **     "type" is the type of thread object to attach
01438 **     "priority" is the priority to assign to the thread
01439 **     "stack" defines the shape of the threads stack
01440 **
01441 ** This can return NULL if some kind of error occurs, or if memory is
01442 ** tight.
01443 **
01444 ** This call is not normally needed unless you create your own native
01445 ** thread. PR_Init does this automatically for the primordial thread.
01446 */
01447 PRThread* _PRI_AttachThread(PRThreadType type,
01448     PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags)
01449 {
01450     PRThread *thread;
01451 
01452     if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) {
01453         return thread;
01454     }
01455     _PR_MD_SET_CURRENT_THREAD(NULL);
01456 
01457     /* Clear out any state if this thread was attached before */
01458     _PR_MD_SET_CURRENT_CPU(NULL);
01459 
01460     thread = _PR_AttachThread(type, priority, stack);
01461     if (thread) {
01462         PRIntn is;
01463 
01464         _PR_MD_SET_CURRENT_THREAD(thread);
01465 
01466         thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED;
01467 
01468         if (!stack) {
01469             thread->stack = PR_NEWZAP(PRThreadStack);
01470             if (!thread->stack) {
01471                 _PR_DestroyThread(thread);
01472                 return NULL;
01473             }
01474             thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE;
01475         }
01476         PR_INIT_CLIST(&thread->links);
01477 
01478         if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) {
01479                 PR_DELETE(thread->stack);
01480                 _PR_DestroyThread(thread);
01481                 return NULL;
01482         }
01483 
01484         _PR_MD_SET_CURRENT_CPU(NULL);
01485 
01486         if (_PR_MD_CURRENT_CPU()) {
01487             _PR_INTSOFF(is);
01488             PR_Lock(_pr_activeLock);
01489         }
01490         if (type == PR_SYSTEM_THREAD) {
01491             thread->flags |= _PR_SYSTEM;
01492             _pr_systemActive++;
01493         } else {
01494             _pr_userActive++;
01495         }
01496         if (_PR_MD_CURRENT_CPU()) {
01497             PR_Unlock(_pr_activeLock);
01498             _PR_INTSON(is);
01499         }
01500     }
01501     return thread;
01502 }
01503 
01504 PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type,
01505     PRThreadPriority priority, PRThreadStack *stack)
01506 {
01507 #ifdef XP_MAC
01508 #pragma unused( type, priority, stack )
01509 #endif
01510     return PR_GetCurrentThread();
01511 }
01512 
01513 PR_IMPLEMENT(void) PR_DetachThread(void)
01514 {
01515     /*
01516      * On IRIX, Solaris, and Windows, foreign threads are detached when
01517      * they terminate.
01518      */
01519 #if !defined(IRIX) && !defined(WIN32) \
01520         && !(defined(SOLARIS) && defined(_PR_GLOBAL_THREADS_ONLY))
01521     PRThread *me;
01522     if (_pr_initialized) {
01523         me = _PR_MD_GET_ATTACHED_THREAD();
01524         if ((me != NULL) && (me->flags & _PR_ATTACHED))
01525             _PRI_DetachThread();
01526     }
01527 #endif
01528 }
01529 
01530 void _PRI_DetachThread(void)
01531 {
01532     PRThread *me = _PR_MD_CURRENT_THREAD();
01533 
01534        if (me->flags & _PR_PRIMORDIAL) {
01535               /*
01536                * ignore, if primordial thread
01537                */
01538               return;
01539        }
01540     PR_ASSERT(me->flags & _PR_ATTACHED);
01541     PR_ASSERT(_PR_IS_NATIVE_THREAD(me));
01542     _PR_CleanupThread(me);
01543     PR_DELETE(me->privateData);
01544 
01545     _PR_DecrActiveThreadCount(me);
01546 
01547     _PR_MD_CLEAN_THREAD(me);
01548     _PR_MD_SET_CURRENT_THREAD(NULL);
01549     if (!me->threadAllocatedOnStack) 
01550         PR_DELETE(me->stack);
01551     _PR_MD_FREE_LOCK(&me->threadLock);
01552     PR_DELETE(me);
01553 }
01554 
01555 /*
01556 ** Wait for thread termination:
01557 **     "thread" is the target thread 
01558 **
01559 ** This can return PR_FAILURE if no joinable thread could be found 
01560 ** corresponding to the specified target thread.
01561 **
01562 ** The calling thread is suspended until the target thread completes.
01563 ** Several threads cannot wait for the same thread to complete; one thread
01564 ** will complete successfully and others will terminate with an error PR_FAILURE.
01565 ** The calling thread will not be blocked if the target thread has already
01566 ** terminated.
01567 */
01568 PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread)
01569 {
01570     PRIntn is;
01571     PRCondVar *term;
01572     PRThread *me = _PR_MD_CURRENT_THREAD();
01573 
01574     if (!_PR_IS_NATIVE_THREAD(me))
01575         _PR_INTSOFF(is);
01576     term = thread->term;
01577     /* can't join a non-joinable thread */
01578     if (term == NULL) {
01579         PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
01580         goto ErrorExit;
01581     }
01582 
01583     /* multiple threads can't wait on the same joinable thread */
01584     if (term->condQ.next != &term->condQ) {
01585         goto ErrorExit;
01586     }
01587     if (!_PR_IS_NATIVE_THREAD(me))
01588         _PR_INTSON(is);
01589 
01590     /* wait for the target thread's termination cv invariant */
01591     PR_Lock (_pr_terminationCVLock);
01592     while (thread->state != _PR_JOIN_WAIT) {
01593         (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT);
01594     }
01595     (void) PR_Unlock (_pr_terminationCVLock);
01596     
01597     /* 
01598      Remove target thread from global waiting to join Q; make it runnable
01599      again and put it back on its run Q.  When it gets scheduled later in
01600      _PR_RunThread code, it will clean up its stack.
01601     */    
01602     if (!_PR_IS_NATIVE_THREAD(me))
01603         _PR_INTSOFF(is);
01604     thread->state = _PR_RUNNABLE;
01605     if ( !_PR_IS_NATIVE_THREAD(thread) ) {
01606         _PR_THREAD_LOCK(thread);
01607 
01608         _PR_MISCQ_LOCK(thread->cpu);
01609         _PR_DEL_JOINQ(thread);
01610         _PR_MISCQ_UNLOCK(thread->cpu);
01611 
01612         _PR_AddThreadToRunQ(me, thread);
01613         _PR_THREAD_UNLOCK(thread);
01614     }
01615     if (!_PR_IS_NATIVE_THREAD(me))
01616         _PR_INTSON(is);
01617 
01618     _PR_MD_WAKEUP_WAITER(thread);
01619 
01620     return PR_SUCCESS;
01621 
01622 ErrorExit:
01623     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
01624     return PR_FAILURE;   
01625 }
01626 
01627 PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread,
01628     PRThreadPriority newPri)
01629 {
01630 
01631     /* 
01632     First, pin down the priority.  Not all compilers catch passing out of
01633     range enum here.  If we let bad values thru, priority queues won't work.
01634     */
01635     if ((PRIntn)newPri > (PRIntn)PR_PRIORITY_LAST) {
01636         newPri = PR_PRIORITY_LAST;
01637     } else if ((PRIntn)newPri < (PRIntn)PR_PRIORITY_FIRST) {
01638         newPri = PR_PRIORITY_FIRST;
01639     }
01640         
01641     if ( _PR_IS_NATIVE_THREAD(thread) ) {
01642         thread->priority = newPri;
01643         _PR_MD_SET_PRIORITY(&(thread->md), newPri);
01644     } else _PR_SetThreadPriority(thread, newPri);
01645 }
01646 
01647 
01648 /*
01649 ** This routine prevents all other threads from running. This call is needed by 
01650 ** the garbage collector.
01651 */
01652 PR_IMPLEMENT(void) PR_SuspendAll(void)
01653 {
01654     PRThread *me = _PR_MD_CURRENT_THREAD();
01655     PRCList *qp;
01656 
01657     /*
01658      * Stop all user and native threads which are marked GC able.
01659      */
01660     PR_Lock(_pr_activeLock);
01661     suspendAllOn = PR_TRUE;
01662     suspendAllThread = _PR_MD_CURRENT_THREAD();
01663     _PR_MD_BEGIN_SUSPEND_ALL();
01664     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
01665         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
01666         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && 
01667             _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp))) {
01668             _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp));
01669                 PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING);
01670             }
01671     }
01672     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
01673         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
01674         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
01675             _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
01676             /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */
01677                 _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); 
01678     }
01679     _PR_MD_END_SUSPEND_ALL();
01680 }
01681 
01682 /*
01683 ** This routine unblocks all other threads that were suspended from running by 
01684 ** PR_SuspendAll(). This call is needed by the garbage collector.
01685 */
01686 PR_IMPLEMENT(void) PR_ResumeAll(void)
01687 {
01688     PRThread *me = _PR_MD_CURRENT_THREAD();
01689     PRCList *qp;
01690 
01691     /*
01692      * Resume all user and native threads which are marked GC able.
01693      */
01694     _PR_MD_BEGIN_RESUME_ALL();
01695     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
01696         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
01697         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && 
01698             _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
01699             _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp));
01700     }
01701     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
01702         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
01703         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
01704             _PR_IS_GCABLE_THREAD(_PR_ACTIVE_THREAD_PTR(qp)))
01705                 _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp));
01706     }
01707     _PR_MD_END_RESUME_ALL();
01708     suspendAllThread = NULL;
01709     suspendAllOn = PR_FALSE;
01710     PR_Unlock(_pr_activeLock);
01711 }
01712 
01713 PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
01714 {
01715     PRCList *qp, *qp_next;
01716     PRIntn i = 0;
01717     PRStatus rv = PR_SUCCESS;
01718     PRThread* t;
01719 
01720     /*
01721     ** Currently Enumerate threads happen only with suspension and
01722     ** pr_activeLock held
01723     */
01724     PR_ASSERT(suspendAllOn);
01725 
01726     /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
01727      * qp->next after applying the function "func".  In particular, "func"
01728      * might remove the thread from the queue and put it into another one in
01729      * which case qp->next no longer points to the next entry in the original
01730      * queue.
01731      *
01732      * To get around this problem, we save qp->next in qp_next before applying
01733      * "func" and use that saved value as the next value after applying "func".
01734      */
01735 
01736     /*
01737      * Traverse the list of local and global threads
01738      */
01739     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
01740          qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next)
01741     {
01742         qp_next = qp->next;
01743         t = _PR_ACTIVE_THREAD_PTR(qp);
01744         if (_PR_IS_GCABLE_THREAD(t))
01745         {
01746             rv = (*func)(t, i, arg);
01747             if (rv != PR_SUCCESS)
01748                 return rv;
01749             i++;
01750         }
01751     }
01752     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
01753          qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next)
01754     {
01755         qp_next = qp->next;
01756         t = _PR_ACTIVE_THREAD_PTR(qp);
01757         if (_PR_IS_GCABLE_THREAD(t))
01758         {
01759             rv = (*func)(t, i, arg);
01760             if (rv != PR_SUCCESS)
01761                 return rv;
01762             i++;
01763         }
01764     }
01765     return rv;
01766 }
01767 
01768 /* FUNCTION: _PR_AddSleepQ
01769 ** DESCRIPTION:
01770 **    Adds a thread to the sleep/pauseQ.
01771 ** RESTRICTIONS:
01772 **    Caller must have the RUNQ lock.
01773 **    Caller must be a user level thread
01774 */
01775 PR_IMPLEMENT(void)
01776 _PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout)
01777 {
01778     _PRCPU *cpu = thread->cpu;
01779 
01780     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
01781         /* append the thread to the global pause Q */
01782         PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu));
01783         thread->flags |= _PR_ON_PAUSEQ;
01784     } else {
01785         PRIntervalTime sleep;
01786         PRCList *q;
01787         PRThread *t;
01788 
01789         /* sort onto global sleepQ */
01790         sleep = timeout;
01791 
01792         /* Check if we are longest timeout */
01793         if (timeout >= _PR_SLEEPQMAX(cpu)) {
01794             PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu));
01795             thread->sleep = timeout - _PR_SLEEPQMAX(cpu);
01796             _PR_SLEEPQMAX(cpu) = timeout;
01797         } else {
01798             /* Sort thread into global sleepQ at appropriate point */
01799             q = _PR_SLEEPQ(cpu).next;
01800 
01801             /* Now scan the list for where to insert this entry */
01802             while (q != &_PR_SLEEPQ(cpu)) {
01803                 t = _PR_THREAD_PTR(q);
01804                 if (sleep < t->sleep) {
01805                     /* Found sleeper to insert in front of */
01806                     break;
01807                 }
01808                 sleep -= t->sleep;
01809                 q = q->next;
01810             }
01811             thread->sleep = sleep;
01812             PR_INSERT_BEFORE(&thread->links, q);
01813 
01814             /*
01815             ** Subtract our sleep time from the sleeper that follows us (there
01816             ** must be one) so that they remain relative to us.
01817             */
01818             PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu));
01819           
01820             t = _PR_THREAD_PTR(thread->links.next);
01821             PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread);
01822             t->sleep -= sleep;
01823         }
01824 
01825         thread->flags |= _PR_ON_SLEEPQ;
01826     }
01827 }
01828 
01829 /* FUNCTION: _PR_DelSleepQ
01830 ** DESCRIPTION:
01831 **    Removes a thread from the sleep/pauseQ.
01832 ** INPUTS:
01833 **    If propogate_time is true, then the thread following the deleted
01834 **    thread will be get the time from the deleted thread.  This is used
01835 **    when deleting a sleeper that has not timed out.
01836 ** RESTRICTIONS:
01837 **    Caller must have the RUNQ lock.
01838 **    Caller must be a user level thread
01839 */
01840 PR_IMPLEMENT(void)
01841 _PR_DelSleepQ(PRThread *thread, PRBool propogate_time)
01842 {
01843     _PRCPU *cpu = thread->cpu;
01844 
01845     /* Remove from pauseQ/sleepQ */
01846     if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
01847         if (thread->flags & _PR_ON_SLEEPQ) {
01848             PRCList *q = thread->links.next;
01849             if (q != &_PR_SLEEPQ(cpu)) {
01850                 if (propogate_time == PR_TRUE) {
01851                     PRThread *after = _PR_THREAD_PTR(q);
01852                     after->sleep += thread->sleep;
01853                 } else 
01854                     _PR_SLEEPQMAX(cpu) -= thread->sleep;
01855             } else {
01856                 /* Check if prev is the beggining of the list; if so,
01857                  * we are the only element on the list.  
01858                  */
01859                 if (thread->links.prev != &_PR_SLEEPQ(cpu))
01860                     _PR_SLEEPQMAX(cpu) -= thread->sleep;
01861                 else
01862                     _PR_SLEEPQMAX(cpu) = 0;
01863             }
01864             thread->flags &= ~_PR_ON_SLEEPQ;
01865         } else {
01866             thread->flags &= ~_PR_ON_PAUSEQ;
01867         }
01868         PR_REMOVE_LINK(&thread->links);
01869     } else 
01870         PR_ASSERT(0);
01871 }
01872 
01873 void
01874 _PR_AddThreadToRunQ(
01875     PRThread *me,     /* the current thread */
01876     PRThread *thread) /* the local thread to be added to a run queue */
01877 {
01878     PRThreadPriority pri = thread->priority;
01879     _PRCPU *cpu = thread->cpu;
01880 
01881     PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
01882 
01883 #if defined(WINNT)
01884     /*
01885      * On NT, we can only reliably know that the current CPU
01886      * is not idle.  We add the awakened thread to the run
01887      * queue of its CPU if its CPU is the current CPU.
01888      * For any other CPU, we don't really know whether it
01889      * is busy or idle.  So in all other cases, we just
01890      * "post" the awakened thread to the IO completion port
01891      * for the next idle CPU to execute (this is done in
01892      * _PR_MD_WAKEUP_WAITER).
01893         * Threads with a suspended I/O operation remain bound to
01894         * the same cpu until I/O is cancelled
01895      *
01896      * NOTE: the boolean expression below must be the exact
01897      * opposite of the corresponding boolean expression in
01898      * _PR_MD_WAKEUP_WAITER.
01899      */
01900     if ((!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) ||
01901                                    (thread->md.thr_bound_cpu)) {
01902               PR_ASSERT(!thread->md.thr_bound_cpu ||
01903                                                  (thread->md.thr_bound_cpu == cpu));
01904         _PR_RUNQ_LOCK(cpu);
01905         _PR_ADD_RUNQ(thread, cpu, pri);
01906         _PR_RUNQ_UNLOCK(cpu);
01907     }
01908 #else
01909     _PR_RUNQ_LOCK(cpu);
01910     _PR_ADD_RUNQ(thread, cpu, pri);
01911     _PR_RUNQ_UNLOCK(cpu);
01912     if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {
01913         if (pri > me->priority) {
01914             _PR_SET_RESCHED_FLAG();
01915         }
01916     }
01917 #endif
01918 }