1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : ** File: ptsynch.c
40 : ** Descritpion: Implemenation for thread synchronization using pthreads
41 : ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h
42 : */
43 :
44 : #if defined(_PR_PTHREADS)
45 :
46 : #include "primpl.h"
47 : #include "obsolete/prsem.h"
48 :
49 : #include <string.h>
50 : #include <pthread.h>
51 : #include <sys/time.h>
52 :
53 : static pthread_mutexattr_t _pt_mattr;
54 : static pthread_condattr_t _pt_cvar_attr;
55 :
56 : #if defined(DEBUG)
57 : extern PTDebug pt_debug; /* this is shared between several modules */
58 :
59 : #if defined(_PR_DCETHREADS)
60 : static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct
61 : * in DCE threads) to compare with */
62 : #endif /* defined(_PR_DCETHREADS) */
63 : #endif /* defined(DEBUG) */
64 :
65 : #if defined(FREEBSD)
66 : /*
67 : * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK.
68 : * Newer versions return EBUSY. We still need to support both.
69 : */
70 : static int
71 : pt_pthread_mutex_is_locked(pthread_mutex_t *m)
72 : {
73 : int rv = pthread_mutex_trylock(m);
74 : return (EBUSY == rv || EDEADLK == rv);
75 : }
76 : #endif
77 :
78 : /**************************************************************/
79 : /**************************************************************/
80 : /*****************************LOCKS****************************/
81 : /**************************************************************/
82 : /**************************************************************/
83 :
84 20034 : void _PR_InitLocks(void)
85 : {
86 : int rv;
87 20034 : rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr);
88 20034 : PR_ASSERT(0 == rv);
89 :
90 : #ifdef LINUX
91 : #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
92 20034 : rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP);
93 20034 : PR_ASSERT(0 == rv);
94 : #endif
95 : #endif
96 :
97 20034 : rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr);
98 20034 : PR_ASSERT(0 == rv);
99 20034 : }
100 :
101 609115 : static void pt_PostNotifies(PRLock *lock, PRBool unlock)
102 : {
103 : PRIntn index, rv;
104 : _PT_Notified post;
105 609115 : _PT_Notified *notified, *prev = NULL;
106 : /*
107 : * Time to actually notify any conditions that were affected
108 : * while the lock was held. Get a copy of the list that's in
109 : * the lock structure and then zero the original. If it's
110 : * linked to other such structures, we own that storage.
111 : */
112 609115 : post = lock->notified; /* a safe copy; we own the lock */
113 :
114 : #if defined(DEBUG)
115 609115 : memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */
116 : #else
117 : lock->notified.length = 0; /* these are really sufficient */
118 : lock->notified.link = NULL;
119 : #endif
120 :
121 : /* should (may) we release lock before notifying? */
122 609115 : if (unlock)
123 : {
124 575092 : rv = pthread_mutex_unlock(&lock->mutex);
125 575092 : PR_ASSERT(0 == rv);
126 : }
127 :
128 609115 : notified = &post; /* this is where we start */
129 : do
130 : {
131 1218231 : for (index = 0; index < notified->length; ++index)
132 : {
133 609115 : PRCondVar *cv = notified->cv[index].cv;
134 609115 : PR_ASSERT(NULL != cv);
135 609114 : PR_ASSERT(0 != notified->cv[index].times);
136 609114 : if (-1 == notified->cv[index].times)
137 : {
138 497062 : rv = pthread_cond_broadcast(&cv->cv);
139 497064 : PR_ASSERT(0 == rv);
140 : }
141 : else
142 : {
143 336156 : while (notified->cv[index].times-- > 0)
144 : {
145 112052 : rv = pthread_cond_signal(&cv->cv);
146 112052 : PR_ASSERT(0 == rv);
147 : }
148 : }
149 : #if defined(DEBUG)
150 609115 : pt_debug.cvars_notified += 1;
151 609115 : if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
152 : {
153 472 : pt_debug.delayed_cv_deletes += 1;
154 472 : PR_DestroyCondVar(cv);
155 : }
156 : #else /* defined(DEBUG) */
157 : if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending))
158 : PR_DestroyCondVar(cv);
159 : #endif /* defined(DEBUG) */
160 : }
161 609116 : prev = notified;
162 609116 : notified = notified->link;
163 609116 : if (&post != prev) PR_DELETE(prev);
164 609116 : } while (NULL != notified);
165 609115 : } /* pt_PostNotifies */
166 :
167 958182 : PR_IMPLEMENT(PRLock*) PR_NewLock(void)
168 : {
169 : PRIntn rv;
170 : PRLock *lock;
171 :
172 958182 : if (!_pr_initialized) _PR_ImplicitInitialization();
173 :
174 958182 : lock = PR_NEWZAP(PRLock);
175 958182 : if (lock != NULL)
176 : {
177 958182 : rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr);
178 958182 : PR_ASSERT(0 == rv);
179 : }
180 : #if defined(DEBUG)
181 958182 : pt_debug.locks_created += 1;
182 : #endif
183 958182 : return lock;
184 : } /* PR_NewLock */
185 :
186 613801 : PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock)
187 : {
188 : PRIntn rv;
189 613801 : PR_ASSERT(NULL != lock);
190 613801 : PR_ASSERT(PR_FALSE == lock->locked);
191 613801 : PR_ASSERT(0 == lock->notified.length);
192 613801 : PR_ASSERT(NULL == lock->notified.link);
193 613801 : rv = pthread_mutex_destroy(&lock->mutex);
194 613801 : PR_ASSERT(0 == rv);
195 : #if defined(DEBUG)
196 613801 : memset(lock, 0xaf, sizeof(PRLock));
197 613801 : pt_debug.locks_destroyed += 1;
198 : #endif
199 613801 : PR_Free(lock);
200 613801 : } /* PR_DestroyLock */
201 :
202 277847110 : PR_IMPLEMENT(void) PR_Lock(PRLock *lock)
203 : {
204 : PRIntn rv;
205 277847110 : PR_ASSERT(lock != NULL);
206 277847110 : rv = pthread_mutex_lock(&lock->mutex);
207 277868845 : PR_ASSERT(0 == rv);
208 277868334 : PR_ASSERT(0 == lock->notified.length);
209 277868334 : PR_ASSERT(NULL == lock->notified.link);
210 277868334 : PR_ASSERT(PR_FALSE == lock->locked);
211 : /* Nb: the order of the next two statements is not critical to
212 : * the correctness of PR_AssertCurrentThreadOwnsLock(), but
213 : * this particular order makes the assertion more likely to
214 : * catch errors. */
215 277868334 : lock->owner = pthread_self();
216 277869580 : lock->locked = PR_TRUE;
217 : #if defined(DEBUG)
218 277869580 : pt_debug.locks_acquired += 1;
219 : #endif
220 277869580 : } /* PR_Lock */
221 :
222 277869646 : PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
223 : {
224 : PRIntn rv;
225 :
226 277869646 : PR_ASSERT(lock != NULL);
227 277869646 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex));
228 277871731 : PR_ASSERT(PR_TRUE == lock->locked);
229 277871731 : PR_ASSERT(pthread_equal(lock->owner, pthread_self()));
230 :
231 277869320 : if (!lock->locked || !pthread_equal(lock->owner, pthread_self()))
232 0 : return PR_FAILURE;
233 :
234 277868281 : lock->locked = PR_FALSE;
235 277868281 : if (0 == lock->notified.length) /* shortcut */
236 : {
237 277293189 : rv = pthread_mutex_unlock(&lock->mutex);
238 277288671 : PR_ASSERT(0 == rv);
239 : }
240 575092 : else pt_PostNotifies(lock, PR_TRUE);
241 :
242 : #if defined(DEBUG)
243 277855024 : pt_debug.locks_released += 1;
244 : #endif
245 277855024 : return PR_SUCCESS;
246 : } /* PR_Unlock */
247 :
248 5146869 : PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock)
249 : {
250 : /* Nb: the order of the |locked| and |owner==me| checks is not critical
251 : * to the correctness of PR_AssertCurrentThreadOwnsLock(), but
252 : * this particular order makes the assertion more likely to
253 : * catch errors. */
254 5146869 : PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self()));
255 5146865 : }
256 :
257 : /**************************************************************/
258 : /**************************************************************/
259 : /***************************CONDITIONS*************************/
260 : /**************************************************************/
261 : /**************************************************************/
262 :
263 :
264 : /*
265 : * This code is used to compute the absolute time for the wakeup.
266 : * It's moderately ugly, so it's defined here and called in a
267 : * couple of places.
268 : */
269 : #define PT_NANOPERMICRO 1000UL
270 : #define PT_BILLION 1000000000UL
271 :
272 35604 : static PRIntn pt_TimedWait(
273 : pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout)
274 : {
275 : int rv;
276 : struct timeval now;
277 : struct timespec tmo;
278 35604 : PRUint32 ticks = PR_TicksPerSecond();
279 :
280 35604 : tmo.tv_sec = (PRInt32)(timeout / ticks);
281 35604 : tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks));
282 35604 : tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec);
283 :
284 : /* pthreads wants this in absolute time, off we go ... */
285 35604 : (void)GETTIMEOFDAY(&now);
286 : /* that one's usecs, this one's nsecs - grrrr! */
287 35604 : tmo.tv_sec += now.tv_sec;
288 35604 : tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
289 35604 : tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
290 35604 : tmo.tv_nsec %= PT_BILLION;
291 :
292 35604 : rv = pthread_cond_timedwait(cv, ml, &tmo);
293 :
294 : /* NSPR doesn't report timeouts */
295 : #ifdef _PR_DCETHREADS
296 : if (rv == -1) return (errno == EAGAIN) ? 0 : errno;
297 : else return rv;
298 : #else
299 35603 : return (rv == ETIMEDOUT) ? 0 : rv;
300 : #endif
301 : } /* pt_TimedWait */
302 :
303 :
304 : /*
305 : * Notifies just get posted to the protecting mutex. The
306 : * actual notification is done when the lock is released so that
307 : * MP systems don't contend for a lock that they can't have.
308 : */
309 609115 : static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast)
310 : {
311 609115 : PRIntn index = 0;
312 609115 : _PT_Notified *notified = &cvar->lock->notified;
313 :
314 609115 : PR_ASSERT(PR_TRUE == cvar->lock->locked);
315 609115 : PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
316 609115 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
317 :
318 : while (1)
319 : {
320 609116 : for (index = 0; index < notified->length; ++index)
321 : {
322 0 : if (notified->cv[index].cv == cvar)
323 : {
324 0 : if (broadcast)
325 0 : notified->cv[index].times = -1;
326 0 : else if (-1 != notified->cv[index].times)
327 0 : notified->cv[index].times += 1;
328 0 : goto finished; /* we're finished */
329 : }
330 : }
331 : /* if not full, enter new CV in this array */
332 609116 : if (notified->length < PT_CV_NOTIFIED_LENGTH) break;
333 :
334 : /* if there's no link, create an empty array and link it */
335 0 : if (NULL == notified->link)
336 0 : notified->link = PR_NEWZAP(_PT_Notified);
337 0 : notified = notified->link;
338 0 : }
339 :
340 : /* A brand new entry in the array */
341 609116 : (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending);
342 1106180 : notified->cv[index].times = (broadcast) ? -1 : 1;
343 609116 : notified->cv[index].cv = cvar;
344 609116 : notified->length += 1;
345 :
346 : finished:
347 609116 : PR_ASSERT(PR_TRUE == cvar->lock->locked);
348 609116 : PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
349 609116 : } /* pt_PostNotifyToCvar */
350 :
351 157745 : PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock)
352 : {
353 157745 : PRCondVar *cv = PR_NEW(PRCondVar);
354 157745 : PR_ASSERT(lock != NULL);
355 157745 : if (cv != NULL)
356 : {
357 157745 : int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr);
358 157745 : PR_ASSERT(0 == rv);
359 157745 : cv->lock = lock;
360 157745 : cv->notify_pending = 0;
361 : #if defined(DEBUG)
362 157745 : pt_debug.cvars_created += 1;
363 : #endif
364 : }
365 157745 : return cv;
366 : } /* PR_NewCondVar */
367 :
368 145644 : PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
369 : {
370 145644 : if (0 > PR_ATOMIC_DECREMENT(&cvar->notify_pending))
371 : {
372 145172 : PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
373 : #if defined(DEBUG)
374 145172 : memset(cvar, 0xaf, sizeof(PRCondVar));
375 145172 : pt_debug.cvars_destroyed += 1;
376 : #endif
377 145172 : PR_Free(cvar);
378 : }
379 145644 : } /* PR_DestroyCondVar */
380 :
381 184232 : PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
382 : {
383 : PRIntn rv;
384 184232 : PRThread *thred = PR_GetCurrentThread();
385 :
386 184232 : PR_ASSERT(cvar != NULL);
387 : /* We'd better be locked */
388 184232 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
389 184232 : PR_ASSERT(PR_TRUE == cvar->lock->locked);
390 : /* and it better be by us */
391 184232 : PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
392 :
393 184232 : if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
394 :
395 : /*
396 : * The thread waiting is used for PR_Interrupt
397 : */
398 184232 : thred->waiting = cvar; /* this is where we're waiting */
399 :
400 : /*
401 : * If we have pending notifies, post them now.
402 : *
403 : * This is not optimal. We're going to post these notifies
404 : * while we're holding the lock. That means on MP systems
405 : * that they are going to collide for the lock that we will
406 : * hold until we actually wait.
407 : */
408 184232 : if (0 != cvar->lock->notified.length)
409 34024 : pt_PostNotifies(cvar->lock, PR_FALSE);
410 :
411 : /*
412 : * We're surrendering the lock, so clear out the locked field.
413 : */
414 184232 : cvar->lock->locked = PR_FALSE;
415 :
416 184232 : if (timeout == PR_INTERVAL_NO_TIMEOUT)
417 148628 : rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex);
418 : else
419 35604 : rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
420 :
421 : /* We just got the lock back - this better be empty */
422 184230 : PR_ASSERT(PR_FALSE == cvar->lock->locked);
423 184230 : cvar->lock->locked = PR_TRUE;
424 184230 : cvar->lock->owner = pthread_self();
425 :
426 184230 : PR_ASSERT(0 == cvar->lock->notified.length);
427 184230 : thred->waiting = NULL; /* and now we're not */
428 184230 : if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
429 184230 : if (rv != 0)
430 : {
431 0 : _PR_MD_MAP_DEFAULT_ERROR(rv);
432 0 : return PR_FAILURE;
433 : }
434 184230 : return PR_SUCCESS;
435 :
436 : aborted:
437 0 : PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
438 0 : thred->state &= ~PT_THREAD_ABORTED;
439 0 : return PR_FAILURE;
440 : } /* PR_WaitCondVar */
441 :
442 105257 : PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
443 : {
444 105257 : PR_ASSERT(cvar != NULL);
445 105257 : pt_PostNotifyToCvar(cvar, PR_FALSE);
446 105257 : return PR_SUCCESS;
447 : } /* PR_NotifyCondVar */
448 :
449 180654 : PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
450 : {
451 180654 : PR_ASSERT(cvar != NULL);
452 180654 : pt_PostNotifyToCvar(cvar, PR_TRUE);
453 180654 : return PR_SUCCESS;
454 : } /* PR_NotifyAllCondVar */
455 :
456 : /**************************************************************/
457 : /**************************************************************/
458 : /***************************MONITORS***************************/
459 : /**************************************************************/
460 : /**************************************************************/
461 :
462 246615 : PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
463 : {
464 : PRMonitor *mon;
465 : PRCondVar *cvar;
466 : int rv;
467 :
468 246615 : if (!_pr_initialized) _PR_ImplicitInitialization();
469 :
470 246615 : cvar = PR_NEWZAP(PRCondVar);
471 246615 : if (NULL == cvar)
472 : {
473 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
474 0 : return NULL;
475 : }
476 246615 : mon = PR_NEWZAP(PRMonitor);
477 246615 : if (mon == NULL)
478 : {
479 0 : PR_Free(cvar);
480 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
481 0 : return NULL;
482 : }
483 :
484 246615 : rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr);
485 246615 : PR_ASSERT(0 == rv);
486 246615 : if (0 != rv)
487 : {
488 0 : PR_Free(mon);
489 0 : PR_Free(cvar);
490 0 : PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
491 0 : return NULL;
492 : }
493 :
494 246615 : _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
495 :
496 246615 : mon->cvar = cvar;
497 246615 : rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr);
498 246615 : PR_ASSERT(0 == rv);
499 246615 : mon->entryCount = 0;
500 246615 : mon->cvar->lock = &mon->lock;
501 246615 : if (0 != rv)
502 : {
503 0 : pthread_mutex_destroy(&mon->lock.mutex);
504 0 : PR_Free(mon);
505 0 : PR_Free(cvar);
506 0 : PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
507 0 : return NULL;
508 : }
509 246615 : return mon;
510 : } /* PR_NewMonitor */
511 :
512 20034 : PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
513 : {
514 20034 : PRMonitor* mon = PR_NewMonitor();
515 20034 : if (mon)
516 20034 : mon->name = name;
517 20034 : return mon;
518 : }
519 :
520 47605 : PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
521 : {
522 : int rv;
523 47605 : PR_ASSERT(mon != NULL);
524 47605 : PR_DestroyCondVar(mon->cvar);
525 47605 : rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv);
526 : #if defined(DEBUG)
527 47605 : memset(mon, 0xaf, sizeof(PRMonitor));
528 : #endif
529 47605 : PR_Free(mon);
530 47605 : } /* PR_DestroyMonitor */
531 :
532 :
533 : /* The GC uses this; it is quite arguably a bad interface. I'm just
534 : * duplicating it for now - XXXMB
535 : */
536 1960 : PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
537 : {
538 1960 : pthread_t self = pthread_self();
539 1960 : if (pthread_equal(mon->owner, self))
540 1100 : return mon->entryCount;
541 860 : return 0;
542 : }
543 :
544 5062676 : PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
545 : {
546 5062676 : PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(&mon->lock);
547 5062676 : }
548 :
549 21827741 : PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
550 : {
551 21827741 : pthread_t self = pthread_self();
552 :
553 21827741 : PR_ASSERT(mon != NULL);
554 : /*
555 : * This is safe only if mon->owner (a pthread_t) can be
556 : * read in one instruction. Perhaps mon->owner should be
557 : * a "PRThread *"?
558 : */
559 21827741 : if (!pthread_equal(mon->owner, self))
560 : {
561 21378799 : PR_Lock(&mon->lock);
562 : /* and now I have the lock */
563 21378824 : PR_ASSERT(0 == mon->entryCount);
564 21378824 : PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
565 21378824 : _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
566 : }
567 21827739 : mon->entryCount += 1;
568 21827739 : } /* PR_EnterMonitor */
569 :
570 21827498 : PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
571 : {
572 21827498 : pthread_t self = pthread_self();
573 :
574 21827506 : PR_ASSERT(mon != NULL);
575 : /* The lock better be that - locked */
576 21827506 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
577 : /* we'd better be the owner */
578 21827651 : PR_ASSERT(pthread_equal(mon->owner, self));
579 21827634 : if (!pthread_equal(mon->owner, self))
580 0 : return PR_FAILURE;
581 :
582 : /* if it's locked and we have it, then the entries should be > 0 */
583 21827616 : PR_ASSERT(mon->entryCount > 0);
584 21827540 : mon->entryCount -= 1; /* reduce by one */
585 21827540 : if (mon->entryCount == 0)
586 : {
587 : /* and if it transitioned to zero - unlock */
588 21378622 : _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknown */
589 21378622 : PR_Unlock(&mon->lock);
590 : }
591 21827528 : return PR_SUCCESS;
592 : } /* PR_ExitMonitor */
593 :
594 68038 : PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
595 : {
596 : PRStatus rv;
597 : PRInt16 saved_entries;
598 : pthread_t saved_owner;
599 :
600 68038 : PR_ASSERT(mon != NULL);
601 : /* we'd better be locked */
602 68038 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
603 : /* and the entries better be positive */
604 68038 : PR_ASSERT(mon->entryCount > 0);
605 : /* and it better be by us */
606 68038 : PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
607 :
608 : /* tuck these away 'till later */
609 68038 : saved_entries = mon->entryCount;
610 68038 : mon->entryCount = 0;
611 68038 : _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
612 68038 : _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
613 :
614 68038 : rv = PR_WaitCondVar(mon->cvar, timeout);
615 :
616 : /* reinstate the intresting information */
617 68038 : mon->entryCount = saved_entries;
618 68038 : _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
619 :
620 68038 : return rv;
621 : } /* PR_Wait */
622 :
623 6795 : PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
624 : {
625 6795 : PR_ASSERT(NULL != mon);
626 : /* we'd better be locked */
627 6795 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
628 : /* and the entries better be positive */
629 6795 : PR_ASSERT(mon->entryCount > 0);
630 : /* and it better be by us */
631 6795 : PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
632 :
633 6795 : pt_PostNotifyToCvar(mon->cvar, PR_FALSE);
634 :
635 6795 : return PR_SUCCESS;
636 : } /* PR_Notify */
637 :
638 316410 : PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
639 : {
640 316410 : PR_ASSERT(mon != NULL);
641 : /* we'd better be locked */
642 316410 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
643 : /* and the entries better be positive */
644 316410 : PR_ASSERT(mon->entryCount > 0);
645 : /* and it better be by us */
646 316410 : PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
647 :
648 316410 : pt_PostNotifyToCvar(mon->cvar, PR_TRUE);
649 :
650 316409 : return PR_SUCCESS;
651 : } /* PR_NotifyAll */
652 :
653 : /**************************************************************/
654 : /**************************************************************/
655 : /**************************SEMAPHORES**************************/
656 : /**************************************************************/
657 : /**************************************************************/
658 0 : PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore)
659 : {
660 : static PRBool unwarned = PR_TRUE;
661 0 : if (unwarned) unwarned = _PR_Obsolete(
662 : "PR_PostSem", "locks & condition variables");
663 0 : PR_Lock(semaphore->cvar->lock);
664 0 : PR_NotifyCondVar(semaphore->cvar);
665 0 : semaphore->count += 1;
666 0 : PR_Unlock(semaphore->cvar->lock);
667 0 : } /* PR_PostSem */
668 :
669 0 : PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore)
670 : {
671 0 : PRStatus status = PR_SUCCESS;
672 : static PRBool unwarned = PR_TRUE;
673 0 : if (unwarned) unwarned = _PR_Obsolete(
674 : "PR_WaitSem", "locks & condition variables");
675 0 : PR_Lock(semaphore->cvar->lock);
676 0 : while ((semaphore->count == 0) && (PR_SUCCESS == status))
677 0 : status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT);
678 0 : if (PR_SUCCESS == status) semaphore->count -= 1;
679 0 : PR_Unlock(semaphore->cvar->lock);
680 0 : return status;
681 : } /* PR_WaitSem */
682 :
683 0 : PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore)
684 : {
685 : static PRBool unwarned = PR_TRUE;
686 0 : if (unwarned) unwarned = _PR_Obsolete(
687 : "PR_DestroySem", "locks & condition variables");
688 0 : PR_DestroyLock(semaphore->cvar->lock);
689 0 : PR_DestroyCondVar(semaphore->cvar);
690 0 : PR_Free(semaphore);
691 0 : } /* PR_DestroySem */
692 :
693 0 : PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
694 : {
695 : PRSemaphore *semaphore;
696 : static PRBool unwarned = PR_TRUE;
697 0 : if (!_pr_initialized) _PR_ImplicitInitialization();
698 :
699 0 : if (unwarned) unwarned = _PR_Obsolete(
700 : "PR_NewSem", "locks & condition variables");
701 :
702 0 : semaphore = PR_NEWZAP(PRSemaphore);
703 0 : if (NULL != semaphore)
704 : {
705 0 : PRLock *lock = PR_NewLock();
706 0 : if (NULL != lock)
707 : {
708 0 : semaphore->cvar = PR_NewCondVar(lock);
709 0 : if (NULL != semaphore->cvar)
710 : {
711 0 : semaphore->count = value;
712 0 : return semaphore;
713 : }
714 0 : PR_DestroyLock(lock);
715 : }
716 0 : PR_Free(semaphore);
717 : }
718 0 : return NULL;
719 : }
720 :
721 : /*
722 : * Define the interprocess named semaphore functions.
723 : * There are three implementations:
724 : * 1. POSIX semaphore based;
725 : * 2. System V semaphore based;
726 : * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR).
727 : */
728 :
729 : #ifdef _PR_HAVE_POSIX_SEMAPHORES
730 : #include <fcntl.h>
731 :
732 : PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
733 : const char *name,
734 : PRIntn flags,
735 : PRIntn mode,
736 : PRUintn value)
737 : {
738 : PRSem *sem;
739 : char osname[PR_IPC_NAME_SIZE];
740 :
741 : if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
742 : == PR_FAILURE)
743 : {
744 : return NULL;
745 : }
746 :
747 : sem = PR_NEW(PRSem);
748 : if (NULL == sem)
749 : {
750 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
751 : return NULL;
752 : }
753 :
754 : if (flags & PR_SEM_CREATE)
755 : {
756 : int oflag = O_CREAT;
757 :
758 : if (flags & PR_SEM_EXCL) oflag |= O_EXCL;
759 : sem->sem = sem_open(osname, oflag, mode, value);
760 : }
761 : else
762 : {
763 : #ifdef HPUX
764 : /* Pass 0 as the mode and value arguments to work around a bug. */
765 : sem->sem = sem_open(osname, 0, 0, 0);
766 : #else
767 : sem->sem = sem_open(osname, 0);
768 : #endif
769 : }
770 : if ((sem_t *) -1 == sem->sem)
771 : {
772 : _PR_MD_MAP_DEFAULT_ERROR(errno);
773 : PR_Free(sem);
774 : return NULL;
775 : }
776 : return sem;
777 : }
778 :
779 : PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
780 : {
781 : int rv;
782 : rv = sem_wait(sem->sem);
783 : if (0 != rv)
784 : {
785 : _PR_MD_MAP_DEFAULT_ERROR(errno);
786 : return PR_FAILURE;
787 : }
788 : return PR_SUCCESS;
789 : }
790 :
791 : PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
792 : {
793 : int rv;
794 : rv = sem_post(sem->sem);
795 : if (0 != rv)
796 : {
797 : _PR_MD_MAP_DEFAULT_ERROR(errno);
798 : return PR_FAILURE;
799 : }
800 : return PR_SUCCESS;
801 : }
802 :
803 : PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
804 : {
805 : int rv;
806 : rv = sem_close(sem->sem);
807 : if (0 != rv)
808 : {
809 : _PR_MD_MAP_DEFAULT_ERROR(errno);
810 : return PR_FAILURE;
811 : }
812 : PR_Free(sem);
813 : return PR_SUCCESS;
814 : }
815 :
816 : PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
817 : {
818 : int rv;
819 : char osname[PR_IPC_NAME_SIZE];
820 :
821 : if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
822 : == PR_FAILURE)
823 : {
824 : return PR_FAILURE;
825 : }
826 : rv = sem_unlink(osname);
827 : if (0 != rv)
828 : {
829 : _PR_MD_MAP_DEFAULT_ERROR(errno);
830 : return PR_FAILURE;
831 : }
832 : return PR_SUCCESS;
833 : }
834 :
835 : #elif defined(_PR_HAVE_SYSV_SEMAPHORES)
836 :
837 : #include <fcntl.h>
838 : #include <sys/sem.h>
839 :
840 : /*
841 : * From the semctl(2) man page in glibc 2.0
842 : */
843 : #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \
844 : || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \
845 : || defined(DARWIN) || defined(SYMBIAN)
846 : /* union semun is defined by including <sys/sem.h> */
847 : #else
848 : /* according to X/OPEN we have to define it ourselves */
849 : union semun {
850 : int val;
851 : struct semid_ds *buf;
852 : unsigned short *array;
853 : };
854 : #endif
855 :
856 : /*
857 : * 'a' (97) is the final closing price of NSCP stock.
858 : */
859 : #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */
860 :
861 : #define NSPR_SEM_MODE 0666
862 :
863 0 : PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
864 : const char *name,
865 : PRIntn flags,
866 : PRIntn mode,
867 : PRUintn value)
868 : {
869 : PRSem *sem;
870 : key_t key;
871 : union semun arg;
872 : struct sembuf sop;
873 : struct semid_ds seminfo;
874 : #define MAX_TRIES 60
875 : PRIntn i;
876 : char osname[PR_IPC_NAME_SIZE];
877 :
878 0 : if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
879 : == PR_FAILURE)
880 : {
881 0 : return NULL;
882 : }
883 :
884 : /* Make sure the file exists before calling ftok. */
885 0 : if (flags & PR_SEM_CREATE)
886 : {
887 0 : int osfd = open(osname, O_RDWR|O_CREAT, mode);
888 0 : if (-1 == osfd)
889 : {
890 0 : _PR_MD_MAP_OPEN_ERROR(errno);
891 0 : return NULL;
892 : }
893 0 : if (close(osfd) == -1)
894 : {
895 0 : _PR_MD_MAP_CLOSE_ERROR(errno);
896 0 : return NULL;
897 : }
898 : }
899 0 : key = ftok(osname, NSPR_IPC_KEY_ID);
900 0 : if ((key_t)-1 == key)
901 : {
902 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
903 0 : return NULL;
904 : }
905 :
906 0 : sem = PR_NEW(PRSem);
907 0 : if (NULL == sem)
908 : {
909 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
910 0 : return NULL;
911 : }
912 :
913 0 : if (flags & PR_SEM_CREATE)
914 : {
915 0 : sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL);
916 0 : if (sem->semid >= 0)
917 : {
918 : /* creator of a semaphore is responsible for initializing it */
919 0 : arg.val = 0;
920 0 : if (semctl(sem->semid, 0, SETVAL, arg) == -1)
921 : {
922 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
923 0 : PR_Free(sem);
924 0 : return NULL;
925 : }
926 : /* call semop to set sem_otime to nonzero */
927 0 : sop.sem_num = 0;
928 0 : sop.sem_op = value;
929 0 : sop.sem_flg = 0;
930 0 : if (semop(sem->semid, &sop, 1) == -1)
931 : {
932 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
933 0 : PR_Free(sem);
934 0 : return NULL;
935 : }
936 0 : return sem;
937 : }
938 :
939 0 : if (errno != EEXIST || flags & PR_SEM_EXCL)
940 : {
941 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
942 0 : PR_Free(sem);
943 0 : return NULL;
944 : }
945 : }
946 :
947 0 : sem->semid = semget(key, 1, NSPR_SEM_MODE);
948 0 : if (sem->semid == -1)
949 : {
950 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
951 0 : PR_Free(sem);
952 0 : return NULL;
953 : }
954 0 : for (i = 0; i < MAX_TRIES; i++)
955 : {
956 0 : arg.buf = &seminfo;
957 0 : semctl(sem->semid, 0, IPC_STAT, arg);
958 0 : if (seminfo.sem_otime != 0) break;
959 0 : sleep(1);
960 : }
961 0 : if (i == MAX_TRIES)
962 : {
963 0 : PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
964 0 : PR_Free(sem);
965 0 : return NULL;
966 : }
967 0 : return sem;
968 : }
969 :
970 0 : PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
971 : {
972 : struct sembuf sop;
973 :
974 0 : sop.sem_num = 0;
975 0 : sop.sem_op = -1;
976 0 : sop.sem_flg = 0;
977 0 : if (semop(sem->semid, &sop, 1) == -1)
978 : {
979 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
980 0 : return PR_FAILURE;
981 : }
982 0 : return PR_SUCCESS;
983 : }
984 :
985 0 : PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
986 : {
987 : struct sembuf sop;
988 :
989 0 : sop.sem_num = 0;
990 0 : sop.sem_op = 1;
991 0 : sop.sem_flg = 0;
992 0 : if (semop(sem->semid, &sop, 1) == -1)
993 : {
994 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
995 0 : return PR_FAILURE;
996 : }
997 0 : return PR_SUCCESS;
998 : }
999 :
1000 0 : PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1001 : {
1002 0 : PR_Free(sem);
1003 0 : return PR_SUCCESS;
1004 : }
1005 :
1006 0 : PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
1007 : {
1008 : key_t key;
1009 : int semid;
1010 : /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
1011 : union semun unused;
1012 : char osname[PR_IPC_NAME_SIZE];
1013 :
1014 0 : if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
1015 : == PR_FAILURE)
1016 : {
1017 0 : return PR_FAILURE;
1018 : }
1019 0 : key = ftok(osname, NSPR_IPC_KEY_ID);
1020 0 : if ((key_t) -1 == key)
1021 : {
1022 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
1023 0 : return PR_FAILURE;
1024 : }
1025 0 : if (unlink(osname) == -1)
1026 : {
1027 0 : _PR_MD_MAP_UNLINK_ERROR(errno);
1028 0 : return PR_FAILURE;
1029 : }
1030 0 : semid = semget(key, 1, NSPR_SEM_MODE);
1031 0 : if (-1 == semid)
1032 : {
1033 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
1034 0 : return PR_FAILURE;
1035 : }
1036 0 : unused.val = 0;
1037 0 : if (semctl(semid, 0, IPC_RMID, unused) == -1)
1038 : {
1039 0 : _PR_MD_MAP_DEFAULT_ERROR(errno);
1040 0 : return PR_FAILURE;
1041 : }
1042 0 : return PR_SUCCESS;
1043 : }
1044 :
1045 : #else /* neither POSIX nor System V semaphores are available */
1046 :
1047 : PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
1048 : const char *name,
1049 : PRIntn flags,
1050 : PRIntn mode,
1051 : PRUintn value)
1052 : {
1053 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1054 : return NULL;
1055 : }
1056 :
1057 : PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
1058 : {
1059 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1060 : return PR_FAILURE;
1061 : }
1062 :
1063 : PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
1064 : {
1065 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1066 : return PR_FAILURE;
1067 : }
1068 :
1069 : PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1070 : {
1071 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1072 : return PR_FAILURE;
1073 : }
1074 :
1075 : PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
1076 : {
1077 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1078 : return PR_FAILURE;
1079 : }
1080 :
1081 : #endif /* end of interprocess named semaphore functions */
1082 :
1083 : /**************************************************************/
1084 : /**************************************************************/
1085 : /******************ROUTINES FOR DCE EMULATION******************/
1086 : /**************************************************************/
1087 : /**************************************************************/
1088 :
1089 : #include "prpdce.h"
1090 :
1091 0 : PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
1092 : {
1093 0 : PRIntn rv = pthread_mutex_trylock(&lock->mutex);
1094 0 : if (rv == PT_TRYLOCK_SUCCESS)
1095 : {
1096 0 : PR_ASSERT(PR_FALSE == lock->locked);
1097 0 : lock->locked = PR_TRUE;
1098 0 : lock->owner = pthread_self();
1099 : }
1100 : /* XXX set error code? */
1101 0 : return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
1102 : } /* PRP_TryLock */
1103 :
1104 0 : PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
1105 : {
1106 : PRCondVar *cv;
1107 :
1108 0 : if (!_pr_initialized) _PR_ImplicitInitialization();
1109 :
1110 0 : cv = PR_NEW(PRCondVar);
1111 0 : if (cv != NULL)
1112 : {
1113 : int rv;
1114 0 : rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr);
1115 0 : PR_ASSERT(0 == rv);
1116 0 : cv->lock = _PR_NAKED_CV_LOCK;
1117 : }
1118 0 : return cv;
1119 : } /* PRP_NewNakedCondVar */
1120 :
1121 0 : PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
1122 : {
1123 : int rv;
1124 0 : rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
1125 : #if defined(DEBUG)
1126 0 : memset(cvar, 0xaf, sizeof(PRCondVar));
1127 : #endif
1128 0 : PR_Free(cvar);
1129 0 : } /* PRP_DestroyNakedCondVar */
1130 :
1131 0 : PR_IMPLEMENT(PRStatus) PRP_NakedWait(
1132 : PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout)
1133 : {
1134 : PRIntn rv;
1135 0 : PR_ASSERT(cvar != NULL);
1136 : /* XXX do we really want to assert this in a naked wait? */
1137 0 : PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex));
1138 0 : if (timeout == PR_INTERVAL_NO_TIMEOUT)
1139 0 : rv = pthread_cond_wait(&cvar->cv, &ml->mutex);
1140 : else
1141 0 : rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout);
1142 0 : if (rv != 0)
1143 : {
1144 0 : _PR_MD_MAP_DEFAULT_ERROR(rv);
1145 0 : return PR_FAILURE;
1146 : }
1147 0 : return PR_SUCCESS;
1148 : } /* PRP_NakedWait */
1149 :
1150 0 : PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
1151 : {
1152 : int rv;
1153 0 : PR_ASSERT(cvar != NULL);
1154 0 : rv = pthread_cond_signal(&cvar->cv);
1155 0 : PR_ASSERT(0 == rv);
1156 0 : return PR_SUCCESS;
1157 : } /* PRP_NakedNotify */
1158 :
1159 0 : PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
1160 : {
1161 : int rv;
1162 0 : PR_ASSERT(cvar != NULL);
1163 0 : rv = pthread_cond_broadcast(&cvar->cv);
1164 0 : PR_ASSERT(0 == rv);
1165 0 : return PR_SUCCESS;
1166 : } /* PRP_NakedBroadcast */
1167 :
1168 : #endif /* defined(_PR_PTHREADS) */
1169 :
1170 : /* ptsynch.c */
|