home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / nsprpub / pr / src / threads / combined / prucv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  18.4 KB  |  635 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.  
  20. #include "primpl.h"
  21. #include "prinrval.h"
  22. #include "prtypes.h"
  23.  
  24.  
  25. /*
  26. ** Notify one thread that it has finished waiting on a condition variable
  27. ** Caller must hold the _PR_CVAR_LOCK(cv)
  28. */
  29. PRBool NotifyThread (PRThread *thread, PRThread *me)
  30. {
  31.     PRBool rv;
  32.  
  33.     PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
  34.  
  35.     _PR_THREAD_LOCK(thread);
  36.     PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  37.     if ( !_PR_IS_NATIVE_THREAD(thread) ) {
  38.         if (thread->wait.cvar != NULL) {
  39.             thread->wait.cvar = NULL;
  40.  
  41.             _PR_SLEEPQ_LOCK(thread->cpu);
  42.             /* The notify and timeout can collide; in which case both may
  43.              * attempt to delete from the sleepQ; only let one do it.
  44.              */
  45.             if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
  46.                 _PR_DEL_SLEEPQ(thread, PR_TRUE);
  47.             _PR_SLEEPQ_UNLOCK(thread->cpu);
  48.  
  49.         if (thread->flags & _PR_SUSPENDING) {
  50.         /*
  51.          * set thread state to SUSPENDED; a Resume operation
  52.          * on the thread will move it to the runQ
  53.          */
  54.                 thread->state = _PR_SUSPENDED;
  55.         _PR_MISCQ_LOCK(thread->cpu);
  56.         _PR_ADD_SUSPENDQ(thread, thread->cpu);
  57.         _PR_MISCQ_UNLOCK(thread->cpu);
  58.                 _PR_THREAD_UNLOCK(thread);
  59.         } else {
  60.                 /* Make thread runnable */
  61.                 thread->state = _PR_RUNNABLE;
  62.                 _PR_THREAD_UNLOCK(thread);
  63.  
  64.                 _PR_AddThreadToRunQ(me, thread);
  65.                 _PR_MD_WAKEUP_WAITER(thread);
  66.             }
  67.  
  68.             rv = PR_TRUE;
  69.         } else {
  70.             /* Thread has already been notified */
  71.             _PR_THREAD_UNLOCK(thread);
  72.             rv = PR_FALSE;
  73.         }
  74.     } else { /* If the thread is a native thread */
  75.         if (thread->wait.cvar) {
  76.             thread->wait.cvar = NULL;
  77.  
  78.         if (thread->flags & _PR_SUSPENDING) {
  79.         /*
  80.          * set thread state to SUSPENDED; a Resume operation
  81.          * on the thread will enable the thread to run
  82.          */
  83.                 thread->state = _PR_SUSPENDED;
  84.          } else
  85.                 thread->state = _PR_RUNNING;
  86.             _PR_THREAD_UNLOCK(thread);
  87.             _PR_MD_WAKEUP_WAITER(thread);
  88.             rv = PR_TRUE;
  89.         } else {
  90.             _PR_THREAD_UNLOCK(thread);
  91.             rv = PR_FALSE;
  92.         }    
  93.     }    
  94.  
  95.     return rv;
  96. }
  97.  
  98. /*
  99.  * Notify thread waiting on cvar; called when thread is interrupted
  100.  *     The thread lock is held on entry and released before return
  101.  */
  102. void _PR_NotifyLockedThread (PRThread *thread)
  103. {
  104.     PRThread *me = _PR_MD_CURRENT_THREAD();
  105.     PRCondVar *cvar;
  106.     PRThreadPriority pri;
  107.  
  108.     if ( !_PR_IS_NATIVE_THREAD(me))
  109.         PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
  110.  
  111.     cvar = thread->wait.cvar;
  112.     thread->wait.cvar = NULL;
  113.     _PR_THREAD_UNLOCK(thread);
  114.  
  115.     _PR_CVAR_LOCK(cvar);
  116.     _PR_THREAD_LOCK(thread);
  117.  
  118.     if (!_PR_IS_NATIVE_THREAD(thread)) {
  119.             _PR_SLEEPQ_LOCK(thread->cpu);
  120.             /* The notify and timeout can collide; in which case both may
  121.              * attempt to delete from the sleepQ; only let one do it.
  122.              */
  123.             if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
  124.                 _PR_DEL_SLEEPQ(thread, PR_TRUE);
  125.             _PR_SLEEPQ_UNLOCK(thread->cpu);
  126.  
  127.         /* Make thread runnable */
  128.         pri = thread->priority;
  129.         thread->state = _PR_RUNNABLE;
  130.  
  131.         PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  132.  
  133.             _PR_AddThreadToRunQ(me, thread);
  134.             _PR_THREAD_UNLOCK(thread);
  135.  
  136.             _PR_MD_WAKEUP_WAITER(thread);
  137.     } else {
  138.         if (thread->flags & _PR_SUSPENDING) {
  139.         /*
  140.          * set thread state to SUSPENDED; a Resume operation
  141.          * on the thread will enable the thread to run
  142.          */
  143.                 thread->state = _PR_SUSPENDED;
  144.          } else
  145.                 thread->state = _PR_RUNNING;
  146.             _PR_THREAD_UNLOCK(thread);
  147.             _PR_MD_WAKEUP_WAITER(thread);
  148.     }    
  149.  
  150.     _PR_CVAR_UNLOCK(cvar);
  151.     return;
  152. }
  153.  
  154. /*
  155. ** Make the given thread wait for the given condition variable
  156. */
  157. PRStatus _PR_WaitCondVar(
  158.     PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
  159. {
  160.     intn is;
  161.     PRStatus rv = PR_SUCCESS;
  162.  
  163.     PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
  164.     PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  165.  
  166. #ifdef _PR_GLOBAL_THREADS_ONLY
  167.     if (_PR_PENDING_INTERRUPT(thread)) {
  168.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  169.         thread->flags &= ~_PR_INTERRUPT;
  170.         return PR_FAILURE;
  171.     }
  172.  
  173.     thread->wait.cvar = cvar;
  174.     lock->owner = NULL;
  175.     _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout);
  176.     thread->wait.cvar = NULL;
  177.     lock->owner = thread;
  178.     if (_PR_PENDING_INTERRUPT(thread)) {
  179.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  180.         thread->flags &= ~_PR_INTERRUPT;
  181.         return PR_FAILURE;
  182.     }
  183.  
  184.     return PR_SUCCESS;
  185. #else  /* _PR_GLOBAL_THREADS_ONLY */
  186.  
  187.     if ( !_PR_IS_NATIVE_THREAD(thread))
  188.         _PR_INTSOFF(is);
  189.  
  190.     _PR_CVAR_LOCK(cvar);
  191.     _PR_THREAD_LOCK(thread);
  192.  
  193.     if (_PR_PENDING_INTERRUPT(thread)) {
  194.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  195.         thread->flags &= ~_PR_INTERRUPT;
  196.         _PR_CVAR_UNLOCK(cvar);
  197.         _PR_THREAD_UNLOCK(thread);
  198.         if ( !_PR_IS_NATIVE_THREAD(thread))
  199.             _PR_INTSON(is);
  200.         return PR_FAILURE;
  201.     }
  202.  
  203.     thread->state = _PR_COND_WAIT;
  204.     thread->wait.cvar = cvar;
  205.  
  206.     /*
  207.     ** Put the caller thread on the condition variable's wait Q
  208.     */
  209.     PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ);
  210.  
  211.     /* Note- for global scope threads, we don't put them on the
  212.      *       global sleepQ, so each global thread must put itself
  213.      *       to sleep only for the time it wants to.
  214.      */
  215.     if ( !_PR_IS_NATIVE_THREAD(thread) ) {
  216.         _PR_SLEEPQ_LOCK(thread->cpu);
  217.         _PR_ADD_SLEEPQ(thread, timeout);
  218.         _PR_SLEEPQ_UNLOCK(thread->cpu);
  219.     }
  220.     _PR_CVAR_UNLOCK(cvar);
  221.     _PR_THREAD_UNLOCK(thread);
  222.    
  223.     /* 
  224.     ** Release lock protecting the condition variable and thereby giving time 
  225.     ** to the next thread which can potentially notify on the condition variable
  226.     */
  227.     PR_Unlock(lock);
  228.  
  229.     PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
  230.        ("PR_Wait: cvar=%p waiting for %d", cvar, timeout));
  231.  
  232.     rv = _PR_MD_WAIT(thread, timeout);
  233.  
  234.     _PR_CVAR_LOCK(cvar);
  235.     PR_REMOVE_LINK(&thread->waitQLinks);
  236.     _PR_CVAR_UNLOCK(cvar);
  237.  
  238.     PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
  239.        ("PR_Wait: cvar=%p done waiting", cvar));
  240.  
  241.     if ( !_PR_IS_NATIVE_THREAD(thread))
  242.         _PR_INTSON(is);
  243.  
  244.     /* Acquire lock again that we had just relinquished */
  245.     PR_Lock(lock);
  246.  
  247.     if (_PR_PENDING_INTERRUPT(thread)) {
  248.         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
  249.         thread->flags &= ~_PR_INTERRUPT;
  250.         return PR_FAILURE;
  251.     }
  252.  
  253.     return rv;
  254. #endif  /* _PR_GLOBAL_THREADS_ONLY */
  255. }
  256.  
  257. void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me)
  258. {
  259. #ifdef _PR_GLOBAL_THREADS_ONLY
  260.     _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock);
  261. #else  /* _PR_GLOBAL_THREADS_ONLY */
  262.  
  263.     PRCList *q;
  264.     PRIntn is;
  265.  
  266.     if ( !_PR_IS_NATIVE_THREAD(me))
  267.         _PR_INTSOFF(is);
  268.     PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
  269.  
  270.     _PR_CVAR_LOCK(cvar);
  271.     q = cvar->condQ.next;
  272.     while (q != &cvar->condQ) {
  273. #ifndef XP_MAC
  274.         PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar));
  275. #endif
  276.         if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar)  {
  277.             if (NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE)
  278.                 break;
  279.         }
  280.         q = q->next;
  281.     }
  282.     _PR_CVAR_UNLOCK(cvar);
  283.  
  284.     if ( !_PR_IS_NATIVE_THREAD(me))
  285.         _PR_INTSON(is);
  286.  
  287. #endif  /* _PR_GLOBAL_THREADS_ONLY */
  288. }
  289.  
  290. /*
  291. ** Cndition variable debugging log info.
  292. */
  293. PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen)
  294. {
  295.     PRUint32 nb;
  296.  
  297.     if (cvar->lock->owner) {
  298.     nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]",
  299.              cvar, cvar->lock->owner->id, cvar->lock->owner);
  300.     } else {
  301.     nb = PR_snprintf(buf, buflen, "[%p]", cvar);
  302.     }
  303.     return nb;
  304. }
  305.  
  306. /*
  307. ** Expire condition variable waits that are ready to expire. "now" is the current
  308. ** time.
  309. */
  310. void _PR_ClockInterrupt(void)
  311. {
  312.     PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
  313.     _PRCPU *cpu = me->cpu;
  314.     PRIntervalTime elapsed, now;
  315.  
  316.     PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
  317.     /* Figure out how much time elapsed since the last clock tick */
  318.     now = PR_IntervalNow();
  319.     elapsed = now - cpu->last_clock;
  320.     cpu->last_clock = now;
  321.  
  322. #ifndef XP_MAC
  323.     PR_LOG(_pr_clock_lm, PR_LOG_MAX,
  324.        ("ExpireWaits: elapsed=%lld usec", elapsed));
  325. #endif
  326.  
  327.     while(1) {
  328.         _PR_SLEEPQ_LOCK(cpu);
  329.         if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) {
  330.             _PR_SLEEPQ_UNLOCK(cpu);
  331.             break;
  332.         }
  333.  
  334.         thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
  335.  
  336.         if (elapsed < thread->sleep) {
  337.             thread->sleep -= elapsed;
  338.             _PR_SLEEPQMAX(thread->cpu) -= elapsed;
  339.             PR_ASSERT((PRInt32)(thread->sleep) >= 0);
  340.             _PR_SLEEPQ_UNLOCK(cpu);
  341.             break;
  342.         }
  343.         _PR_SLEEPQ_UNLOCK(cpu);
  344.  
  345.         PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
  346.  
  347.         _PR_THREAD_LOCK(thread);
  348.  
  349.         /*
  350.         ** Consume this sleeper's amount of elapsed time from the elapsed
  351.         ** time value. The next remaining piece of elapsed time will be
  352.         ** available for the next sleeping thread's timer.
  353.         */
  354.         _PR_SLEEPQ_LOCK(cpu);
  355.         PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ));
  356.         if (thread->flags & _PR_ON_SLEEPQ) {
  357.             _PR_DEL_SLEEPQ(thread, PR_FALSE);
  358.             elapsed -= thread->sleep;
  359.             _PR_SLEEPQ_UNLOCK(cpu);
  360.         } else {
  361.             /* Thread was already handled; Go get another one */
  362.             _PR_SLEEPQ_UNLOCK(cpu);
  363.             _PR_THREAD_UNLOCK(thread);
  364.             continue;
  365.         }
  366.  
  367.         /* Notify the thread waiting on the condition variable */
  368.         if (thread->flags & _PR_SUSPENDING) {
  369.         PR_ASSERT((thread->state == _PR_IO_WAIT) ||
  370.                 (thread->state == _PR_COND_WAIT));
  371.             /*
  372.             ** Thread is suspended and its condition timeout
  373.             ** expired. Transfer thread from sleepQ to suspendQ.
  374.             */
  375.             thread->wait.cvar = NULL;
  376.             _PR_MISCQ_LOCK(cpu);
  377.             thread->state = _PR_SUSPENDED;
  378.             _PR_ADD_SUSPENDQ(thread, cpu);
  379.             _PR_MISCQ_UNLOCK(cpu);
  380.         } else {
  381.             if (thread->wait.cvar) {
  382.                 PRThreadPriority pri;
  383.  
  384.                 /* Do work very similar to what NotifyThread does */
  385.                 PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );
  386.  
  387.                 /* Make thread runnable */
  388.                 pri = thread->priority;
  389.                 thread->state = _PR_RUNNABLE;
  390.                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  391.  
  392.                 PR_ASSERT(thread->cpu == cpu);
  393.                 _PR_RUNQ_LOCK(cpu);
  394.                 _PR_ADD_RUNQ(thread, cpu, pri);
  395.                 _PR_RUNQ_UNLOCK(cpu);
  396.  
  397.                 if (pri > me->priority)
  398.                     _PR_SET_RESCHED_FLAG();
  399.  
  400.                 thread->wait.cvar = NULL;
  401.  
  402.                 _PR_MD_WAKEUP_WAITER(thread);
  403.  
  404.             } else if (thread->io_pending == PR_TRUE) {
  405.                 /* Need to put IO sleeper back on runq */
  406.                 int pri = thread->priority;
  407.  
  408.                 thread->io_suspended = PR_TRUE;
  409.  
  410.                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
  411.                 PR_ASSERT(thread->cpu == cpu);
  412.                 thread->state = _PR_RUNNABLE;
  413.                 _PR_RUNQ_LOCK(cpu);
  414.                 _PR_ADD_RUNQ(thread, cpu, pri);
  415.                 _PR_RUNQ_UNLOCK(cpu);
  416.             }
  417.         }
  418.         _PR_THREAD_UNLOCK(thread);
  419.     }
  420. }
  421.  
  422. /************************************************************************/
  423.  
  424. /*
  425. ** Create a new condition variable.
  426. **     "lock" is the lock to use with the condition variable.
  427. **
  428. ** Condition variables are synchronization objects that threads can use
  429. ** to wait for some condition to occur.
  430. **
  431. ** This may fail if memory is tight or if some operating system resource
  432. ** is low.
  433. */
  434. PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
  435. {
  436.     PRCondVar *cvar;
  437.  
  438.     PR_ASSERT(lock != NULL);
  439.  
  440.     cvar = PR_NEWZAP(PRCondVar);
  441.     if (cvar) {
  442. #ifdef _PR_GLOBAL_THREADS_ONLY
  443.     if(_PR_MD_NEW_CV(&cvar->md)) {
  444.         PR_DELETE(cvar);
  445.         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  446.         return NULL;
  447.     }
  448. #endif
  449.         if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) {
  450.         PR_DELETE(cvar);
  451.         PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
  452.         return NULL;
  453.     }
  454.     cvar->lock = lock;
  455.     PR_INIT_CLIST(&cvar->condQ);
  456.  
  457.     } else {
  458.         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
  459.     }
  460.     return cvar;
  461. }
  462.  
  463. /*
  464. ** Destroy a condition variable. There must be no thread
  465. ** waiting on the condvar. The caller is responsible for guaranteeing
  466. ** that the condvar is no longer in use.
  467. **
  468. */
  469. PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
  470. {
  471.     PR_ASSERT(cvar->condQ.next == &cvar->condQ);
  472.  
  473. #ifdef _PR_GLOBAL_THREADS_ONLY
  474.     _PR_MD_FREE_CV(&cvar->md);
  475. #endif
  476.     _PR_MD_FREE_LOCK(&(cvar->ilock));
  477.  
  478.     PR_DELETE(cvar);
  479. }
  480.  
  481. /*
  482. ** Wait for a notify on the condition variable. Sleep for "tiemout" amount
  483. ** of ticks (if "timeout" is zero then the sleep is indefinite). While
  484. ** the thread is waiting it unlocks lock. When the wait has
  485. ** finished the thread regains control of the condition variable after
  486. ** locking the associated lock.
  487. **
  488. ** The thread waiting on the condvar will be resumed when the condvar is
  489. ** notified (assuming the thread is the next in line to receive the
  490. ** notify) or when the timeout elapses.
  491. **
  492. ** Returns PR_FAILURE if the caller has not locked the lock associated
  493. ** with the condition variable or the thread has been interrupted.
  494. */
  495. extern PRThread *suspendAllThread;
  496. PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
  497. {
  498.     PRThread *me = _PR_MD_CURRENT_THREAD();
  499.  
  500.     PR_ASSERT(cvar->lock->owner == me);
  501.     PR_ASSERT(me != suspendAllThread);
  502.         if (cvar->lock->owner != me) return PR_FAILURE;
  503.  
  504.     return _PR_WaitCondVar(me, cvar, cvar->lock, timeout);
  505. }
  506.  
  507. /*
  508. ** Notify the highest priority thread waiting on the condition
  509. ** variable. If a thread is waiting on the condition variable (using
  510. ** PR_Wait) then it is awakened and begins waiting on the lock.
  511. */
  512. PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
  513. {
  514.     PRThread *me = _PR_MD_CURRENT_THREAD();
  515.  
  516.     PR_ASSERT(cvar->lock->owner == me);
  517.     PR_ASSERT(me != suspendAllThread);
  518.     if (cvar->lock->owner != me) return PR_FAILURE;
  519.  
  520.     _PR_NotifyCondVar(cvar, me);
  521.     return PR_SUCCESS;
  522. }
  523.  
  524. /*
  525. ** Notify all of the threads waiting on the condition variable. All of
  526. ** threads are notified in turn. The highest priority thread will
  527. ** probably acquire the lock.
  528. */
  529. PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
  530. {
  531.     PRCList *q;
  532.     PRIntn is;
  533.     PRThread *me = _PR_MD_CURRENT_THREAD();
  534.  
  535.     PR_ASSERT(cvar->lock->owner == me);
  536.     if (cvar->lock->owner != me) return PR_FAILURE;
  537.  
  538. #ifdef _PR_GLOBAL_THREADS_ONLY
  539.     _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock);
  540.     return PR_SUCCESS;
  541. #else  /* _PR_GLOBAL_THREADS_ONLY */
  542.     if ( !_PR_IS_NATIVE_THREAD(me))
  543.         _PR_INTSOFF(is);
  544.     _PR_CVAR_LOCK(cvar);
  545.     q = cvar->condQ.next;
  546.     while (q != &cvar->condQ) {
  547.         PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
  548.         NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
  549.         q = q->next;
  550.     }
  551.     _PR_CVAR_UNLOCK(cvar);
  552.     if (!_PR_IS_NATIVE_THREAD(me))
  553.         _PR_INTSON(is);
  554.  
  555.     return PR_SUCCESS;
  556. #endif  /* _PR_GLOBAL_THREADS_ONLY */
  557. }
  558.  
  559.  
  560. /*********************************************************************/
  561. /*********************************************************************/
  562. /********************ROUTINES FOR DCE EMULATION***********************/
  563. /*********************************************************************/
  564. /*********************************************************************/
  565. #include "prpdce.h"
  566.  
  567. PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
  568. {
  569.     PRCondVar *cvar = PR_NEWZAP(PRCondVar);
  570.     if (NULL != cvar)
  571.     {
  572.         if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE)
  573.         {
  574.             PR_DELETE(cvar); cvar = NULL;
  575.         }
  576.         else
  577.         {
  578.             PR_INIT_CLIST(&cvar->condQ);
  579.             cvar->lock = _PR_NAKED_CV_LOCK;
  580.         }
  581.  
  582.     }
  583.     return cvar;
  584. }
  585.  
  586. PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
  587. {
  588.     PR_ASSERT(cvar->condQ.next == &cvar->condQ);
  589.     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
  590.  
  591.     _PR_MD_FREE_LOCK(&(cvar->ilock));
  592.  
  593.     PR_DELETE(cvar);
  594. }
  595.  
  596. PR_IMPLEMENT(PRStatus) PRP_NakedWait(
  597.     PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
  598. {
  599.     PRThread *me = _PR_MD_CURRENT_THREAD();
  600.     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
  601.     return _PR_WaitCondVar(me, cvar, lock, timeout);
  602. }  /* PRP_NakedWait */
  603.  
  604. PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
  605. {
  606.     PRThread *me = _PR_MD_CURRENT_THREAD();
  607.     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
  608.  
  609.     _PR_NotifyCondVar(cvar, me);
  610.  
  611.     return PR_SUCCESS;
  612. }  /* PRP_NakedNotify */
  613.  
  614. PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
  615. {
  616.     PRCList *q;
  617.     PRIntn is;
  618.     PRThread *me = _PR_MD_CURRENT_THREAD();
  619.     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
  620.  
  621.     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
  622.     _PR_MD_LOCK( &(cvar->ilock) );
  623.     q = cvar->condQ.next;
  624.     while (q != &cvar->condQ) {
  625.         PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
  626.         NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
  627.         q = q->next;
  628.     }
  629.     _PR_MD_UNLOCK( &(cvar->ilock) );
  630.     if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
  631.  
  632.     return PR_SUCCESS;
  633. }  /* PRP_NakedBroadcast */
  634.  
  635.