home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / threads / combined / pruthr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  52.6 KB  |  1,795 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /*
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  * 
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  * 
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "primpl.h"
  20. #include <signal.h>
  21. #include <string.h>
  22.  
  23. /* _pr_activeLock protects the following global variables */
  24. PRLock *_pr_activeLock;
  25. PRUintn _pr_primordialExitCount;   /* In PR_Cleanup(), the primordial thread
  26.                     * waits until all other user (non-system)
  27.                     * threads have terminated before it exits.
  28.                     * So whenever we decrement _pr_userActive,
  29.                     * it is compared with
  30.                     * _pr_primordialExitCount.
  31.                     * If the primordial thread is a system
  32.                     * thread, then _pr_primordialExitCount
  33.                     * is 0.  If the primordial thread is
  34.                     * itself a user thread, then 
  35.                     * _pr_primordialThread is 1.
  36.                     */
  37. PRCondVar *_pr_primordialExitCVar; /* When _pr_userActive is decremented to
  38.                     * _pr_primordialExitCount, this condition
  39.                     * variable is notified.
  40.                     */
  41.  
  42. PRLock *_pr_deadQLock;
  43. PRUint32 _pr_numNativeDead;
  44. PRUint32 _pr_numUserDead;
  45. PRCList _pr_deadNativeQ;
  46. PRCList _pr_deadUserQ;
  47.  
  48. PRUint32 _pr_join_counter;
  49.  
  50. PRUint32 _pr_local_threads;
  51. PRUint32 _pr_global_threads;
  52.  
  53. PRBool suspendAllOn = PR_FALSE;
  54. PRThread *suspendAllThread = NULL;
  55.  
  56. extern PRCList _pr_active_global_threadQ;
  57. extern PRCList _pr_active_local_threadQ;
  58. extern _PRCPU  *_pr_primordialCPU;
  59.  
  60. static void _PR_DecrActiveThreadCount(PRThread *thread);
  61. static PRThread *_PR_AttachThread(PRThreadType, PRThreadPriority, PRThreadStack *);
  62. static void _PR_InitializeNativeStack(PRThreadStack *ts);
  63. static void _PR_InitializeRecycledThread(PRThread *thread);
  64.  
  65. void _PR_InitThreads(PRThreadType type, PRThreadPriority priority,
  66.     PRUintn maxPTDs)
  67. {
  68. #if defined(XP_MAC)
  69. #pragma unused (maxPTDs)
  70. #endif
  71.  
  72.     PRThread *thread;
  73.     PRThreadStack *stack;
  74.  
  75.     _pr_terminationCVLock = PR_NewLock();
  76.     _pr_activeLock = PR_NewLock();
  77.  
  78. #ifndef HAVE_CUSTOM_USER_THREADS
  79.     stack = PR_NEWZAP(PRThreadStack);
  80. #ifdef HAVE_STACK_GROWING_UP
  81.     stack->stackTop = (char*) ((((long)&type) >> _pr_pageShift)
  82.                   << _pr_pageShift);
  83. #else
  84. #if defined(SOLARIS) || defined (UNIXWARE) && defined (USR_SVR4_THREADS)
  85.     stack->stackTop = (char*) &thread;
  86. #else
  87.     stack->stackTop = (char*) ((((long)&type + _pr_pageSize - 1)
  88.                 >> _pr_pageShift) << _pr_pageShift);
  89. #endif
  90. #endif
  91. #else
  92.     /* If stack is NULL, we're using custom user threads like NT fibers. */
  93.     stack = PR_NEWZAP(PRThreadStack);
  94.     if (stack) {
  95.         stack->stackSize = 0;
  96.         _PR_InitializeNativeStack(stack);
  97.     }
  98. #endif /* HAVE_CUSTOM_USER_THREADS */
  99.  
  100.     thread = _PR_AttachThread(type, priority, stack);
  101.     if (thread) {
  102.         _PR_MD_SET_CURRENT_THREAD(thread);
  103.  
  104.         if (type == PR_SYSTEM_THREAD) {
  105.             thread->flags = _PR_SYSTEM;
  106.             _pr_systemActive++;
  107.             _pr_primordialExitCount = 0;
  108.         } else {
  109.             _pr_userActive++;
  110.             _pr_primordialExitCount = 1;
  111.         }
  112.     thread->no_sched = 1;
  113.     _pr_primordialExitCVar = PR_NewCondVar(_pr_activeLock);
  114.     }
  115.  
  116.     if (!thread) PR_Abort();
  117. #ifdef _PR_GLOBAL_THREADS_ONLY
  118.     thread->flags |= _PR_PRIMORDIAL | _PR_GLOBAL_SCOPE;
  119. #else
  120.     thread->flags |= _PR_PRIMORDIAL;
  121. #endif
  122.  
  123.     /* Needs _PR_PRIMORDIAL flag set before calling _PR_MD_INIT_THREAD() */
  124.     if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
  125.         /*
  126.          * XXX do what?
  127.          */
  128.     }
  129.  
  130.     if (_PR_IS_NATIVE_THREAD(thread)) {
  131.         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
  132.         _pr_global_threads++;
  133.     } else {
  134.         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
  135.         _pr_local_threads++;
  136.     }
  137.  
  138.     _pr_recycleThreads = 0;
  139.     _pr_deadQLock = PR_NewLock();
  140.     _pr_numNativeDead = 0;
  141.     _pr_numUserDead = 0;
  142.     PR_INIT_CLIST(&_pr_deadNativeQ);
  143.     PR_INIT_CLIST(&_pr_deadUserQ);
  144. }
  145.  
  146. /*
  147. ** Initialize a stack for a native thread
  148. */
  149. static void _PR_InitializeNativeStack(PRThreadStack *ts)
  150. {
  151.     if( ts && (ts->stackTop == 0) ) {
  152.         ts->allocSize = ts->stackSize;
  153.  
  154.         /*
  155.         ** Setup stackTop and stackBottom values.
  156.         */
  157. #ifdef HAVE_STACK_GROWING_UP
  158.     ts->allocBase = (char*) ((((long)&ts) >> _pr_pageShift)
  159.                   << _pr_pageShift);
  160.         ts->stackBottom = ts->allocBase + ts->stackSize;
  161.         ts->stackTop = ts->allocBase;
  162. #else
  163.         ts->allocBase = (char*) ((((long)&ts + _pr_pageSize - 1)
  164.                 >> _pr_pageShift) << _pr_pageShift);
  165.         ts->stackTop    = ts->allocBase;
  166.         ts->stackBottom = ts->allocBase - ts->stackSize;
  167. #endif
  168.     }
  169. }
  170.  
  171. void _PR_NotifyJoinWaiters(PRThread *thread)
  172. {
  173.     /*
  174.     ** Handle joinable threads.  Change the state to waiting for join.
  175.     ** Remove from our run Q and put it on global waiting to join Q.
  176.     ** Notify on our "termination" condition variable so that joining
  177.     ** thread will know about our termination.  Switch our context and
  178.     ** come back later on to continue the cleanup.
  179.     */    
  180.     PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
  181.     if (thread->term != NULL) {
  182.         PR_Lock(_pr_terminationCVLock);
  183.         _PR_THREAD_LOCK(thread);
  184.         thread->state = _PR_JOIN_WAIT;
  185.         if ( !_PR_IS_NATIVE_THREAD(thread) ) {
  186.             _PR_MISCQ_LOCK(thread->cpu);
  187.             _PR_ADD_JOINQ(thread, thread->cpu);
  188.             _PR_MISCQ_UNLOCK(thread->cpu);
  189.         }
  190.         _PR_THREAD_UNLOCK(thread);
  191.         PR_NotifyCondVar(thread->term);
  192.         PR_Unlock(_pr_terminationCVLock);
  193.         _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
  194.         PR_ASSERT(thread->state != _PR_JOIN_WAIT);
  195.     }
  196.  
  197. }
  198.  
  199. /*
  200.  * Zero some of the data members of a recycled thread.
  201.  *
  202.  * Note that we can do this either when a dead thread is added to
  203.  * the dead thread queue or when it is reused.  Here, we are doing
  204.  * this lazily, when the thread is reused in _PR_CreateThread().
  205.  */
  206. static void _PR_InitializeRecycledThread(PRThread *thread)
  207. {
  208.     /*
  209.      * Assert that the following data members are already zeroed
  210.      * by _PR_CleanupThread().
  211.      */
  212. #ifdef DEBUG
  213.     if (thread->privateData) {
  214.         unsigned int i;
  215.         for (i = 0; i < thread->tpdLength; i++) {
  216.             PR_ASSERT(thread->privateData[i] == NULL);
  217.         }
  218.     }
  219. #endif
  220.     PR_ASSERT(thread->dumpArg == 0 && thread->dump == 0);
  221.     PR_ASSERT(thread->numExits == 0 && thread->ptes == 0);
  222.     PR_ASSERT(thread->errorString == 0 && thread->errorStringSize == 0);
  223.  
  224.     /* Reset data members in thread structure */
  225.     thread->errorCode = thread->osErrorCode = 0;
  226.     thread->io_pending = thread->io_suspended = PR_FALSE;
  227.     thread->environment = 0;
  228.     PR_INIT_CLIST(&thread->lockList);
  229. }
  230.  
  231. PRStatus _PR_RecycleThread(PRThread *thread)
  232. {
  233.     if ( _PR_IS_NATIVE_THREAD(thread) &&
  234.             _PR_NUM_DEADNATIVE < _pr_recycleThreads) {
  235.         _PR_DEADQ_LOCK;
  236.         PR_APPEND_LINK(&thread->links, &_PR_DEADNATIVEQ);
  237.         _PR_INC_DEADNATIVE;
  238.         _PR_DEADQ_UNLOCK;
  239.     return (PR_SUCCESS);
  240.     } else if ( !_PR_IS_NATIVE_THREAD(thread) &&
  241.                 _PR_NUM_DEADUSER < _pr_recycleThreads) {
  242.         _PR_DEADQ_LOCK;
  243.         PR_APPEND_LINK(&thread->links, &_PR_DEADUSERQ);
  244.         _PR_INC_DEADUSER;
  245.         _PR_DEADQ_UNLOCK;
  246.     return (PR_SUCCESS);
  247.     }
  248.     return (PR_FAILURE);
  249. }
  250.  
  251. /*
  252.  * Decrement the active thread count, either _pr_systemActive or
  253.  * _pr_userActive, depending on whether the thread is a system thread
  254.  * or a user thread.  If all the user threads, except possibly
  255.  * the primordial thread, have terminated, we notify the primordial
  256.  * thread of this condition.
  257.  *
  258.  * Since this function will lock _pr_activeLock, do not call this
  259.  * function while holding the _pr_activeLock lock, as this will result
  260.  * in a deadlock.
  261.  */
  262.  
  263. static void
  264. _PR_DecrActiveThreadCount(PRThread *thread)
  265. {
  266.     PR_Lock(_pr_activeLock);
  267.     if (thread->flags & _PR_SYSTEM) {
  268.         _pr_systemActive--;
  269.     } else {
  270.         _pr_userActive--;
  271.         if (_pr_userActive == _pr_primordialExitCount) {
  272.             PR_NotifyCondVar(_pr_primordialExitCVar);
  273.         }
  274.     }
  275.     PR_Unlock(_pr_activeLock);
  276. }
  277.  
  278. /*
  279. ** Detach thread structure
  280. */
  281. static void
  282. _PR_DetachThread(PRThread *thread)
  283. {
  284.     _MD_FREE_LOCK(&thread->threadLock);
  285.     PR_DELETE(thread);
  286. }
  287.  
  288. void
  289. _PR_NativeDestroyThread(PRThread *thread)
  290. {
  291.     if(thread->term) {
  292.         PR_DestroyCondVar(thread->term);
  293.         thread->term = 0;
  294.     }
  295.  
  296.     PR_DELETE(thread->stack);
  297.     _PR_DetachThread(thread);
  298. }
  299.  
  300. void
  301. _PR_UserDestroyThread(PRThread *thread)
  302. {
  303.     if(thread->term) {
  304.         PR_DestroyCondVar(thread->term);
  305.         thread->term = 0;
  306.     }
  307.     if (NULL != thread->privateData)
  308.     {
  309.         PR_ASSERT(0 != thread->tpdLength);
  310.         PR_DELETE(thread->privateData);
  311.         thread->privateData = NULL;
  312.         thread->tpdLength = 0;
  313.     }
  314.     _MD_FREE_LOCK(&thread->threadLock);
  315.     if (thread->threadAllocatedOnStack == 1) {
  316.         _PR_MD_CLEAN_THREAD(thread);
  317.         /*
  318.           *  Because the no_sched field is set, this thread/stack will
  319.           *  will not be re-used until the flag is cleared by the thread
  320.           *  we will context switch to.
  321.           */
  322.     _PR_FreeStack(thread->stack);
  323.     } else {
  324. #ifdef WINNT
  325.     _PR_MD_CLEAN_THREAD(thread);
  326. #else
  327.         /*
  328.          * This assertion does not apply to NT.  On NT, every fiber,
  329.          * including the primordial thread, has its threadAllocatedOnStack
  330.          * equal to 0.  Elsewhere, only the primordial thread has its
  331.          * threadAllocatedOnStack equal to 0.
  332.          */
  333.         PR_ASSERT(thread->flags & _PR_PRIMORDIAL);
  334. #endif
  335.     }
  336. }
  337.  
  338.  
  339. /*
  340. ** Run a thread's start function. When the start function returns the
  341. ** thread is done executing and no longer needs the CPU. If there are no
  342. ** more user threads running then we can exit the program.
  343. */
  344. void _PR_NativeRunThread(void *arg)
  345. {
  346.     PRThread *thread = (PRThread *)arg;
  347.  
  348.     _PR_MD_SET_CURRENT_THREAD(thread);
  349.  
  350.     _PR_MD_SET_CURRENT_CPU(NULL);
  351.  
  352.     /* Set up the thread stack information */
  353.     _PR_InitializeNativeStack(thread->stack);
  354.  
  355.     /* Set up the thread md information */
  356.     if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
  357.         /*
  358.          * thread failed to initialize itself, possibly due to
  359.          * failure to allocate per-thread resources
  360.          */
  361.         return;
  362.     }
  363.  
  364.     while(1) {
  365.         thread->state = _PR_RUNNING;
  366.  
  367.         if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_SET_INTSOFF(0);
  368.  
  369.         /*
  370.          * Add to list of active threads
  371.          */
  372.         PR_Lock(_pr_activeLock);
  373.         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_GLOBAL_THREADQ());
  374.         _pr_global_threads++;
  375.         PR_Unlock(_pr_activeLock);
  376.  
  377.         (*thread->startFunc)(thread->arg);
  378.  
  379.         /*
  380.          * The following two assertions are meant for NT asynch io.
  381.          *
  382.          * The thread should have no asynch io in progress when it
  383.          * exits, otherwise the overlapped buffer, which is part of
  384.          * the thread structure, would become invalid.
  385.          */
  386.         PR_ASSERT(thread->io_pending == PR_FALSE);
  387.         /*
  388.          * This assertion enforces the programming guideline that
  389.          * if an io function times out or is interrupted, the thread
  390.          * should close the fd to force the asynch io to abort
  391.          * before it exits.  Right now, closing the fd is the only
  392.          * way to clear the io_suspended flag.
  393.          */
  394.         PR_ASSERT(thread->io_suspended == PR_FALSE);
  395.  
  396.         /*
  397.          * remove thread from list of active threads
  398.          */
  399.         PR_Lock(_pr_activeLock);
  400.         PR_REMOVE_LINK(&thread->active);
  401.         _pr_global_threads--;
  402.         PR_Unlock(_pr_activeLock);
  403.  
  404.         PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));
  405.  
  406.         /* All done, time to go away */
  407.         _PR_CleanupThread(thread);
  408.  
  409.         _PR_NotifyJoinWaiters(thread);
  410.  
  411.         _PR_DecrActiveThreadCount(thread);
  412.  
  413.         thread->state = _PR_DEAD_STATE;
  414.  
  415.         if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
  416.                         PR_FAILURE)) {
  417.             /*
  418.              * thread not recycled
  419.              * platform-specific thread exit processing
  420.              *        - for stuff like releasing native-thread resources, etc.
  421.              */
  422.             _PR_MD_EXIT_THREAD(thread);
  423.             /*
  424.              * Free memory allocated for the thread
  425.              */
  426.             _PR_NativeDestroyThread(thread);
  427.             /*
  428.              * thread gone, cannot de-reference thread now
  429.              */
  430.             return;
  431.         }
  432.  
  433.         /* Now wait for someone to activate us again... */
  434.         _PR_MD_WAIT(thread, PR_INTERVAL_NO_TIMEOUT);
  435.     }
  436. }
  437.  
  438. void _PR_UserRunThread(void)
  439. {
  440.     PRThread *thread = _PR_MD_CURRENT_THREAD();
  441.     PRIntn is;
  442.  
  443.     if (_MD_LAST_THREAD())
  444.     _MD_LAST_THREAD()->no_sched = 0;
  445.  
  446. #ifdef HAVE_CUSTOM_USER_THREADS
  447.     if (thread->stack == NULL) {
  448.         thread->stack = PR_NEWZAP(PRThreadStack);
  449.         _PR_InitializeNativeStack(thread->stack);
  450.     }
  451. #endif /* HAVE_CUSTOM_USER_THREADS */
  452.  
  453.     while(1) {
  454.         /* Run thread main */
  455.         if ( !_PR_IS_NATIVE_THREAD(thread)) _PR_SET_INTSOFF(0);
  456.  
  457.     /*
  458.      * Add to list of active threads
  459.      */
  460.     if (!(thread->flags & _PR_IDLE_THREAD)) {
  461.         PR_Lock(_pr_activeLock);
  462.         PR_APPEND_LINK(&thread->active, &_PR_ACTIVE_LOCAL_THREADQ());
  463.         _pr_local_threads++;
  464.         PR_Unlock(_pr_activeLock);
  465.     }
  466.  
  467.         (*thread->startFunc)(thread->arg);
  468.  
  469.         /*
  470.          * The following two assertions are meant for NT asynch io.
  471.          *
  472.          * The thread should have no asynch io in progress when it
  473.          * exits, otherwise the overlapped buffer, which is part of
  474.          * the thread structure, would become invalid.
  475.          */
  476.         PR_ASSERT(thread->io_pending == PR_FALSE);
  477.         /*
  478.          * This assertion enforces the programming guideline that
  479.          * if an io function times out or is interrupted, the thread
  480.          * should close the fd to force the asynch io to abort
  481.          * before it exits.  Right now, closing the fd is the only
  482.          * way to clear the io_suspended flag.
  483.          */
  484.         PR_ASSERT(thread->io_suspended == PR_FALSE);
  485.  
  486.         PR_Lock(_pr_activeLock);
  487.     /*
  488.      * remove thread from list of active threads
  489.      */
  490.     if (!(thread->flags & _PR_IDLE_THREAD)) {
  491.            PR_REMOVE_LINK(&thread->active);
  492.         _pr_local_threads--;
  493.     }
  494.     PR_Unlock(_pr_activeLock);
  495.         PR_LOG(_pr_thread_lm, PR_LOG_MIN, ("thread exiting"));
  496.  
  497.         /* All done, time to go away */
  498.         _PR_CleanupThread(thread);
  499.  
  500.         _PR_INTSOFF(is);    
  501.  
  502.         _PR_NotifyJoinWaiters(thread);
  503.  
  504.     _PR_DecrActiveThreadCount(thread);
  505.  
  506.         thread->state = _PR_DEAD_STATE;
  507.  
  508.         if (!_pr_recycleThreads || (_PR_RecycleThread(thread) ==
  509.                         PR_FAILURE)) {
  510.             /*
  511.             ** Destroy the thread resources
  512.             */
  513.         _PR_UserDestroyThread(thread);
  514.         }
  515.  
  516.         /*
  517.         ** Find another user thread to run. This cpu has finished the
  518.         ** previous threads main and is now ready to run another thread.
  519.         */
  520.         {
  521.             PRInt32 is;
  522.             _PR_INTSOFF(is);
  523.             _PR_MD_SWITCH_CONTEXT(thread);
  524.         }
  525.  
  526.         /* Will land here when we get scheduled again if we are recycling... */
  527.     }
  528. }
  529.  
  530. void _PR_SetThreadPriority(PRThread *thread, PRThreadPriority newPri)
  531. {
  532.     PRThread *me = _PR_MD_CURRENT_THREAD();
  533.     PRIntn is;
  534.  
  535.     if ( _PR_IS_NATIVE_THREAD(thread) ) {
  536.         _PR_MD_SET_PRIORITY(&(thread->md), newPri);
  537.         return;
  538.     }
  539.  
  540.     if (!_PR_IS_NATIVE_THREAD(me))
  541.     _PR_INTSOFF(is);
  542.     _PR_THREAD_LOCK(thread);
  543.     if (newPri != thread->priority) {
  544.     PRUintn oldPri;
  545.         _PRCPU *cpu = thread->cpu;
  546.  
  547.     oldPri = thread->priority;
  548.     switch (thread->state) {
  549.       case _PR_RUNNING:
  550.         /* Change my priority */
  551.  
  552.             _PR_RUNQ_LOCK(cpu);
  553.         thread->priority = newPri;
  554.         if (_PR_RUNQREADYMASK(cpu) >> (newPri + 1)) {
  555.             if (!_PR_IS_NATIVE_THREAD(me))
  556.                     _PR_SET_RESCHED_FLAG();
  557.         }
  558.             _PR_RUNQ_UNLOCK(cpu);
  559.         break;
  560.  
  561.       case _PR_RUNNABLE:
  562.  
  563.         _PR_RUNQ_LOCK(cpu);
  564.             /* Move to different runQ */
  565.             _PR_DEL_RUNQ(thread);
  566.             thread->priority = newPri;
  567.             PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  568.             _PR_ADD_RUNQ(thread, cpu, newPri);
  569.         _PR_RUNQ_UNLOCK(cpu);
  570.  
  571.             if (newPri > me->priority) {
  572.             if (!_PR_IS_NATIVE_THREAD(me))
  573.                     _PR_SET_RESCHED_FLAG();
  574.             }
  575.  
  576.         break;
  577.  
  578.       case _PR_LOCK_WAIT:
  579.       case _PR_COND_WAIT:
  580.       case _PR_IO_WAIT:
  581.       case _PR_SUSPENDED:
  582.  
  583.         thread->priority = newPri;
  584.         break;
  585.     }
  586.     }
  587.     _PR_THREAD_UNLOCK(thread);
  588.     if (!_PR_IS_NATIVE_THREAD(me))
  589.     _PR_INTSON(is);
  590. }
  591.  
  592. /*
  593. ** Suspend the named thread and copy its gc registers into regBuf
  594. */
  595. static void _PR_Suspend(PRThread *thread)
  596. {
  597.     PRIntn is;
  598.     PRThread *me = _PR_MD_CURRENT_THREAD();
  599.  
  600.     PR_ASSERT(thread != me);
  601.     PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread) || (!thread->cpu));
  602.  
  603.     if (!_PR_IS_NATIVE_THREAD(me))
  604.         _PR_INTSOFF(is);
  605.     _PR_THREAD_LOCK(thread);
  606.     switch (thread->state) {
  607.       case _PR_RUNNABLE:
  608.         if (!_PR_IS_NATIVE_THREAD(thread)) {
  609.             _PR_RUNQ_LOCK(thread->cpu);
  610.             _PR_DEL_RUNQ(thread);
  611.             _PR_RUNQ_UNLOCK(thread->cpu);
  612.  
  613.             _PR_MISCQ_LOCK(thread->cpu);
  614.             _PR_ADD_SUSPENDQ(thread, thread->cpu);
  615.             _PR_MISCQ_UNLOCK(thread->cpu);
  616.         } else {
  617.             /*
  618.              * Only LOCAL threads are suspended by _PR_Suspend
  619.              */
  620.              PR_ASSERT(0);
  621.         }
  622.         thread->state = _PR_SUSPENDED;
  623.         break;
  624.  
  625.       case _PR_RUNNING:
  626.         /*
  627.          * The thread being suspended should be a LOCAL thread with
  628.          * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
  629.          */
  630.         PR_ASSERT(0);
  631.         break;
  632.  
  633.       case _PR_LOCK_WAIT:
  634.       case _PR_IO_WAIT:
  635.       case _PR_COND_WAIT:
  636.         if (_PR_IS_NATIVE_THREAD(thread)) {
  637.             _PR_MD_SUSPEND_THREAD(thread);
  638.     }
  639.         thread->flags |= _PR_SUSPENDING;
  640.         break;
  641.  
  642.       default:
  643.         PR_Abort();
  644.     }
  645.     _PR_THREAD_UNLOCK(thread);
  646.     if (!_PR_IS_NATIVE_THREAD(me))
  647.     _PR_INTSON(is);
  648. }
  649.  
  650. static void _PR_Resume(PRThread *thread)
  651. {
  652.     PRThreadPriority pri;
  653.     PRIntn is;
  654.     PRThread *me = _PR_MD_CURRENT_THREAD();
  655.  
  656.     if (!_PR_IS_NATIVE_THREAD(me))
  657.     _PR_INTSOFF(is);
  658.     _PR_THREAD_LOCK(thread);
  659.     switch (thread->state) {
  660.       case _PR_SUSPENDED:
  661.         thread->state = _PR_RUNNABLE;
  662.         thread->flags &= ~_PR_SUSPENDING;
  663.         if (!_PR_IS_NATIVE_THREAD(thread)) {
  664.             _PR_MISCQ_LOCK(thread->cpu);
  665.             _PR_DEL_SUSPENDQ(thread);
  666.             _PR_MISCQ_UNLOCK(thread->cpu);
  667.  
  668.             pri = thread->priority;
  669.  
  670.             _PR_RUNQ_LOCK(thread->cpu);
  671.             _PR_ADD_RUNQ(thread, thread->cpu, pri);
  672.             _PR_RUNQ_UNLOCK(thread->cpu);
  673.  
  674.             if (pri > _PR_MD_CURRENT_THREAD()->priority) {
  675.                 if (!_PR_IS_NATIVE_THREAD(me))
  676.                     _PR_SET_RESCHED_FLAG();
  677.             }
  678.         } else {
  679.             PR_ASSERT(0);
  680.         }
  681.         break;
  682.  
  683.       case _PR_IO_WAIT:
  684.       case _PR_COND_WAIT:
  685.         thread->flags &= ~_PR_SUSPENDING;
  686. /*      PR_ASSERT(thread->wait.monitor->stickyCount == 0); */
  687.         break;
  688.  
  689.       case _PR_LOCK_WAIT: 
  690.       {
  691.         PRLock *wLock = thread->wait.lock;
  692.  
  693.         thread->flags &= ~_PR_SUSPENDING;
  694.  
  695.         _PR_LOCK_LOCK(wLock);
  696.         if (thread->wait.lock->owner == 0) {
  697.             _PR_AssignLock(thread->wait.lock);
  698.         }
  699.         _PR_LOCK_UNLOCK(wLock);
  700.         break;
  701.       }
  702.       case _PR_RUNNABLE:
  703.         break;
  704.       case _PR_RUNNING:
  705.         /*
  706.          * The thread being suspended should be a LOCAL thread with
  707.          * _pr_numCPUs == 1. Hence, the thread cannot be in RUNNING state
  708.          */
  709.         PR_ASSERT(0);
  710.         break;
  711.  
  712.       default:
  713.     /*
  714.      * thread should have been in one of the above-listed blocked states
  715.      * (_PR_JOIN_WAIT, _PR_IO_WAIT, _PR_UNBORN, _PR_DEAD_STATE)
  716.      */
  717.         PR_Abort();
  718.     }
  719.     _PR_THREAD_UNLOCK(thread);
  720.     if (!_PR_IS_NATIVE_THREAD(me))
  721.         _PR_INTSON(is);
  722.  
  723. }
  724.  
  725. static PRThread *get_thread(_PRCPU *cpu)
  726. {
  727.     PRThread *thread;
  728.     PRIntn pri;
  729.     PRUint32 r;
  730.     PRCList *qp;
  731.     PRIntn priMin, priMax;
  732.  
  733.     _PR_RUNQ_LOCK(cpu);
  734.     r = _PR_RUNQREADYMASK(cpu);
  735.     if (r==0) {
  736.         priMin = priMax = PR_PRIORITY_FIRST;
  737.     } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
  738.         priMin = priMax = PR_PRIORITY_NORMAL;
  739.     } else {
  740.         priMin = PR_PRIORITY_FIRST;
  741.         priMax = PR_PRIORITY_LAST;
  742.     }
  743.     thread = NULL;
  744.     for (pri = priMax; pri >= priMin ; pri-- ) {
  745.     if (r & (1 << pri)) {
  746.             for (qp = _PR_RUNQ(cpu)[pri].next; 
  747.                  qp != &_PR_RUNQ(cpu)[pri];
  748.                  qp = qp->next) {
  749.                 thread = _PR_THREAD_PTR(qp);
  750.                 /*
  751.                 * skip non-schedulable threads
  752.                 */
  753.                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  754.                 if (thread->no_sched){
  755.                     thread = NULL;
  756.             /*
  757.              * Need to wakeup cpus to avoid missing a
  758.              * runnable thread
  759.              */
  760.             _PR_MD_WAKEUP_CPUS();
  761.                     continue;
  762.                 } else if (thread->io_pending == PR_TRUE) {
  763.                     /*
  764.                      * A thread that is blocked for I/O needs to run
  765.                      * on the same cpu on which it was blocked
  766.                      */
  767.                     thread = NULL;
  768.                     continue;
  769.                 } else {
  770.                     /* Pull thread off of its run queue */
  771.                     _PR_DEL_RUNQ(thread);
  772.                     _PR_RUNQ_UNLOCK(cpu);
  773.                 return(thread);
  774.                 }
  775.             }
  776.         }
  777.         thread = NULL;
  778.     }
  779.     _PR_RUNQ_UNLOCK(cpu);
  780.     return(thread);
  781. }
  782.  
  783. /*
  784. ** Schedule this native thread by finding the highest priority nspr
  785. ** thread that is ready to run.
  786. **
  787. ** Note- everyone really needs to call _PR_MD_SWITCH_CONTEXT (which calls
  788. **       PR_Schedule() rather than calling PR_Schedule.  Otherwise if there
  789. **       is initialization required for switching from SWITCH_CONTEXT,
  790. **       it will not get done!
  791. */
  792. void _PR_Schedule(void)
  793. {
  794.     PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
  795.     _PRCPU *cpu = me->cpu;
  796.     PRIntn pri;
  797.     PRUint32 r;
  798.     PRCList *qp;
  799.     PRIntn priMin, priMax;
  800.  
  801.     /* Interrupts must be disabled */
  802.     PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
  803.  
  804.     /* Since we are rescheduling, we no longer want to */
  805.     _PR_CLEAR_RESCHED_FLAG();
  806.  
  807.     /*
  808.     ** Find highest priority thread to run. Bigger priority numbers are
  809.     ** higher priority threads
  810.     */
  811.     _PR_RUNQ_LOCK(cpu);
  812.     /*
  813.      *  if we are in SuspendAll mode, can schedule only the thread
  814.      *    that called PR_SuspendAll
  815.      *
  816.      *  The thread may be ready to run now, after completing an I/O
  817.      *  operation, for example
  818.      */
  819.     if ((thread = suspendAllThread) != 0) {
  820.     if ((!(thread->no_sched)) && (thread->state == _PR_RUNNABLE)) {
  821.             /* Pull thread off of its run queue */
  822.             _PR_DEL_RUNQ(thread);
  823.             _PR_RUNQ_UNLOCK(cpu);
  824.             goto found_thread;
  825.     } else {
  826.             thread = NULL;
  827.             _PR_RUNQ_UNLOCK(cpu);
  828.             goto idle_thread;
  829.     }
  830.     }
  831.     r = _PR_RUNQREADYMASK(cpu);
  832.     if (r==0) {
  833.         priMin = priMax = PR_PRIORITY_FIRST;
  834.     } else if (r == (1<<PR_PRIORITY_NORMAL) ) {
  835.         priMin = priMax = PR_PRIORITY_NORMAL;
  836.     } else {
  837.         priMin = PR_PRIORITY_FIRST;
  838.         priMax = PR_PRIORITY_LAST;
  839.     }
  840.     thread = NULL;
  841.     for (pri = priMax; pri >= priMin ; pri-- ) {
  842.     if (r & (1 << pri)) {
  843.             for (qp = _PR_RUNQ(cpu)[pri].next; 
  844.                  qp != &_PR_RUNQ(cpu)[pri];
  845.                  qp = qp->next) {
  846.                 thread = _PR_THREAD_PTR(qp);
  847.                 /*
  848.                 * skip non-schedulable threads
  849.                 */
  850. #if !defined(XP_MAC)
  851.                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  852. #endif
  853.                 if ((thread->no_sched) && (me != thread)){
  854.                     thread = NULL;
  855.                     continue;
  856.                 } else {
  857.                     /* Pull thread off of its run queue */
  858.                     _PR_DEL_RUNQ(thread);
  859.                     _PR_RUNQ_UNLOCK(cpu);
  860.                     goto found_thread;
  861.                 }
  862.             }
  863.         }
  864.         thread = NULL;
  865.     }
  866.     _PR_RUNQ_UNLOCK(cpu);
  867.  
  868. #if !defined(_PR_LOCAL_THREADS_ONLY) && defined(XP_UNIX)
  869.     _PR_CPU_LIST_LOCK();
  870.     for (qp = _PR_CPUQ().next; qp != &_PR_CPUQ(); qp = qp->next) {
  871.         if (cpu != _PR_CPU_PTR(qp)) {
  872.         if ((thread = get_thread(_PR_CPU_PTR(qp))) != NULL) {
  873.             thread->cpu = cpu;
  874.                 _PR_CPU_LIST_UNLOCK();
  875.                     goto found_thread;
  876.         }
  877.         }
  878.     }
  879.     _PR_CPU_LIST_UNLOCK();
  880. #endif        /* _PR_LOCAL_THREADS_ONLY */
  881.  
  882. idle_thread:
  883.    /*
  884.     ** There are no threads to run. Switch to the idle thread
  885.     */
  886.     PR_LOG(_pr_sched_lm, PR_LOG_MAX, ("pausing"));
  887.     thread = _PR_MD_CURRENT_CPU()->idle_thread;
  888.  
  889. found_thread:
  890.     PR_ASSERT((me == thread) || ((thread->state == _PR_RUNNABLE) &&
  891.                     (!(thread->no_sched))));
  892.  
  893.     /* Resume the thread */
  894.     PR_LOG(_pr_sched_lm, PR_LOG_MAX,
  895.        ("switching to %d[%p]", thread->id, thread));
  896.     PR_ASSERT(thread->state != _PR_RUNNING);
  897.     thread->state = _PR_RUNNING;
  898.  
  899.     /* If we are on the runq, it just means that we went to sleep on some
  900.      * resource, and by the time we got here another real native thread had
  901.      * already given us the resource and put us back on the runqueue 
  902.      */
  903.     if (thread != me) 
  904.         _PR_MD_RESTORE_CONTEXT(thread);
  905. #if 0
  906.     /* XXXMB; with setjmp/longjmp it is impossible to land here, but 
  907.      * it is not with fibers... Is this a bad thing?  I believe it is 
  908.      * still safe.
  909.      */
  910.     PR_NOT_REACHED("impossible return from schedule");
  911. #endif
  912. }
  913.  
  914. /*
  915. ** Attaches a thread.  
  916. ** Does not set the _PR_MD_CURRENT_THREAD.  
  917. ** Does not specify the scope of the thread.
  918. */
  919. static PRThread *
  920. _PR_AttachThread(PRThreadType type, PRThreadPriority priority,
  921.     PRThreadStack *stack)
  922. {
  923. #if defined(XP_MAC)
  924. #pragma unused (type)
  925. #endif
  926.  
  927.     PRThread *thread;
  928.     char *mem;
  929.  
  930.     if (priority > PR_PRIORITY_LAST) {
  931.         priority = PR_PRIORITY_LAST;
  932.     } else if (priority < PR_PRIORITY_FIRST) {
  933.         priority = PR_PRIORITY_FIRST;
  934.     }
  935.  
  936.     mem = (char*) PR_CALLOC(sizeof(PRThread));
  937.     if (mem) {
  938.         thread = (PRThread*) mem;
  939.         thread->priority = priority;
  940.         thread->stack = stack;
  941.         thread->state = _PR_RUNNING;
  942.         PR_INIT_CLIST(&thread->lockList);
  943.         if (_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
  944.         PR_DELETE(thread);
  945.         return 0;
  946.     }
  947.  
  948.         return thread;
  949.     }
  950.     return 0;
  951. }
  952.  
  953.  
  954.  
  955. PR_IMPLEMENT(PRThread*) 
  956. _PR_NativeCreateThread(PRThreadType type,
  957.                      void (*start)(void *arg),
  958.                      void *arg,
  959.                      PRThreadPriority priority,
  960.                      PRThreadScope scope,
  961.                      PRThreadState state,
  962.                      PRUint32 stackSize,
  963.                      PRUint32 flags)
  964. {
  965. #if defined(XP_MAC)
  966. #pragma unused (scope)
  967. #endif
  968.  
  969.     PRThread *thread;
  970.  
  971.     thread = _PR_AttachThread(type, priority, NULL);
  972.  
  973.     if (thread) {
  974.         PR_Lock(_pr_activeLock);
  975.         thread->flags = (flags | _PR_GLOBAL_SCOPE);
  976.         thread->id = ++_pr_utid;
  977.         if (type == PR_SYSTEM_THREAD) {
  978.             thread->flags |= _PR_SYSTEM;
  979.             _pr_systemActive++;
  980.         } else {
  981.             _pr_userActive++;
  982.         }
  983.         PR_Unlock(_pr_activeLock);
  984.  
  985.         thread->stack = PR_NEWZAP(PRThreadStack);
  986.         if (!thread->stack) {
  987.             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  988.             goto done;
  989.         }
  990.         thread->stack->stackSize = stackSize?stackSize:_MD_DEFAULT_STACK_SIZE;
  991.         thread->stack->thr = thread;
  992.         thread->startFunc = start;
  993.         thread->arg = arg;
  994.  
  995.         /* 
  996.           Set thread flags related to scope and joinable state. If joinable
  997.           thread, allocate a "termination" conidition variable.
  998.          */
  999.         if (state == PR_JOINABLE_THREAD) {
  1000.             thread->term = PR_NewCondVar(_pr_terminationCVLock);
  1001.         if (thread->term == NULL) {
  1002.         PR_DELETE(thread->stack);
  1003.         goto done;
  1004.         }
  1005.         }
  1006.  
  1007.     thread->state = _PR_RUNNING;
  1008.         if (_PR_MD_CREATE_THREAD(thread, _PR_NativeRunThread, priority,
  1009.             scope,state,stackSize) == PR_SUCCESS) {
  1010.             return thread;
  1011.         }
  1012.         if (thread->term) {
  1013.             PR_DestroyCondVar(thread->term);
  1014.             thread->term = NULL;
  1015.         }
  1016.     PR_DELETE(thread->stack);
  1017.     }
  1018.  
  1019. done:
  1020.     if (thread) {
  1021.     _PR_DecrActiveThreadCount(thread);
  1022.         _PR_DetachThread(thread);
  1023.     }
  1024.     return NULL;
  1025. }
  1026.  
  1027. /************************************************************************/
  1028.  
  1029. PR_IMPLEMENT(PRThread*) _PR_CreateThread(PRThreadType type,
  1030.                      void (*start)(void *arg),
  1031.                      void *arg,
  1032.                      PRThreadPriority priority,
  1033.                      PRThreadScope scope,
  1034.                      PRThreadState state,
  1035.                      PRUint32 stackSize,
  1036.                      PRUint32 flags)
  1037. {
  1038.     PRThread *me;
  1039.     PRThread *thread = NULL;
  1040.     PRThreadStack *stack;
  1041.     char *top;
  1042.     PRIntn is;
  1043.     PRIntn native = 0;
  1044.     PRIntn useRecycled = 0;
  1045.     PRBool status;
  1046.  
  1047.     /* 
  1048.     First, pin down the priority.  Not all compilers catch passing out of
  1049.     range enum here.  If we let bad values thru, priority queues won't work.
  1050.     */
  1051.     if (priority > PR_PRIORITY_LAST) {
  1052.         priority = PR_PRIORITY_LAST;
  1053.     } else if (priority < PR_PRIORITY_FIRST) {
  1054.         priority = PR_PRIORITY_FIRST;
  1055.     }
  1056.         
  1057.     if (!_pr_initialized) _PR_ImplicitInitialization();
  1058.  
  1059.     if (! (flags & _PR_IDLE_THREAD))
  1060.         me = _PR_MD_CURRENT_THREAD();
  1061.  
  1062. #if    defined(_PR_GLOBAL_THREADS_ONLY)
  1063.     scope = PR_GLOBAL_THREAD;
  1064. #endif
  1065.  
  1066.     native = ((scope == PR_GLOBAL_THREAD) && _PR_IS_NATIVE_THREAD_SUPPORTED());
  1067.  
  1068.     _PR_ADJUST_STACKSIZE(stackSize);
  1069.  
  1070.     if (native) {
  1071.     /*
  1072.      * clear the IDLE_THREAD flag which applies to LOCAL
  1073.      * threads only
  1074.      */
  1075.     flags &= ~_PR_IDLE_THREAD;
  1076.         flags |= _PR_GLOBAL_SCOPE;
  1077.         if (_PR_NUM_DEADNATIVE > 0) {
  1078.             _PR_DEADQ_LOCK;
  1079.  
  1080.             if (_PR_NUM_DEADNATIVE == 0) { /* Thread safe check */
  1081.                 _PR_DEADQ_UNLOCK;
  1082.             } else {
  1083.                 thread = _PR_THREAD_PTR(_PR_DEADNATIVEQ.next);
  1084.                 PR_REMOVE_LINK(&thread->links);
  1085.                 _PR_DEC_DEADNATIVE;
  1086.                 _PR_DEADQ_UNLOCK;
  1087.  
  1088.                 _PR_InitializeRecycledThread(thread);
  1089.                 thread->startFunc = start;
  1090.                 thread->arg = arg;
  1091.             PR_Lock(_pr_activeLock);
  1092.             thread->flags = (flags | _PR_GLOBAL_SCOPE);
  1093.             if (type == PR_SYSTEM_THREAD) {
  1094.                     thread->flags |= _PR_SYSTEM;
  1095.                     _pr_systemActive++;
  1096.             } else {
  1097.                     _pr_userActive++;
  1098.             }
  1099.             PR_Unlock(_pr_activeLock);
  1100.  
  1101.             if (state == PR_JOINABLE_THREAD) {
  1102.                 if (!thread->term) 
  1103.                        thread->term = PR_NewCondVar(_pr_terminationCVLock);
  1104.             }
  1105.         else {
  1106.                 if(thread->term) {
  1107.                     PR_DestroyCondVar(thread->term);
  1108.                         thread->term = 0;
  1109.             }
  1110.             }
  1111.  
  1112.                 thread->priority = priority;
  1113.         _PR_MD_SET_PRIORITY(&(thread->md), priority);
  1114.         /* XXX what about stackSize? */
  1115.         thread->state = _PR_RUNNING;
  1116.                 _PR_MD_WAKEUP_WAITER(thread);
  1117.         return thread;
  1118.             }
  1119.         }
  1120.         thread = _PR_NativeCreateThread(type, start, arg, priority, 
  1121.                                             scope, state, stackSize, flags);
  1122.     } else {
  1123.         if (_PR_NUM_DEADUSER > 0) {
  1124.             _PR_DEADQ_LOCK;
  1125.  
  1126.             if (_PR_NUM_DEADUSER == 0) {  /* thread safe check */
  1127.                 _PR_DEADQ_UNLOCK;
  1128.             } else {
  1129.                 PRCList *ptr;
  1130.  
  1131.                 /* Go down list checking for a recycled thread with a 
  1132.                  * large enough stack.  XXXMB - this has a bad degenerate case.
  1133.                  */
  1134.                 ptr = _PR_DEADUSERQ.next;
  1135.                 while( ptr != &_PR_DEADUSERQ ) {
  1136.                     thread = _PR_THREAD_PTR(ptr);
  1137.                     if ((thread->stack->stackSize >= stackSize) &&
  1138.                 (!thread->no_sched)) {
  1139.                         PR_REMOVE_LINK(&thread->links);
  1140.                         _PR_DEC_DEADUSER;
  1141.                         break;
  1142.                     } else {
  1143.                         ptr = ptr->next;
  1144.                         thread = NULL;
  1145.                     }
  1146.                 } 
  1147.  
  1148.                 _PR_DEADQ_UNLOCK;
  1149.  
  1150.                if (thread) {
  1151.                     _PR_InitializeRecycledThread(thread);
  1152.                     thread->startFunc = start;
  1153.                     thread->arg = arg;
  1154.                     thread->priority = priority;
  1155.             if (state == PR_JOINABLE_THREAD) {
  1156.             if (!thread->term) 
  1157.                thread->term = PR_NewCondVar(_pr_terminationCVLock);
  1158.             } else {
  1159.             if(thread->term) {
  1160.                PR_DestroyCondVar(thread->term);
  1161.                 thread->term = 0;
  1162.             }
  1163.             }
  1164.                     useRecycled++;
  1165.                 }
  1166.             }
  1167.         } 
  1168.         if (thread == NULL) {
  1169. #ifndef HAVE_CUSTOM_USER_THREADS
  1170.             stack = _PR_NewStack(stackSize);
  1171.             if (!stack) {
  1172.                 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1173.             return 0;
  1174.             }
  1175.             stack->thr = thread;
  1176.  
  1177.             /* Allocate thread object and per-thread data off the top of the stack*/
  1178.             top = stack->stackTop;
  1179. #ifdef HAVE_STACK_GROWING_UP
  1180.             thread = (PRThread*) top;
  1181.             top = top + sizeof(PRThread);
  1182.         /*
  1183.          * Make stack 64-byte aligned
  1184.          */
  1185.             if ((PRUptrdiff)top & 0x3f) {
  1186.                 top = (char*)(((PRUptrdiff)top + 0x40) & ~0x3f);
  1187.             }
  1188. #else
  1189.             top = top - sizeof(PRThread);
  1190.             thread = (PRThread*) top;
  1191.         /*
  1192.          * Make stack 64-byte aligned
  1193.          */
  1194.             if ((PRUptrdiff)top & 0x3f) {
  1195.                 top = (char*)((PRUptrdiff)top & ~0x3f);
  1196.             }
  1197. #endif
  1198.             memset(thread, 0, sizeof(PRThread));
  1199.             thread->threadAllocatedOnStack = 1;
  1200. #else
  1201.             thread = _PR_MD_CREATE_USER_THREAD(stackSize, start, arg);
  1202.             if (!thread) {
  1203.                 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  1204.                 return NULL;
  1205.             }
  1206.             thread->threadAllocatedOnStack = 0;
  1207.             stack = NULL;
  1208. #endif
  1209.  
  1210.             /* Initialize thread */
  1211.             if (stack)
  1212.                 stack->thr = thread;
  1213.             thread->tpdLength = 0;
  1214.             thread->privateData = NULL;
  1215.             thread->stack = stack;
  1216.             thread->priority = priority;
  1217.             thread->startFunc = start;
  1218.             thread->arg = arg;
  1219.             PR_INIT_CLIST(&thread->lockList);
  1220.  
  1221.             if (_PR_MD_INIT_THREAD(thread) == PR_FAILURE) {
  1222.                 if (thread->threadAllocatedOnStack == 1)
  1223.                     _PR_FreeStack(thread->stack);
  1224.                 else {
  1225.                     PR_DELETE(thread);
  1226.                 }
  1227.                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1228.                 return NULL;
  1229.             }
  1230.  
  1231.             if (_MD_NEW_LOCK(&thread->threadLock) == PR_FAILURE) {
  1232.                 if (thread->threadAllocatedOnStack == 1)
  1233.                     _PR_FreeStack(thread->stack);
  1234.                 else {
  1235.                     PR_DELETE(thread->privateData);
  1236.                     PR_DELETE(thread);
  1237.                 }
  1238.                 PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  1239.                 return NULL;
  1240.             }
  1241.  
  1242.             _PR_MD_INIT_CONTEXT(thread, top, _PR_UserRunThread, &status);
  1243.  
  1244.             if (status == PR_FALSE) {
  1245.         _MD_FREE_LOCK(&thread->threadLock);
  1246.                 if (thread->threadAllocatedOnStack == 1)
  1247.             _PR_FreeStack(thread->stack);
  1248.         else {
  1249.             PR_DELETE(thread->privateData);
  1250.             PR_DELETE(thread);
  1251.         }
  1252.                 return NULL;
  1253.             }
  1254.  
  1255.             /* 
  1256.               Set thread flags related to scope and joinable state. If joinable
  1257.               thread, allocate a "termination" condition variable.
  1258.             */
  1259.             if (state == PR_JOINABLE_THREAD) {
  1260.                 thread->term = PR_NewCondVar(_pr_terminationCVLock);
  1261.         if (thread->term == NULL) {
  1262.             _MD_FREE_LOCK(&thread->threadLock);
  1263.             if (thread->threadAllocatedOnStack == 1)
  1264.                 _PR_FreeStack(thread->stack);
  1265.             else {
  1266.                 PR_DELETE(thread->privateData);
  1267.                 PR_DELETE(thread);
  1268.             }
  1269.             return NULL;
  1270.         }
  1271.             }
  1272.   
  1273.         }
  1274.   
  1275.         /* Update thread type counter */
  1276.         PR_Lock(_pr_activeLock);
  1277.         thread->flags = flags;
  1278.         thread->id = ++_pr_utid;
  1279.         if (type == PR_SYSTEM_THREAD) {
  1280.             thread->flags |= _PR_SYSTEM;
  1281.             _pr_systemActive++;
  1282.         } else {
  1283.             _pr_userActive++;
  1284.         }
  1285.  
  1286.         /* Make thread runnable */
  1287.         thread->state = _PR_RUNNABLE;
  1288.     /*
  1289.      * Add to list of active threads
  1290.      */
  1291.         PR_Unlock(_pr_activeLock);
  1292.  
  1293.         if ( (thread->flags & _PR_IDLE_THREAD) || _PR_IS_NATIVE_THREAD(me) )
  1294.             thread->cpu = _PR_GetPrimordialCPU();
  1295.         else
  1296.             thread->cpu = _PR_MD_CURRENT_CPU();
  1297.  
  1298.         if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me))
  1299.             _PR_INTSOFF(is);
  1300.         if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(thread)) {
  1301.             _PR_RUNQ_LOCK(thread->cpu);
  1302.             _PR_ADD_RUNQ(thread, thread->cpu, priority);
  1303.             _PR_RUNQ_UNLOCK(thread->cpu);
  1304.         }
  1305.  
  1306.         if ((thread->flags & _PR_IDLE_THREAD) || _PR_IS_NATIVE_THREAD(me)) {
  1307.             /*
  1308.             ** If the creating thread is a kernel thread, we need to
  1309.             ** awaken the user thread idle thread somehow; potentially
  1310.             ** it could be sleeping in its idle loop, and we need to poke
  1311.             ** it.  To do so, wake the idle thread...  
  1312.             */
  1313.             _PR_MD_WAKEUP_WAITER(NULL);
  1314.         }
  1315.         if ((! (thread->flags & _PR_IDLE_THREAD)) && !_PR_IS_NATIVE_THREAD(me) )
  1316.             _PR_INTSON(is);
  1317.     }
  1318.  
  1319.     return thread;
  1320. }
  1321.  
  1322. PR_IMPLEMENT(PRThread*) PR_CreateThread(PRThreadType type,
  1323.                      void (*start)(void *arg),
  1324.                      void *arg,
  1325.                      PRThreadPriority priority,
  1326.                      PRThreadScope scope,
  1327.                      PRThreadState state,
  1328.                      PRUint32 stackSize)
  1329. {
  1330.     return _PR_CreateThread(type, start, arg, priority, scope, state, 
  1331.                             stackSize, 0);
  1332. }
  1333.  
  1334. /*
  1335. ** Associate a thread object with an existing native thread.
  1336. **     "type" is the type of thread object to attach
  1337. **     "priority" is the priority to assign to the thread
  1338. **     "stack" defines the shape of the threads stack
  1339. **
  1340. ** This can return NULL if some kind of error occurs, or if memory is
  1341. ** tight.
  1342. **
  1343. ** This call is not normally needed unless you create your own native
  1344. ** thread. PR_Init does this automatically for the primordial thread.
  1345. */
  1346. PR_IMPLEMENT(PRThread*) _PRI_AttachThread(PRThreadType type,
  1347.     PRThreadPriority priority, PRThreadStack *stack, PRUint32 flags)
  1348. {
  1349.     PRThread *thread;
  1350.  
  1351.     if ((thread = _PR_MD_GET_ATTACHED_THREAD()) != NULL) {
  1352.         return thread;
  1353.     }
  1354.  
  1355.     /* Clear out any state if this thread was attached before */
  1356.     _PR_MD_SET_CURRENT_CPU(NULL);
  1357.  
  1358.     thread = _PR_AttachThread(type, priority, stack);
  1359.     if (thread) {
  1360.         PRIntn is;
  1361.  
  1362.         _PR_MD_SET_CURRENT_THREAD(thread);
  1363.  
  1364.         thread->flags = flags | _PR_GLOBAL_SCOPE | _PR_ATTACHED;
  1365.  
  1366.         if (!stack) {
  1367.             thread->stack = PR_NEWZAP(PRThreadStack);
  1368.             if (!thread->stack) {
  1369.                 _PR_DetachThread(thread);
  1370.                 return NULL;
  1371.             }
  1372.             thread->stack->stackSize = _MD_DEFAULT_STACK_SIZE;
  1373.         }
  1374.         PR_INIT_CLIST(&thread->links);
  1375.  
  1376.         if (_PR_MD_INIT_ATTACHED_THREAD(thread) == PR_FAILURE) {
  1377.                 PR_DELETE(thread->stack);
  1378.                 _PR_DetachThread(thread);
  1379.                 return NULL;
  1380.         }
  1381.  
  1382.         _PR_MD_SET_CURRENT_CPU(NULL);
  1383.  
  1384.         if (_PR_MD_CURRENT_CPU()) {
  1385.             _PR_INTSOFF(is);
  1386.             PR_Lock(_pr_activeLock);
  1387.         }
  1388.         if (type == PR_SYSTEM_THREAD) {
  1389.             thread->flags |= _PR_SYSTEM;
  1390.             _pr_systemActive++;
  1391.         } else {
  1392.             _pr_userActive++;
  1393.         }
  1394.         if (_PR_MD_CURRENT_CPU()) {
  1395.             PR_Unlock(_pr_activeLock);
  1396.             _PR_INTSON(is);
  1397.         }
  1398.     }
  1399.     return thread;
  1400. }
  1401.  
  1402. PR_IMPLEMENT(PRThread*) PR_AttachThread(PRThreadType type,
  1403.     PRThreadPriority priority, PRThreadStack *stack)
  1404. {
  1405.     return _PRI_AttachThread(type, priority, stack, 0);
  1406. }
  1407.  
  1408. /*
  1409. ** Detach the nspr thread from the currently executing native thread.
  1410. ** The thread object will be destroyed and all related data attached
  1411. ** to it. The exit procs will be invoked.
  1412. **
  1413. ** This call is not normally needed unless you create your own native
  1414. ** thread. PR_Exit will automatially detach the nspr thread object
  1415. ** created by PR_Init for the primordial thread.
  1416. **
  1417. ** This call returns after the nspr thread object is destroyed.
  1418. */
  1419. PR_IMPLEMENT(void) PR_DetachThread(void)
  1420. {
  1421.     PRIntn is;
  1422.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1423.  
  1424.     PR_ASSERT(me->flags & _PR_ATTACHED);
  1425.     _PR_CleanupThread(me);
  1426.     PR_DELETE(me->privateData);
  1427.     _PR_MD_CLEAN_THREAD(me);
  1428.  
  1429.     /*XXX we need DetachCPU */
  1430.      if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
  1431.     _PR_DecrActiveThreadCount(me);
  1432.     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_FAST_INTSON(is);
  1433.     _PR_MD_SET_CURRENT_THREAD(NULL);
  1434.     if (!me->threadAllocatedOnStack) 
  1435.         PR_DELETE(me->stack);
  1436.     _MD_FREE_LOCK(&me->threadLock);
  1437.     PR_DELETE(me);
  1438. }
  1439.  
  1440. /*
  1441. ** Wait for thread termination:
  1442. **     "thread" is the target thread 
  1443. **
  1444. ** This can return PR_FAILURE if no joinable thread could be found 
  1445. ** corresponding to the specified target thread.
  1446. **
  1447. ** The calling thread is suspended until the target thread completes.
  1448. ** Several threads cannot wait for the same thread to complete; one thread
  1449. ** will complete successfully and others will terminate with an error PR_FAILURE.
  1450. ** The calling thread will not be blocked if the target thread has already
  1451. ** terminated.
  1452. */
  1453. PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thread)
  1454. {
  1455.     PRIntn is;
  1456.     PRCondVar *term;
  1457.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1458.  
  1459.     if (!_PR_IS_NATIVE_THREAD(me))
  1460.         _PR_INTSOFF(is);
  1461.     term = thread->term;
  1462.     /* can't join a non-joinable thread */
  1463.     if (term == NULL) {
  1464.         goto ErrorExit;
  1465.     }
  1466.  
  1467.     /* multiple threads can't wait on the same joinable thread */
  1468.     if (term->condQ.next != &term->condQ) {
  1469.         goto ErrorExit;
  1470.     }
  1471.     if (!_PR_IS_NATIVE_THREAD(me))
  1472.         _PR_INTSON(is);
  1473.  
  1474.     /* wait for the target thread's termination cv invariant */
  1475.     PR_Lock (_pr_terminationCVLock);
  1476.     while (thread->state != _PR_JOIN_WAIT) {
  1477.         (void) PR_WaitCondVar(term, PR_INTERVAL_NO_TIMEOUT);
  1478.     }
  1479.     (void) PR_Unlock (_pr_terminationCVLock);
  1480.     
  1481.     /* 
  1482.      Remove target thread from global waiting to join Q; make it runnable
  1483.      again and put it back on its run Q.  When it gets scheduled later in
  1484.      _PR_RunThread code, it will clean up its stack.
  1485.     */    
  1486.     if (!_PR_IS_NATIVE_THREAD(me))
  1487.         _PR_INTSOFF(is);
  1488.     thread->state = _PR_RUNNABLE;
  1489.     if ( !_PR_IS_NATIVE_THREAD(thread) ) {
  1490.         _PR_THREAD_LOCK(thread);
  1491.  
  1492.         _PR_MISCQ_LOCK(thread->cpu);
  1493.         _PR_DEL_JOINQ(thread);
  1494.         _PR_MISCQ_UNLOCK(thread->cpu);
  1495.  
  1496.         _PR_AddThreadToRunQ(me, thread);
  1497.         _PR_THREAD_UNLOCK(thread);
  1498.     }
  1499.     if (!_PR_IS_NATIVE_THREAD(me))
  1500.         _PR_INTSON(is);
  1501.  
  1502.     _PR_MD_WAKEUP_WAITER(thread);
  1503.  
  1504.     return PR_SUCCESS;
  1505.  
  1506. ErrorExit:
  1507.     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
  1508.     return PR_FAILURE;   
  1509. }
  1510.  
  1511. PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thread,
  1512.     PRThreadPriority newPri)
  1513. {
  1514.  
  1515.     /* 
  1516.     First, pin down the priority.  Not all compilers catch passing out of
  1517.     range enum here.  If we let bad values thru, priority queues won't work.
  1518.     */
  1519.     if (newPri > PR_PRIORITY_LAST) {
  1520.         newPri = PR_PRIORITY_LAST;
  1521.     } else if (newPri < PR_PRIORITY_FIRST) {
  1522.         newPri = PR_PRIORITY_FIRST;
  1523.     }
  1524.         
  1525.     if ( _PR_IS_NATIVE_THREAD(thread) ) {
  1526.         thread->priority = newPri;
  1527.         _PR_MD_SET_PRIORITY(&(thread->md), newPri);
  1528.     } else _PR_SetThreadPriority(thread, newPri);
  1529. }
  1530.  
  1531.  
  1532. /*
  1533. ** This routine prevents all other threads from running. This call is needed by 
  1534. ** the garbage collector.
  1535. */
  1536. PR_IMPLEMENT(void) PR_SuspendAll(void)
  1537. {
  1538.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1539.     PRCList *qp;
  1540.  
  1541.     /*
  1542.      * Stop all user and native threads which are marked GC able.
  1543.      */
  1544.     PR_Lock(_pr_activeLock);
  1545.     suspendAllOn = PR_TRUE;
  1546.     suspendAllThread = _PR_MD_CURRENT_THREAD();
  1547.     _PR_MD_BEGIN_SUSPEND_ALL();
  1548.     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
  1549.         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
  1550.         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && 
  1551.             (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD)) {
  1552.             _PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp));
  1553.                 PR_ASSERT((_PR_ACTIVE_THREAD_PTR(qp))->state != _PR_RUNNING);
  1554.             }
  1555.     }
  1556.     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
  1557.         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
  1558.         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
  1559.             (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD))
  1560.             /* PR_Suspend(_PR_ACTIVE_THREAD_PTR(qp)); */
  1561.                 _PR_MD_SUSPEND_THREAD(_PR_ACTIVE_THREAD_PTR(qp)); 
  1562.     }
  1563.     _PR_MD_END_SUSPEND_ALL();
  1564. }
  1565.  
  1566. /*
  1567. ** This routine unblocks all other threads that were suspended from running by 
  1568. ** PR_SuspendAll(). This call is needed by the garbage collector.
  1569. */
  1570. PR_IMPLEMENT(void) PR_ResumeAll(void)
  1571. {
  1572.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1573.     PRCList *qp;
  1574.  
  1575.     /*
  1576.      * Resume all user and native threads which are marked GC able.
  1577.      */
  1578.     _PR_MD_BEGIN_RESUME_ALL();
  1579.     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
  1580.         qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp->next) {
  1581.         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) && 
  1582.             (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD))
  1583.             _PR_Resume(_PR_ACTIVE_THREAD_PTR(qp));
  1584.     }
  1585.     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
  1586.         qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp->next) {
  1587.         if ((me != _PR_ACTIVE_THREAD_PTR(qp)) &&
  1588.             (_PR_ACTIVE_THREAD_PTR(qp)->flags & _PR_GCABLE_THREAD))
  1589.                 _PR_MD_RESUME_THREAD(_PR_ACTIVE_THREAD_PTR(qp));
  1590.     }
  1591.     _PR_MD_END_RESUME_ALL();
  1592.     suspendAllThread = NULL;
  1593.     suspendAllOn = PR_FALSE;
  1594.     PR_Unlock(_pr_activeLock);
  1595. }
  1596.  
  1597. PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
  1598. {
  1599.     PRCList *qp, *qp_next;
  1600.     PRIntn i = 0;
  1601.     PRThread *me = _PR_MD_CURRENT_THREAD();
  1602.     PRStatus rv = PR_SUCCESS;
  1603.     PRThread* t;
  1604.  
  1605.     /*
  1606.     ** Currently Enumerate threads happen only with suspension and
  1607.     ** pr_activeLock held
  1608.     */
  1609.     PR_ASSERT(suspendAllOn);
  1610.  
  1611.     /* Steve Morse, 4-23-97: Note that we can't walk a queue by taking
  1612.      * qp->next after applying the function "func".  In particular, "func"
  1613.      * might remove the thread from the queue and put it into another one in
  1614.      * which case qp->next no longer points to the next entry in the original
  1615.      * queue.
  1616.      *
  1617.      * To get around this problem, we save qp->next in qp_next before applying
  1618.      * "func" and use that saved value as the next value after applying "func".
  1619.      */
  1620.  
  1621.     /*
  1622.      * Traverse the list of local and global threads
  1623.      */
  1624.     for (qp = _PR_ACTIVE_LOCAL_THREADQ().next;
  1625.          qp != &_PR_ACTIVE_LOCAL_THREADQ(); qp = qp_next)
  1626.     {
  1627.         qp_next = qp->next;
  1628.         t = _PR_ACTIVE_THREAD_PTR(qp);
  1629.         if (t->flags & _PR_GCABLE_THREAD)
  1630.         {
  1631.             rv = (*func)(t, i, arg);
  1632.             if (rv != PR_SUCCESS)
  1633.                 return rv;
  1634.             i++;
  1635.         }
  1636.     }
  1637.     for (qp = _PR_ACTIVE_GLOBAL_THREADQ().next;
  1638.          qp != &_PR_ACTIVE_GLOBAL_THREADQ(); qp = qp_next)
  1639.     {
  1640.         qp_next = qp->next;
  1641.         t = _PR_ACTIVE_THREAD_PTR(qp);
  1642.         if (t->flags & _PR_GCABLE_THREAD)
  1643.         {
  1644.             rv = (*func)(t, i, arg);
  1645.             if (rv != PR_SUCCESS)
  1646.                 return rv;
  1647.             i++;
  1648.         }
  1649.     }
  1650.     return rv;
  1651. }
  1652.  
  1653. /* FUNCTION: _PR_AddSleepQ
  1654. ** DESCRIPTION:
  1655. **    Adds a thread to the sleep/pauseQ.
  1656. ** RESTRICTIONS:
  1657. **    Caller must have the RUNQ lock.
  1658. **    Caller must be a user level thread
  1659. */
  1660. PR_IMPLEMENT(void)
  1661. _PR_AddSleepQ(PRThread *thread, PRIntervalTime timeout)
  1662. {
  1663.     _PRCPU *cpu = thread->cpu;
  1664.  
  1665.     if (timeout == PR_INTERVAL_NO_TIMEOUT) {
  1666.         /* append the thread to the global pause Q */
  1667.         PR_APPEND_LINK(&thread->links, &_PR_PAUSEQ(thread->cpu));
  1668.         thread->flags |= _PR_ON_PAUSEQ;
  1669.     } else {
  1670.         PRIntervalTime sleep;
  1671.         PRCList *q;
  1672.         PRThread *t;
  1673.  
  1674.         /* sort onto global sleepQ */
  1675.         sleep = timeout;
  1676.  
  1677.         /* Check if we are longest timeout */
  1678.         if (timeout >= _PR_SLEEPQMAX(cpu)) {
  1679.             PR_INSERT_BEFORE(&thread->links, &_PR_SLEEPQ(cpu));
  1680.             thread->sleep = timeout - _PR_SLEEPQMAX(cpu);
  1681.             _PR_SLEEPQMAX(cpu) = timeout;
  1682.         } else {
  1683.             /* Sort thread into global sleepQ at appropriate point */
  1684.             q = _PR_SLEEPQ(cpu).next;
  1685.  
  1686.             /* Now scan the list for where to insert this entry */
  1687.             while (q != &_PR_SLEEPQ(cpu)) {
  1688.                 t = _PR_THREAD_PTR(q);
  1689.                 if (sleep < t->sleep) {
  1690.                     /* Found sleeper to insert in front of */
  1691.                     break;
  1692.                 }
  1693.                 sleep -= t->sleep;
  1694.                 q = q->next;
  1695.             }
  1696.             thread->sleep = sleep;
  1697.             PR_INSERT_BEFORE(&thread->links, q);
  1698.  
  1699.             /*
  1700.             ** Subtract our sleep time from the sleeper that follows us (there
  1701.             ** must be one) so that they remain relative to us.
  1702.             */
  1703.             PR_ASSERT (thread->links.next != &_PR_SLEEPQ(cpu));
  1704.           
  1705.             t = _PR_THREAD_PTR(thread->links.next);
  1706.             PR_ASSERT(_PR_THREAD_PTR(t->links.prev) == thread);
  1707.             t->sleep -= sleep;
  1708.         }
  1709.  
  1710.         thread->flags |= _PR_ON_SLEEPQ;
  1711.     }
  1712. }
  1713.  
  1714. /* FUNCTION: _PR_DelSleepQ
  1715. ** DESCRIPTION:
  1716. **    Removes a thread from the sleep/pauseQ.
  1717. ** INPUTS:
  1718. **    If propogate_time is true, then the thread following the deleted
  1719. **    thread will be get the time from the deleted thread.  This is used
  1720. **    when deleting a sleeper that has not timed out.
  1721. ** RESTRICTIONS:
  1722. **    Caller must have the RUNQ lock.
  1723. **    Caller must be a user level thread
  1724. */
  1725. PR_IMPLEMENT(void)
  1726. _PR_DelSleepQ(PRThread *thread, PRBool propogate_time)
  1727. {
  1728.     _PRCPU *cpu = thread->cpu;
  1729.  
  1730.     /* Remove from pauseQ/sleepQ */
  1731.     if (thread->flags & (_PR_ON_PAUSEQ|_PR_ON_SLEEPQ)) {
  1732.         if (thread->flags & _PR_ON_SLEEPQ) {
  1733.             PRCList *q = thread->links.next;
  1734.             if (q != &_PR_SLEEPQ(cpu)) {
  1735.                 if (propogate_time == PR_TRUE) {
  1736.                     PRThread *after = _PR_THREAD_PTR(q);
  1737.                     after->sleep += thread->sleep;
  1738.                 } else 
  1739.                     _PR_SLEEPQMAX(cpu) -= thread->sleep;
  1740.             } else {
  1741.                 /* Check if prev is the beggining of the list; if so,
  1742.                  * we are the only element on the list.  
  1743.                  */
  1744.                 if (thread->links.prev != &_PR_SLEEPQ(cpu))
  1745.                     _PR_SLEEPQMAX(cpu) -= thread->sleep;
  1746.                 else
  1747.                     _PR_SLEEPQMAX(cpu) = 0;
  1748.             }
  1749.             thread->flags &= ~_PR_ON_SLEEPQ;
  1750.         } else {
  1751.             thread->flags &= ~_PR_ON_PAUSEQ;
  1752.         }
  1753.         PR_REMOVE_LINK(&thread->links);
  1754.     } else 
  1755.         PR_ASSERT(0);
  1756. }
  1757.  
  1758. void
  1759. _PR_AddThreadToRunQ(
  1760.     PRThread *me,     /* the current thread */
  1761.     PRThread *thread) /* the local thread to be added to a run queue */
  1762. {
  1763.     PRThreadPriority pri = thread->priority;
  1764.     _PRCPU *cpu = thread->cpu;
  1765.  
  1766.     PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
  1767.  
  1768. #if defined(WINNT)
  1769.     /*
  1770.      * On NT, we can only reliably know that the current CPU
  1771.      * is not idle.  We add the awakened thread to the run
  1772.      * queue of its CPU if its CPU is the current CPU.
  1773.      * For any other CPU, we don't really know whether it
  1774.      * is busy or idle.  So in all other cases, we just
  1775.      * "post" the awakened thread to the IO completion port
  1776.      * for the next idle CPU to execute (this is done in
  1777.      * _PR_MD_WAKEUP_WAITER).
  1778.      */
  1779.     if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {
  1780.         _PR_RUNQ_LOCK(cpu);
  1781.         _PR_ADD_RUNQ(thread, cpu, pri);
  1782.         _PR_RUNQ_UNLOCK(cpu);
  1783.     }
  1784. #else
  1785.     _PR_RUNQ_LOCK(cpu);
  1786.     _PR_ADD_RUNQ(thread, cpu, pri);
  1787.     _PR_RUNQ_UNLOCK(cpu);
  1788.     if (!_PR_IS_NATIVE_THREAD(me) && (cpu == me->cpu)) {
  1789.         if (pri > me->priority) {
  1790.             _PR_SET_RESCHED_FLAG();
  1791.         }
  1792.     }
  1793. #endif
  1794. }
  1795.