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