Back to index

lightning-sunbird  0.9+nobinonly
prucv.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include "primpl.h"
00040 #include "prinrval.h"
00041 #include "prtypes.h"
00042 
00043 #if defined(WIN95)
00044 /*
00045 ** Some local variables report warnings on Win95 because the code paths 
00046 ** using them are conditioned on HAVE_CUSTOME_USER_THREADS.
00047 ** The pragma suppresses the warning.
00048 ** 
00049 */
00050 #pragma warning(disable : 4101)
00051 #endif
00052 
00053 
00054 /*
00055 ** Notify one thread that it has finished waiting on a condition variable
00056 ** Caller must hold the _PR_CVAR_LOCK(cv)
00057 */
00058 PRBool _PR_NotifyThread (PRThread *thread, PRThread *me)
00059 {
00060     PRBool rv;
00061 
00062     PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
00063 
00064     _PR_THREAD_LOCK(thread);
00065     PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00066     if ( !_PR_IS_NATIVE_THREAD(thread) ) {
00067         if (thread->wait.cvar != NULL) {
00068             thread->wait.cvar = NULL;
00069 
00070             _PR_SLEEPQ_LOCK(thread->cpu);
00071             /* The notify and timeout can collide; in which case both may
00072              * attempt to delete from the sleepQ; only let one do it.
00073              */
00074             if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
00075                 _PR_DEL_SLEEPQ(thread, PR_TRUE);
00076             _PR_SLEEPQ_UNLOCK(thread->cpu);
00077 
00078            if (thread->flags & _PR_SUSPENDING) {
00079               /*
00080                * set thread state to SUSPENDED; a Resume operation
00081                * on the thread will move it to the runQ
00082                */
00083               thread->state = _PR_SUSPENDED;
00084               _PR_MISCQ_LOCK(thread->cpu);
00085               _PR_ADD_SUSPENDQ(thread, thread->cpu);
00086               _PR_MISCQ_UNLOCK(thread->cpu);
00087               _PR_THREAD_UNLOCK(thread);
00088            } else {
00089               /* Make thread runnable */
00090               thread->state = _PR_RUNNABLE;
00091               _PR_THREAD_UNLOCK(thread);
00092 
00093                 _PR_AddThreadToRunQ(me, thread);
00094                 _PR_MD_WAKEUP_WAITER(thread);
00095             }
00096 
00097             rv = PR_TRUE;
00098         } else {
00099             /* Thread has already been notified */
00100             _PR_THREAD_UNLOCK(thread);
00101             rv = PR_FALSE;
00102         }
00103     } else { /* If the thread is a native thread */
00104         if (thread->wait.cvar) {
00105             thread->wait.cvar = NULL;
00106 
00107            if (thread->flags & _PR_SUSPENDING) {
00108               /*
00109                * set thread state to SUSPENDED; a Resume operation
00110                * on the thread will enable the thread to run
00111                */
00112               thread->state = _PR_SUSPENDED;
00113             } else
00114               thread->state = _PR_RUNNING;
00115             _PR_THREAD_UNLOCK(thread);
00116             _PR_MD_WAKEUP_WAITER(thread);
00117             rv = PR_TRUE;
00118         } else {
00119             _PR_THREAD_UNLOCK(thread);
00120             rv = PR_FALSE;
00121         }    
00122     }    
00123 
00124     return rv;
00125 }
00126 
00127 /*
00128  * Notify thread waiting on cvar; called when thread is interrupted
00129  *     The thread lock is held on entry and released before return
00130  */
00131 void _PR_NotifyLockedThread (PRThread *thread)
00132 {
00133     PRThread *me = _PR_MD_CURRENT_THREAD();
00134     PRCondVar *cvar;
00135     PRThreadPriority pri;
00136 
00137     if ( !_PR_IS_NATIVE_THREAD(me))
00138        PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
00139 
00140     cvar = thread->wait.cvar;
00141     thread->wait.cvar = NULL;
00142     _PR_THREAD_UNLOCK(thread);
00143 
00144     _PR_CVAR_LOCK(cvar);
00145     _PR_THREAD_LOCK(thread);
00146 
00147     if (!_PR_IS_NATIVE_THREAD(thread)) {
00148             _PR_SLEEPQ_LOCK(thread->cpu);
00149             /* The notify and timeout can collide; in which case both may
00150              * attempt to delete from the sleepQ; only let one do it.
00151              */
00152             if (thread->flags & (_PR_ON_SLEEPQ|_PR_ON_PAUSEQ))
00153                 _PR_DEL_SLEEPQ(thread, PR_TRUE);
00154             _PR_SLEEPQ_UNLOCK(thread->cpu);
00155 
00156            /* Make thread runnable */
00157            pri = thread->priority;
00158            thread->state = _PR_RUNNABLE;
00159 
00160            PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00161 
00162             _PR_AddThreadToRunQ(me, thread);
00163             _PR_THREAD_UNLOCK(thread);
00164 
00165             _PR_MD_WAKEUP_WAITER(thread);
00166     } else {
00167            if (thread->flags & _PR_SUSPENDING) {
00168               /*
00169                * set thread state to SUSPENDED; a Resume operation
00170                * on the thread will enable the thread to run
00171                */
00172               thread->state = _PR_SUSPENDED;
00173             } else
00174               thread->state = _PR_RUNNING;
00175             _PR_THREAD_UNLOCK(thread);
00176             _PR_MD_WAKEUP_WAITER(thread);
00177     }    
00178 
00179     _PR_CVAR_UNLOCK(cvar);
00180     return;
00181 }
00182 
00183 /*
00184 ** Make the given thread wait for the given condition variable
00185 */
00186 PRStatus _PR_WaitCondVar(
00187     PRThread *thread, PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
00188 {
00189     PRIntn is;
00190     PRStatus rv = PR_SUCCESS;
00191 
00192     PR_ASSERT(thread == _PR_MD_CURRENT_THREAD());
00193     PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00194 
00195 #ifdef _PR_GLOBAL_THREADS_ONLY
00196     if (_PR_PENDING_INTERRUPT(thread)) {
00197         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00198         thread->flags &= ~_PR_INTERRUPT;
00199         return PR_FAILURE;
00200     }
00201 
00202     thread->wait.cvar = cvar;
00203     lock->owner = NULL;
00204     _PR_MD_WAIT_CV(&cvar->md,&lock->ilock, timeout);
00205     thread->wait.cvar = NULL;
00206     lock->owner = thread;
00207     if (_PR_PENDING_INTERRUPT(thread)) {
00208         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00209         thread->flags &= ~_PR_INTERRUPT;
00210         return PR_FAILURE;
00211     }
00212 
00213     return PR_SUCCESS;
00214 #else  /* _PR_GLOBAL_THREADS_ONLY */
00215 
00216     if ( !_PR_IS_NATIVE_THREAD(thread))
00217        _PR_INTSOFF(is);
00218 
00219     _PR_CVAR_LOCK(cvar);
00220     _PR_THREAD_LOCK(thread);
00221 
00222     if (_PR_PENDING_INTERRUPT(thread)) {
00223         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00224         thread->flags &= ~_PR_INTERRUPT;
00225        _PR_CVAR_UNLOCK(cvar);
00226        _PR_THREAD_UNLOCK(thread);
00227        if ( !_PR_IS_NATIVE_THREAD(thread))
00228               _PR_INTSON(is);
00229         return PR_FAILURE;
00230     }
00231 
00232     thread->state = _PR_COND_WAIT;
00233     thread->wait.cvar = cvar;
00234 
00235     /*
00236     ** Put the caller thread on the condition variable's wait Q
00237     */
00238     PR_APPEND_LINK(&thread->waitQLinks, &cvar->condQ);
00239 
00240     /* Note- for global scope threads, we don't put them on the
00241      *       global sleepQ, so each global thread must put itself
00242      *       to sleep only for the time it wants to.
00243      */
00244     if ( !_PR_IS_NATIVE_THREAD(thread) ) {
00245         _PR_SLEEPQ_LOCK(thread->cpu);
00246         _PR_ADD_SLEEPQ(thread, timeout);
00247         _PR_SLEEPQ_UNLOCK(thread->cpu);
00248     }
00249     _PR_CVAR_UNLOCK(cvar);
00250     _PR_THREAD_UNLOCK(thread);
00251    
00252     /* 
00253     ** Release lock protecting the condition variable and thereby giving time 
00254     ** to the next thread which can potentially notify on the condition variable
00255     */
00256     PR_Unlock(lock);
00257 
00258     PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
00259           ("PR_Wait: cvar=%p waiting for %d", cvar, timeout));
00260 
00261     rv = _PR_MD_WAIT(thread, timeout);
00262 
00263     _PR_CVAR_LOCK(cvar);
00264     PR_REMOVE_LINK(&thread->waitQLinks);
00265     _PR_CVAR_UNLOCK(cvar);
00266 
00267     PR_LOG(_pr_cvar_lm, PR_LOG_MIN,
00268           ("PR_Wait: cvar=%p done waiting", cvar));
00269 
00270     if ( !_PR_IS_NATIVE_THREAD(thread))
00271        _PR_INTSON(is);
00272 
00273     /* Acquire lock again that we had just relinquished */
00274     PR_Lock(lock);
00275 
00276     if (_PR_PENDING_INTERRUPT(thread)) {
00277         PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
00278         thread->flags &= ~_PR_INTERRUPT;
00279         return PR_FAILURE;
00280     }
00281 
00282     return rv;
00283 #endif  /* _PR_GLOBAL_THREADS_ONLY */
00284 }
00285 
00286 void _PR_NotifyCondVar(PRCondVar *cvar, PRThread *me)
00287 {
00288 #ifdef _PR_GLOBAL_THREADS_ONLY
00289     _PR_MD_NOTIFY_CV(&cvar->md, &cvar->lock->ilock);
00290 #else  /* _PR_GLOBAL_THREADS_ONLY */
00291 
00292     PRCList *q;
00293     PRIntn is;
00294 
00295     if ( !_PR_IS_NATIVE_THREAD(me))
00296        _PR_INTSOFF(is);
00297     PR_ASSERT(_PR_IS_NATIVE_THREAD(me) || _PR_MD_GET_INTSOFF() != 0);
00298 
00299     _PR_CVAR_LOCK(cvar);
00300     q = cvar->condQ.next;
00301     while (q != &cvar->condQ) {
00302 #ifndef XP_MAC
00303         PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("_PR_NotifyCondVar: cvar=%p", cvar));
00304 #endif
00305         if (_PR_THREAD_CONDQ_PTR(q)->wait.cvar)  {
00306             if (_PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me) == PR_TRUE)
00307                 break;
00308         }
00309         q = q->next;
00310     }
00311     _PR_CVAR_UNLOCK(cvar);
00312 
00313     if ( !_PR_IS_NATIVE_THREAD(me))
00314        _PR_INTSON(is);
00315 
00316 #endif  /* _PR_GLOBAL_THREADS_ONLY */
00317 }
00318 
00319 /*
00320 ** Cndition variable debugging log info.
00321 */
00322 PRUint32 _PR_CondVarToString(PRCondVar *cvar, char *buf, PRUint32 buflen)
00323 {
00324     PRUint32 nb;
00325 
00326     if (cvar->lock->owner) {
00327        nb = PR_snprintf(buf, buflen, "[%p] owner=%ld[%p]",
00328                       cvar, cvar->lock->owner->id, cvar->lock->owner);
00329     } else {
00330        nb = PR_snprintf(buf, buflen, "[%p]", cvar);
00331     }
00332     return nb;
00333 }
00334 
00335 /*
00336 ** Expire condition variable waits that are ready to expire. "now" is the current
00337 ** time.
00338 */
00339 void _PR_ClockInterrupt(void)
00340 {
00341     PRThread *thread, *me = _PR_MD_CURRENT_THREAD();
00342     _PRCPU *cpu = me->cpu;
00343     PRIntervalTime elapsed, now;
00344  
00345     PR_ASSERT(_PR_MD_GET_INTSOFF() != 0);
00346     /* Figure out how much time elapsed since the last clock tick */
00347     now = PR_IntervalNow();
00348     elapsed = now - cpu->last_clock;
00349     cpu->last_clock = now;
00350 
00351 #ifndef XP_MAC
00352     PR_LOG(_pr_clock_lm, PR_LOG_MAX,
00353           ("ExpireWaits: elapsed=%lld usec", elapsed));
00354 #endif
00355 
00356     while(1) {
00357         _PR_SLEEPQ_LOCK(cpu);
00358         if (_PR_SLEEPQ(cpu).next == &_PR_SLEEPQ(cpu)) {
00359             _PR_SLEEPQ_UNLOCK(cpu);
00360             break;
00361         }
00362 
00363         thread = _PR_THREAD_PTR(_PR_SLEEPQ(cpu).next);
00364         PR_ASSERT(thread->cpu == cpu);
00365 
00366         if (elapsed < thread->sleep) {
00367             thread->sleep -= elapsed;
00368             _PR_SLEEPQMAX(thread->cpu) -= elapsed;
00369             _PR_SLEEPQ_UNLOCK(cpu);
00370             break;
00371         }
00372         _PR_SLEEPQ_UNLOCK(cpu);
00373 
00374         PR_ASSERT(!_PR_IS_NATIVE_THREAD(thread));
00375 
00376         _PR_THREAD_LOCK(thread);
00377 
00378         if (thread->cpu != cpu) {
00379             /*
00380             ** The thread was switched to another CPU
00381             ** between the time we unlocked the sleep
00382             ** queue and the time we acquired the thread
00383             ** lock, so it is none of our business now.
00384             */
00385             _PR_THREAD_UNLOCK(thread);
00386             continue;
00387         }
00388 
00389         /*
00390         ** Consume this sleeper's amount of elapsed time from the elapsed
00391         ** time value. The next remaining piece of elapsed time will be
00392         ** available for the next sleeping thread's timer.
00393         */
00394         _PR_SLEEPQ_LOCK(cpu);
00395         PR_ASSERT(!(thread->flags & _PR_ON_PAUSEQ));
00396         if (thread->flags & _PR_ON_SLEEPQ) {
00397             _PR_DEL_SLEEPQ(thread, PR_FALSE);
00398             elapsed -= thread->sleep;
00399             _PR_SLEEPQ_UNLOCK(cpu);
00400         } else {
00401             /* Thread was already handled; Go get another one */
00402             _PR_SLEEPQ_UNLOCK(cpu);
00403             _PR_THREAD_UNLOCK(thread);
00404             continue;
00405         }
00406 
00407         /* Notify the thread waiting on the condition variable */
00408         if (thread->flags & _PR_SUSPENDING) {
00409               PR_ASSERT((thread->state == _PR_IO_WAIT) ||
00410                             (thread->state == _PR_COND_WAIT));
00411             /*
00412             ** Thread is suspended and its condition timeout
00413             ** expired. Transfer thread from sleepQ to suspendQ.
00414             */
00415             thread->wait.cvar = NULL;
00416             _PR_MISCQ_LOCK(cpu);
00417             thread->state = _PR_SUSPENDED;
00418             _PR_ADD_SUSPENDQ(thread, cpu);
00419             _PR_MISCQ_UNLOCK(cpu);
00420         } else {
00421             if (thread->wait.cvar) {
00422                 PRThreadPriority pri;
00423 
00424                 /* Do work very similar to what _PR_NotifyThread does */
00425                 PR_ASSERT( !_PR_IS_NATIVE_THREAD(thread) );
00426 
00427                 /* Make thread runnable */
00428                 pri = thread->priority;
00429                 thread->state = _PR_RUNNABLE;
00430                 PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00431 
00432                 PR_ASSERT(thread->cpu == cpu);
00433                 _PR_RUNQ_LOCK(cpu);
00434                 _PR_ADD_RUNQ(thread, cpu, pri);
00435                 _PR_RUNQ_UNLOCK(cpu);
00436 
00437                 if (pri > me->priority)
00438                     _PR_SET_RESCHED_FLAG();
00439 
00440                 thread->wait.cvar = NULL;
00441 
00442                 _PR_MD_WAKEUP_WAITER(thread);
00443 
00444             } else if (thread->io_pending == PR_TRUE) {
00445                 /* Need to put IO sleeper back on runq */
00446                 int pri = thread->priority;
00447 
00448                 thread->io_suspended = PR_TRUE;
00449 #ifdef WINNT
00450                             /*
00451                              * For NT, record the cpu on which I/O was issued
00452                              * I/O cancellation is done on the same cpu
00453                              */
00454                 thread->md.thr_bound_cpu = cpu;
00455 #endif
00456 
00457                             PR_ASSERT(!(thread->flags & _PR_IDLE_THREAD));
00458                 PR_ASSERT(thread->cpu == cpu);
00459                 thread->state = _PR_RUNNABLE;
00460                 _PR_RUNQ_LOCK(cpu);
00461                 _PR_ADD_RUNQ(thread, cpu, pri);
00462                 _PR_RUNQ_UNLOCK(cpu);
00463             }
00464         }
00465         _PR_THREAD_UNLOCK(thread);
00466     }
00467 }
00468 
00469 /************************************************************************/
00470 
00471 /*
00472 ** Create a new condition variable.
00473 **     "lock" is the lock to use with the condition variable.
00474 **
00475 ** Condition variables are synchronization objects that threads can use
00476 ** to wait for some condition to occur.
00477 **
00478 ** This may fail if memory is tight or if some operating system resource
00479 ** is low.
00480 */
00481 PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
00482 {
00483     PRCondVar *cvar;
00484 
00485     PR_ASSERT(lock != NULL);
00486 
00487     cvar = PR_NEWZAP(PRCondVar);
00488     if (cvar) {
00489 #ifdef _PR_GLOBAL_THREADS_ONLY
00490        if(_PR_MD_NEW_CV(&cvar->md)) {
00491               PR_DELETE(cvar);
00492               PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
00493               return NULL;
00494        }
00495 #endif
00496         if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE) {
00497               PR_DELETE(cvar);
00498               PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, 0);
00499               return NULL;
00500        }
00501     cvar->lock = lock;
00502        PR_INIT_CLIST(&cvar->condQ);
00503 
00504     } else {
00505         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00506     }
00507     return cvar;
00508 }
00509 
00510 /*
00511 ** Destroy a condition variable. There must be no thread
00512 ** waiting on the condvar. The caller is responsible for guaranteeing
00513 ** that the condvar is no longer in use.
00514 **
00515 */
00516 PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
00517 {
00518     PR_ASSERT(cvar->condQ.next == &cvar->condQ);
00519 
00520 #ifdef _PR_GLOBAL_THREADS_ONLY
00521     _PR_MD_FREE_CV(&cvar->md);
00522 #endif
00523     _PR_MD_FREE_LOCK(&(cvar->ilock));
00524  
00525     PR_DELETE(cvar);
00526 }
00527 
00528 /*
00529 ** Wait for a notify on the condition variable. Sleep for "tiemout" amount
00530 ** of ticks (if "timeout" is zero then the sleep is indefinite). While
00531 ** the thread is waiting it unlocks lock. When the wait has
00532 ** finished the thread regains control of the condition variable after
00533 ** locking the associated lock.
00534 **
00535 ** The thread waiting on the condvar will be resumed when the condvar is
00536 ** notified (assuming the thread is the next in line to receive the
00537 ** notify) or when the timeout elapses.
00538 **
00539 ** Returns PR_FAILURE if the caller has not locked the lock associated
00540 ** with the condition variable or the thread has been interrupted.
00541 */
00542 extern PRThread *suspendAllThread;
00543 PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
00544 {
00545     PRThread *me = _PR_MD_CURRENT_THREAD();
00546 
00547        PR_ASSERT(cvar->lock->owner == me);
00548        PR_ASSERT(me != suspendAllThread);
00549        if (cvar->lock->owner != me) return PR_FAILURE;
00550 
00551        return _PR_WaitCondVar(me, cvar, cvar->lock, timeout);
00552 }
00553 
00554 /*
00555 ** Notify the highest priority thread waiting on the condition
00556 ** variable. If a thread is waiting on the condition variable (using
00557 ** PR_Wait) then it is awakened and begins waiting on the lock.
00558 */
00559 PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
00560 {
00561     PRThread *me = _PR_MD_CURRENT_THREAD();
00562 
00563     PR_ASSERT(cvar->lock->owner == me);
00564     PR_ASSERT(me != suspendAllThread);
00565     if (cvar->lock->owner != me) return PR_FAILURE;
00566 
00567     _PR_NotifyCondVar(cvar, me);
00568     return PR_SUCCESS;
00569 }
00570 
00571 /*
00572 ** Notify all of the threads waiting on the condition variable. All of
00573 ** threads are notified in turn. The highest priority thread will
00574 ** probably acquire the lock.
00575 */
00576 PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
00577 {
00578     PRCList *q;
00579     PRIntn is;
00580     PRThread *me = _PR_MD_CURRENT_THREAD();
00581 
00582     PR_ASSERT(cvar->lock->owner == me);
00583     if (cvar->lock->owner != me) return PR_FAILURE;
00584 
00585 #ifdef _PR_GLOBAL_THREADS_ONLY
00586     _PR_MD_NOTIFYALL_CV(&cvar->md, &cvar->lock->ilock);
00587     return PR_SUCCESS;
00588 #else  /* _PR_GLOBAL_THREADS_ONLY */
00589     if ( !_PR_IS_NATIVE_THREAD(me))
00590        _PR_INTSOFF(is);
00591     _PR_CVAR_LOCK(cvar);
00592     q = cvar->condQ.next;
00593     while (q != &cvar->condQ) {
00594               PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
00595               _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
00596               q = q->next;
00597     }
00598     _PR_CVAR_UNLOCK(cvar);
00599     if (!_PR_IS_NATIVE_THREAD(me))
00600        _PR_INTSON(is);
00601 
00602     return PR_SUCCESS;
00603 #endif  /* _PR_GLOBAL_THREADS_ONLY */
00604 }
00605 
00606 
00607 /*********************************************************************/
00608 /*********************************************************************/
00609 /********************ROUTINES FOR DCE EMULATION***********************/
00610 /*********************************************************************/
00611 /*********************************************************************/
00612 #include "prpdce.h"
00613 
00614 PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
00615 {
00616     PRCondVar *cvar = PR_NEWZAP(PRCondVar);
00617     if (NULL != cvar)
00618     {
00619         if (_PR_MD_NEW_LOCK(&(cvar->ilock)) == PR_FAILURE)
00620         {
00621                   PR_DELETE(cvar); cvar = NULL;
00622            }
00623            else
00624            {
00625                PR_INIT_CLIST(&cvar->condQ);
00626             cvar->lock = _PR_NAKED_CV_LOCK;
00627            }
00628 
00629     }
00630     return cvar;
00631 }
00632 
00633 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
00634 {
00635     PR_ASSERT(cvar->condQ.next == &cvar->condQ);
00636     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
00637 
00638     _PR_MD_FREE_LOCK(&(cvar->ilock));
00639  
00640     PR_DELETE(cvar);
00641 }
00642 
00643 PR_IMPLEMENT(PRStatus) PRP_NakedWait(
00644        PRCondVar *cvar, PRLock *lock, PRIntervalTime timeout)
00645 {
00646     PRThread *me = _PR_MD_CURRENT_THREAD();
00647     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
00648        return _PR_WaitCondVar(me, cvar, lock, timeout);
00649 }  /* PRP_NakedWait */
00650 
00651 PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
00652 {
00653     PRThread *me = _PR_MD_CURRENT_THREAD();
00654     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
00655 
00656     _PR_NotifyCondVar(cvar, me);
00657 
00658     return PR_SUCCESS;
00659 }  /* PRP_NakedNotify */
00660 
00661 PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
00662 {
00663     PRCList *q;
00664     PRIntn is;
00665     PRThread *me = _PR_MD_CURRENT_THREAD();
00666     PR_ASSERT(_PR_NAKED_CV_LOCK == cvar->lock);
00667 
00668     if ( !_PR_IS_NATIVE_THREAD(me)) _PR_INTSOFF(is);
00669        _PR_MD_LOCK( &(cvar->ilock) );
00670     q = cvar->condQ.next;
00671     while (q != &cvar->condQ) {
00672               PR_LOG(_pr_cvar_lm, PR_LOG_MIN, ("PR_NotifyAll: cvar=%p", cvar));
00673               _PR_NotifyThread(_PR_THREAD_CONDQ_PTR(q), me);
00674               q = q->next;
00675     }
00676        _PR_MD_UNLOCK( &(cvar->ilock) );
00677     if (!_PR_IS_NATIVE_THREAD(me)) _PR_INTSON(is);
00678 
00679     return PR_SUCCESS;
00680 }  /* PRP_NakedBroadcast */
00681