tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

prucv.c (17734B)


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