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