Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(133)

Side by Side Diff: nspr/pr/src/pthreads/ptsynch.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nspr/pr/src/pthreads/ptmisc.c ('k') | nspr/pr/src/pthreads/ptthread.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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_ns ec);
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 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
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
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
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
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 */
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
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
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
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
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 */
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
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
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
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
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
722 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
723 {
724 pt_PostNotifyToMonitor(mon, PR_FALSE);
725 return PR_SUCCESS;
726 } /* PR_Notify */
727
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 /**************************************************************/
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
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
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
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
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
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
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
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
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
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
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
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
1081 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1082 {
1083 PR_Free(sem);
1084 return PR_SUCCESS;
1085 }
1086
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
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
1138 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
1139 {
1140 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1141 return PR_FAILURE;
1142 }
1143
1144 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
1145 {
1146 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1147 return PR_FAILURE;
1148 }
1149
1150 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1151 {
1152 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1153 return PR_FAILURE;
1154 }
1155
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
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
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
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
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
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
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 */
OLDNEW
« no previous file with comments | « nspr/pr/src/pthreads/ptmisc.c ('k') | nspr/pr/src/pthreads/ptthread.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698