comparison nspr/pr/src/pthreads/ptsynch.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 ** 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
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
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
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
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
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
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
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
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
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 */
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
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 cv->lock = lock;
328 cv->notify_pending = 0;
329 #if defined(DEBUG)
330 pt_debug.cvars_created += 1;
331 #endif
332 }
333 return cv;
334 } /* PR_NewCondVar */
335
336 PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar)
337 {
338 if (0 > PR_ATOMIC_DECREMENT(&cvar->notify_pending))
339 {
340 PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
341 #if defined(DEBUG)
342 memset(cvar, 0xaf, sizeof(PRCondVar));
343 pt_debug.cvars_destroyed += 1;
344 #endif
345 PR_Free(cvar);
346 }
347 } /* PR_DestroyCondVar */
348
349 PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout)
350 {
351 PRIntn rv;
352 PRThread *thred = PR_GetCurrentThread();
353
354 PR_ASSERT(cvar != NULL);
355 /* We'd better be locked */
356 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
357 PR_ASSERT(PR_TRUE == cvar->lock->locked);
358 /* and it better be by us */
359 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
360
361 if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
362
363 /*
364 * The thread waiting is used for PR_Interrupt
365 */
366 thred->waiting = cvar; /* this is where we're waiting */
367
368 /*
369 * If we have pending notifies, post them now.
370 *
371 * This is not optimal. We're going to post these notifies
372 * while we're holding the lock. That means on MP systems
373 * that they are going to collide for the lock that we will
374 * hold until we actually wait.
375 */
376 if (0 != cvar->lock->notified.length)
377 pt_PostNotifies(cvar->lock, PR_FALSE);
378
379 /*
380 * We're surrendering the lock, so clear out the locked field.
381 */
382 cvar->lock->locked = PR_FALSE;
383
384 if (timeout == PR_INTERVAL_NO_TIMEOUT)
385 rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex);
386 else
387 rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout);
388
389 /* We just got the lock back - this better be empty */
390 PR_ASSERT(PR_FALSE == cvar->lock->locked);
391 cvar->lock->locked = PR_TRUE;
392 cvar->lock->owner = pthread_self();
393
394 PR_ASSERT(0 == cvar->lock->notified.length);
395 thred->waiting = NULL; /* and now we're not */
396 if (_PT_THREAD_INTERRUPTED(thred)) goto aborted;
397 if (rv != 0)
398 {
399 _PR_MD_MAP_DEFAULT_ERROR(rv);
400 return PR_FAILURE;
401 }
402 return PR_SUCCESS;
403
404 aborted:
405 PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0);
406 thred->state &= ~PT_THREAD_ABORTED;
407 return PR_FAILURE;
408 } /* PR_WaitCondVar */
409
410 PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar)
411 {
412 PR_ASSERT(cvar != NULL);
413 pt_PostNotifyToCvar(cvar, PR_FALSE);
414 return PR_SUCCESS;
415 } /* PR_NotifyCondVar */
416
417 PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar)
418 {
419 PR_ASSERT(cvar != NULL);
420 pt_PostNotifyToCvar(cvar, PR_TRUE);
421 return PR_SUCCESS;
422 } /* PR_NotifyAllCondVar */
423
424 /**************************************************************/
425 /**************************************************************/
426 /***************************MONITORS***************************/
427 /**************************************************************/
428 /**************************************************************/
429
430 /*
431 * Notifies just get posted to the monitor. The actual notification is done
432 * when the monitor is fully exited so that MP systems don't contend for a
433 * monitor that they can't enter.
434 */
435 static void pt_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast)
436 {
437 PR_ASSERT(NULL != mon);
438 PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mon);
439
440 /* mon->notifyTimes is protected by the monitor, so we don't need to
441 * acquire mon->lock.
442 */
443 if (broadcast)
444 mon->notifyTimes = -1;
445 else if (-1 != mon->notifyTimes)
446 mon->notifyTimes += 1;
447 } /* pt_PostNotifyToMonitor */
448
449 static void pt_PostNotifiesFromMonitor(pthread_cond_t *cv, PRIntn times)
450 {
451 PRIntn rv;
452
453 /*
454 * Time to actually notify any waits that were affected while the monitor
455 * was entered.
456 */
457 PR_ASSERT(NULL != cv);
458 PR_ASSERT(0 != times);
459 if (-1 == times)
460 {
461 rv = pthread_cond_broadcast(cv);
462 PR_ASSERT(0 == rv);
463 }
464 else
465 {
466 while (times-- > 0)
467 {
468 rv = pthread_cond_signal(cv);
469 PR_ASSERT(0 == rv);
470 }
471 }
472 } /* pt_PostNotifiesFromMonitor */
473
474 PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
475 {
476 PRMonitor *mon;
477 int rv;
478
479 if (!_pr_initialized) _PR_ImplicitInitialization();
480
481 mon = PR_NEWZAP(PRMonitor);
482 if (mon == NULL)
483 {
484 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
485 return NULL;
486 }
487
488 rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr);
489 PR_ASSERT(0 == rv);
490 if (0 != rv)
491 goto error1;
492
493 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
494
495 rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr);
496 PR_ASSERT(0 == rv);
497 if (0 != rv)
498 goto error2;
499
500 rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr);
501 PR_ASSERT(0 == rv);
502 if (0 != rv)
503 goto error3;
504
505 mon->notifyTimes = 0;
506 mon->entryCount = 0;
507 mon->refCount = 1;
508 mon->name = NULL;
509 return mon;
510
511 error3:
512 pthread_cond_destroy(&mon->entryCV);
513 error2:
514 pthread_mutex_destroy(&mon->lock);
515 error1:
516 PR_Free(mon);
517 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
518 return NULL;
519 } /* PR_NewMonitor */
520
521 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
522 {
523 PRMonitor* mon = PR_NewMonitor();
524 if (mon)
525 mon->name = name;
526 return mon;
527 }
528
529 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
530 {
531 int rv;
532
533 PR_ASSERT(mon != NULL);
534 if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0)
535 {
536 rv = pthread_cond_destroy(&mon->waitCV); PR_ASSERT(0 == rv);
537 rv = pthread_cond_destroy(&mon->entryCV); PR_ASSERT(0 == rv);
538 rv = pthread_mutex_destroy(&mon->lock); PR_ASSERT(0 == rv);
539 #if defined(DEBUG)
540 memset(mon, 0xaf, sizeof(PRMonitor));
541 #endif
542 PR_Free(mon);
543 }
544 } /* PR_DestroyMonitor */
545
546 /* The GC uses this; it is quite arguably a bad interface. I'm just
547 * duplicating it for now - XXXMB
548 */
549 PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
550 {
551 pthread_t self = pthread_self();
552 PRIntn rv;
553 PRIntn count = 0;
554
555 rv = pthread_mutex_lock(&mon->lock);
556 PR_ASSERT(0 == rv);
557 if (pthread_equal(mon->owner, self))
558 count = mon->entryCount;
559 rv = pthread_mutex_unlock(&mon->lock);
560 PR_ASSERT(0 == rv);
561 return count;
562 }
563
564 PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
565 {
566 #if defined(DEBUG) || defined(FORCE_PR_ASSERT)
567 PRIntn rv;
568
569 rv = pthread_mutex_lock(&mon->lock);
570 PR_ASSERT(0 == rv);
571 PR_ASSERT(mon->entryCount != 0 &&
572 pthread_equal(mon->owner, pthread_self()));
573 rv = pthread_mutex_unlock(&mon->lock);
574 PR_ASSERT(0 == rv);
575 #endif
576 }
577
578 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
579 {
580 pthread_t self = pthread_self();
581 PRIntn rv;
582
583 PR_ASSERT(mon != NULL);
584 rv = pthread_mutex_lock(&mon->lock);
585 PR_ASSERT(0 == rv);
586 if (mon->entryCount != 0)
587 {
588 if (pthread_equal(mon->owner, self))
589 goto done;
590 while (mon->entryCount != 0)
591 {
592 rv = pthread_cond_wait(&mon->entryCV, &mon->lock);
593 PR_ASSERT(0 == rv);
594 }
595 }
596 /* and now I have the monitor */
597 PR_ASSERT(0 == mon->notifyTimes);
598 PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
599 _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
600
601 done:
602 mon->entryCount += 1;
603 rv = pthread_mutex_unlock(&mon->lock);
604 PR_ASSERT(0 == rv);
605 } /* PR_EnterMonitor */
606
607 PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
608 {
609 pthread_t self = pthread_self();
610 PRIntn rv;
611 PRBool notifyEntryWaiter = PR_FALSE;
612 PRIntn notifyTimes = 0;
613
614 PR_ASSERT(mon != NULL);
615 rv = pthread_mutex_lock(&mon->lock);
616 PR_ASSERT(0 == rv);
617 /* the entries should be > 0 and we'd better be the owner */
618 PR_ASSERT(mon->entryCount > 0);
619 PR_ASSERT(pthread_equal(mon->owner, self));
620 if (mon->entryCount == 0 || !pthread_equal(mon->owner, self))
621 {
622 rv = pthread_mutex_unlock(&mon->lock);
623 PR_ASSERT(0 == rv);
624 return PR_FAILURE;
625 }
626
627 mon->entryCount -= 1; /* reduce by one */
628 if (mon->entryCount == 0)
629 {
630 /* and if it transitioned to zero - notify an entry waiter */
631 /* make the owner unknown */
632 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
633 notifyEntryWaiter = PR_TRUE;
634 notifyTimes = mon->notifyTimes;
635 mon->notifyTimes = 0;
636 /* We will access the members of 'mon' after unlocking mon->lock.
637 * Add a reference. */
638 PR_ATOMIC_INCREMENT(&mon->refCount);
639 }
640 rv = pthread_mutex_unlock(&mon->lock);
641 PR_ASSERT(0 == rv);
642 if (notifyEntryWaiter)
643 {
644 if (notifyTimes)
645 pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes);
646 rv = pthread_cond_signal(&mon->entryCV);
647 PR_ASSERT(0 == rv);
648 /* We are done accessing the members of 'mon'. Release the
649 * reference. */
650 PR_DestroyMonitor(mon);
651 }
652 return PR_SUCCESS;
653 } /* PR_ExitMonitor */
654
655 PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
656 {
657 PRStatus rv;
658 PRUint32 saved_entries;
659 pthread_t saved_owner;
660
661 PR_ASSERT(mon != NULL);
662 rv = pthread_mutex_lock(&mon->lock);
663 PR_ASSERT(0 == rv);
664 /* the entries better be positive */
665 PR_ASSERT(mon->entryCount > 0);
666 /* and it better be owned by us */
667 PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
668
669 /* tuck these away 'till later */
670 saved_entries = mon->entryCount;
671 mon->entryCount = 0;
672 _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
673 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
674 /*
675 * If we have pending notifies, post them now.
676 *
677 * This is not optimal. We're going to post these notifies
678 * while we're holding the lock. That means on MP systems
679 * that they are going to collide for the lock that we will
680 * hold until we actually wait.
681 */
682 if (0 != mon->notifyTimes)
683 {
684 pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes);
685 mon->notifyTimes = 0;
686 }
687 rv = pthread_cond_signal(&mon->entryCV);
688 PR_ASSERT(0 == rv);
689
690 if (timeout == PR_INTERVAL_NO_TIMEOUT)
691 rv = pthread_cond_wait(&mon->waitCV, &mon->lock);
692 else
693 rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout);
694 PR_ASSERT(0 == rv);
695
696 while (mon->entryCount != 0)
697 {
698 rv = pthread_cond_wait(&mon->entryCV, &mon->lock);
699 PR_ASSERT(0 == rv);
700 }
701 PR_ASSERT(0 == mon->notifyTimes);
702 /* reinstate the interesting information */
703 mon->entryCount = saved_entries;
704 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
705
706 rv = pthread_mutex_unlock(&mon->lock);
707 PR_ASSERT(0 == rv);
708 return rv;
709 } /* PR_Wait */
710
711 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
712 {
713 pt_PostNotifyToMonitor(mon, PR_FALSE);
714 return PR_SUCCESS;
715 } /* PR_Notify */
716
717 PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
718 {
719 pt_PostNotifyToMonitor(mon, PR_TRUE);
720 return PR_SUCCESS;
721 } /* PR_NotifyAll */
722
723 /**************************************************************/
724 /**************************************************************/
725 /**************************SEMAPHORES**************************/
726 /**************************************************************/
727 /**************************************************************/
728 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore)
729 {
730 static PRBool unwarned = PR_TRUE;
731 if (unwarned) unwarned = _PR_Obsolete(
732 "PR_PostSem", "locks & condition variables");
733 PR_Lock(semaphore->cvar->lock);
734 PR_NotifyCondVar(semaphore->cvar);
735 semaphore->count += 1;
736 PR_Unlock(semaphore->cvar->lock);
737 } /* PR_PostSem */
738
739 PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore)
740 {
741 PRStatus status = PR_SUCCESS;
742 static PRBool unwarned = PR_TRUE;
743 if (unwarned) unwarned = _PR_Obsolete(
744 "PR_WaitSem", "locks & condition variables");
745 PR_Lock(semaphore->cvar->lock);
746 while ((semaphore->count == 0) && (PR_SUCCESS == status))
747 status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT);
748 if (PR_SUCCESS == status) semaphore->count -= 1;
749 PR_Unlock(semaphore->cvar->lock);
750 return status;
751 } /* PR_WaitSem */
752
753 PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore)
754 {
755 static PRBool unwarned = PR_TRUE;
756 if (unwarned) unwarned = _PR_Obsolete(
757 "PR_DestroySem", "locks & condition variables");
758 PR_DestroyLock(semaphore->cvar->lock);
759 PR_DestroyCondVar(semaphore->cvar);
760 PR_Free(semaphore);
761 } /* PR_DestroySem */
762
763 PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
764 {
765 PRSemaphore *semaphore;
766 static PRBool unwarned = PR_TRUE;
767 if (!_pr_initialized) _PR_ImplicitInitialization();
768
769 if (unwarned) unwarned = _PR_Obsolete(
770 "PR_NewSem", "locks & condition variables");
771
772 semaphore = PR_NEWZAP(PRSemaphore);
773 if (NULL != semaphore)
774 {
775 PRLock *lock = PR_NewLock();
776 if (NULL != lock)
777 {
778 semaphore->cvar = PR_NewCondVar(lock);
779 if (NULL != semaphore->cvar)
780 {
781 semaphore->count = value;
782 return semaphore;
783 }
784 PR_DestroyLock(lock);
785 }
786 PR_Free(semaphore);
787 }
788 return NULL;
789 }
790
791 /*
792 * Define the interprocess named semaphore functions.
793 * There are three implementations:
794 * 1. POSIX semaphore based;
795 * 2. System V semaphore based;
796 * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR).
797 */
798
799 #ifdef _PR_HAVE_POSIX_SEMAPHORES
800 #include <fcntl.h>
801
802 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
803 const char *name,
804 PRIntn flags,
805 PRIntn mode,
806 PRUintn value)
807 {
808 PRSem *sem;
809 char osname[PR_IPC_NAME_SIZE];
810
811 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
812 == PR_FAILURE)
813 {
814 return NULL;
815 }
816
817 sem = PR_NEW(PRSem);
818 if (NULL == sem)
819 {
820 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
821 return NULL;
822 }
823
824 if (flags & PR_SEM_CREATE)
825 {
826 int oflag = O_CREAT;
827
828 if (flags & PR_SEM_EXCL) oflag |= O_EXCL;
829 sem->sem = sem_open(osname, oflag, mode, value);
830 }
831 else
832 {
833 #ifdef HPUX
834 /* Pass 0 as the mode and value arguments to work around a bug. */
835 sem->sem = sem_open(osname, 0, 0, 0);
836 #else
837 sem->sem = sem_open(osname, 0);
838 #endif
839 }
840 if ((sem_t *) -1 == sem->sem)
841 {
842 _PR_MD_MAP_DEFAULT_ERROR(errno);
843 PR_Free(sem);
844 return NULL;
845 }
846 return sem;
847 }
848
849 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
850 {
851 int rv;
852 rv = sem_wait(sem->sem);
853 if (0 != rv)
854 {
855 _PR_MD_MAP_DEFAULT_ERROR(errno);
856 return PR_FAILURE;
857 }
858 return PR_SUCCESS;
859 }
860
861 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
862 {
863 int rv;
864 rv = sem_post(sem->sem);
865 if (0 != rv)
866 {
867 _PR_MD_MAP_DEFAULT_ERROR(errno);
868 return PR_FAILURE;
869 }
870 return PR_SUCCESS;
871 }
872
873 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
874 {
875 int rv;
876 rv = sem_close(sem->sem);
877 if (0 != rv)
878 {
879 _PR_MD_MAP_DEFAULT_ERROR(errno);
880 return PR_FAILURE;
881 }
882 PR_Free(sem);
883 return PR_SUCCESS;
884 }
885
886 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
887 {
888 int rv;
889 char osname[PR_IPC_NAME_SIZE];
890
891 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
892 == PR_FAILURE)
893 {
894 return PR_FAILURE;
895 }
896 rv = sem_unlink(osname);
897 if (0 != rv)
898 {
899 _PR_MD_MAP_DEFAULT_ERROR(errno);
900 return PR_FAILURE;
901 }
902 return PR_SUCCESS;
903 }
904
905 #elif defined(_PR_HAVE_SYSV_SEMAPHORES)
906
907 #include <fcntl.h>
908 #include <sys/sem.h>
909
910 /*
911 * From the semctl(2) man page in glibc 2.0
912 */
913 #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \
914 || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \
915 || defined(DARWIN) || defined(SYMBIAN)
916 /* union semun is defined by including <sys/sem.h> */
917 #else
918 /* according to X/OPEN we have to define it ourselves */
919 union semun {
920 int val;
921 struct semid_ds *buf;
922 unsigned short *array;
923 };
924 #endif
925
926 /*
927 * 'a' (97) is the final closing price of NSCP stock.
928 */
929 #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */
930
931 #define NSPR_SEM_MODE 0666
932
933 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
934 const char *name,
935 PRIntn flags,
936 PRIntn mode,
937 PRUintn value)
938 {
939 PRSem *sem;
940 key_t key;
941 union semun arg;
942 struct sembuf sop;
943 struct semid_ds seminfo;
944 #define MAX_TRIES 60
945 PRIntn i;
946 char osname[PR_IPC_NAME_SIZE];
947
948 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
949 == PR_FAILURE)
950 {
951 return NULL;
952 }
953
954 /* Make sure the file exists before calling ftok. */
955 if (flags & PR_SEM_CREATE)
956 {
957 int osfd = open(osname, O_RDWR|O_CREAT, mode);
958 if (-1 == osfd)
959 {
960 _PR_MD_MAP_OPEN_ERROR(errno);
961 return NULL;
962 }
963 if (close(osfd) == -1)
964 {
965 _PR_MD_MAP_CLOSE_ERROR(errno);
966 return NULL;
967 }
968 }
969 key = ftok(osname, NSPR_IPC_KEY_ID);
970 if ((key_t)-1 == key)
971 {
972 _PR_MD_MAP_DEFAULT_ERROR(errno);
973 return NULL;
974 }
975
976 sem = PR_NEW(PRSem);
977 if (NULL == sem)
978 {
979 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
980 return NULL;
981 }
982
983 if (flags & PR_SEM_CREATE)
984 {
985 sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL);
986 if (sem->semid >= 0)
987 {
988 /* creator of a semaphore is responsible for initializing it */
989 arg.val = 0;
990 if (semctl(sem->semid, 0, SETVAL, arg) == -1)
991 {
992 _PR_MD_MAP_DEFAULT_ERROR(errno);
993 PR_Free(sem);
994 return NULL;
995 }
996 /* call semop to set sem_otime to nonzero */
997 sop.sem_num = 0;
998 sop.sem_op = value;
999 sop.sem_flg = 0;
1000 if (semop(sem->semid, &sop, 1) == -1)
1001 {
1002 _PR_MD_MAP_DEFAULT_ERROR(errno);
1003 PR_Free(sem);
1004 return NULL;
1005 }
1006 return sem;
1007 }
1008
1009 if (errno != EEXIST || flags & PR_SEM_EXCL)
1010 {
1011 _PR_MD_MAP_DEFAULT_ERROR(errno);
1012 PR_Free(sem);
1013 return NULL;
1014 }
1015 }
1016
1017 sem->semid = semget(key, 1, NSPR_SEM_MODE);
1018 if (sem->semid == -1)
1019 {
1020 _PR_MD_MAP_DEFAULT_ERROR(errno);
1021 PR_Free(sem);
1022 return NULL;
1023 }
1024 for (i = 0; i < MAX_TRIES; i++)
1025 {
1026 arg.buf = &seminfo;
1027 semctl(sem->semid, 0, IPC_STAT, arg);
1028 if (seminfo.sem_otime != 0) break;
1029 sleep(1);
1030 }
1031 if (i == MAX_TRIES)
1032 {
1033 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
1034 PR_Free(sem);
1035 return NULL;
1036 }
1037 return sem;
1038 }
1039
1040 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
1041 {
1042 struct sembuf sop;
1043
1044 sop.sem_num = 0;
1045 sop.sem_op = -1;
1046 sop.sem_flg = 0;
1047 if (semop(sem->semid, &sop, 1) == -1)
1048 {
1049 _PR_MD_MAP_DEFAULT_ERROR(errno);
1050 return PR_FAILURE;
1051 }
1052 return PR_SUCCESS;
1053 }
1054
1055 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
1056 {
1057 struct sembuf sop;
1058
1059 sop.sem_num = 0;
1060 sop.sem_op = 1;
1061 sop.sem_flg = 0;
1062 if (semop(sem->semid, &sop, 1) == -1)
1063 {
1064 _PR_MD_MAP_DEFAULT_ERROR(errno);
1065 return PR_FAILURE;
1066 }
1067 return PR_SUCCESS;
1068 }
1069
1070 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1071 {
1072 PR_Free(sem);
1073 return PR_SUCCESS;
1074 }
1075
1076 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
1077 {
1078 key_t key;
1079 int semid;
1080 /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
1081 union semun unused;
1082 char osname[PR_IPC_NAME_SIZE];
1083
1084 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
1085 == PR_FAILURE)
1086 {
1087 return PR_FAILURE;
1088 }
1089 key = ftok(osname, NSPR_IPC_KEY_ID);
1090 if ((key_t) -1 == key)
1091 {
1092 _PR_MD_MAP_DEFAULT_ERROR(errno);
1093 return PR_FAILURE;
1094 }
1095 if (unlink(osname) == -1)
1096 {
1097 _PR_MD_MAP_UNLINK_ERROR(errno);
1098 return PR_FAILURE;
1099 }
1100 semid = semget(key, 1, NSPR_SEM_MODE);
1101 if (-1 == semid)
1102 {
1103 _PR_MD_MAP_DEFAULT_ERROR(errno);
1104 return PR_FAILURE;
1105 }
1106 unused.val = 0;
1107 if (semctl(semid, 0, IPC_RMID, unused) == -1)
1108 {
1109 _PR_MD_MAP_DEFAULT_ERROR(errno);
1110 return PR_FAILURE;
1111 }
1112 return PR_SUCCESS;
1113 }
1114
1115 #else /* neither POSIX nor System V semaphores are available */
1116
1117 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
1118 const char *name,
1119 PRIntn flags,
1120 PRIntn mode,
1121 PRUintn value)
1122 {
1123 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1124 return NULL;
1125 }
1126
1127 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
1128 {
1129 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1130 return PR_FAILURE;
1131 }
1132
1133 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
1134 {
1135 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1136 return PR_FAILURE;
1137 }
1138
1139 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1140 {
1141 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1142 return PR_FAILURE;
1143 }
1144
1145 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
1146 {
1147 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1148 return PR_FAILURE;
1149 }
1150
1151 #endif /* end of interprocess named semaphore functions */
1152
1153 /**************************************************************/
1154 /**************************************************************/
1155 /******************ROUTINES FOR DCE EMULATION******************/
1156 /**************************************************************/
1157 /**************************************************************/
1158
1159 #include "prpdce.h"
1160
1161 PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
1162 {
1163 PRIntn rv = pthread_mutex_trylock(&lock->mutex);
1164 if (rv == PT_TRYLOCK_SUCCESS)
1165 {
1166 PR_ASSERT(PR_FALSE == lock->locked);
1167 lock->locked = PR_TRUE;
1168 lock->owner = pthread_self();
1169 }
1170 /* XXX set error code? */
1171 return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
1172 } /* PRP_TryLock */
1173
1174 PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
1175 {
1176 PRCondVar *cv;
1177
1178 if (!_pr_initialized) _PR_ImplicitInitialization();
1179
1180 cv = PR_NEW(PRCondVar);
1181 if (cv != NULL)
1182 {
1183 int rv;
1184 rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr);
1185 PR_ASSERT(0 == rv);
1186 cv->lock = _PR_NAKED_CV_LOCK;
1187 }
1188 return cv;
1189 } /* PRP_NewNakedCondVar */
1190
1191 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
1192 {
1193 int rv;
1194 rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
1195 #if defined(DEBUG)
1196 memset(cvar, 0xaf, sizeof(PRCondVar));
1197 #endif
1198 PR_Free(cvar);
1199 } /* PRP_DestroyNakedCondVar */
1200
1201 PR_IMPLEMENT(PRStatus) PRP_NakedWait(
1202 PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout)
1203 {
1204 PRIntn rv;
1205 PR_ASSERT(cvar != NULL);
1206 /* XXX do we really want to assert this in a naked wait? */
1207 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex));
1208 if (timeout == PR_INTERVAL_NO_TIMEOUT)
1209 rv = pthread_cond_wait(&cvar->cv, &ml->mutex);
1210 else
1211 rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout);
1212 if (rv != 0)
1213 {
1214 _PR_MD_MAP_DEFAULT_ERROR(rv);
1215 return PR_FAILURE;
1216 }
1217 return PR_SUCCESS;
1218 } /* PRP_NakedWait */
1219
1220 PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
1221 {
1222 int rv;
1223 PR_ASSERT(cvar != NULL);
1224 rv = pthread_cond_signal(&cvar->cv);
1225 PR_ASSERT(0 == rv);
1226 return PR_SUCCESS;
1227 } /* PRP_NakedNotify */
1228
1229 PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
1230 {
1231 int rv;
1232 PR_ASSERT(cvar != NULL);
1233 rv = pthread_cond_broadcast(&cvar->cv);
1234 PR_ASSERT(0 == rv);
1235 return PR_SUCCESS;
1236 } /* PRP_NakedBroadcast */
1237
1238 #endif /* defined(_PR_PTHREADS) */
1239
1240 /* ptsynch.c */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)