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