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