Mercurial > trustbridge > nss-cmake-static
comparison nspr/pr/src/threads/combined/prucv.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
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 |