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

Side by Side Diff: mozilla/nsprpub/pr/src/pthreads/ptsynch.c

Issue 14249009: Change the NSS and NSPR source tree to the new directory structure to be (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/deps/third_party/nss/
Patch Set: Created 7 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « mozilla/nsprpub/pr/src/pthreads/ptmisc.c ('k') | mozilla/nsprpub/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 PRIntn rv;
173 PR_ASSERT(lock != NULL);
174 rv = pthread_mutex_lock(&lock->mutex);
175 PR_ASSERT(0 == rv);
176 PR_ASSERT(0 == lock->notified.length);
177 PR_ASSERT(NULL == lock->notified.link);
178 PR_ASSERT(PR_FALSE == lock->locked);
179 /* Nb: the order of the next two statements is not critical to
180 * the correctness of PR_AssertCurrentThreadOwnsLock(), but
181 * this particular order makes the assertion more likely to
182 * catch errors. */
183 lock->owner = pthread_self();
184 lock->locked = PR_TRUE;
185 #if defined(DEBUG)
186 pt_debug.locks_acquired += 1;
187 #endif
188 } /* PR_Lock */
189
190 PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock)
191 {
192 PRIntn rv;
193
194 PR_ASSERT(lock != NULL);
195 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex));
196 PR_ASSERT(PR_TRUE == lock->locked);
197 PR_ASSERT(pthread_equal(lock->owner, pthread_self()));
198
199 if (!lock->locked || !pthread_equal(lock->owner, pthread_self()))
200 return PR_FAILURE;
201
202 lock->locked = PR_FALSE;
203 if (0 == lock->notified.length) /* shortcut */
204 {
205 rv = pthread_mutex_unlock(&lock->mutex);
206 PR_ASSERT(0 == rv);
207 }
208 else pt_PostNotifies(lock, PR_TRUE);
209
210 #if defined(DEBUG)
211 pt_debug.locks_released += 1;
212 #endif
213 return PR_SUCCESS;
214 } /* PR_Unlock */
215
216 PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock)
217 {
218 /* Nb: the order of the |locked| and |owner==me| checks is not critical
219 * to the correctness of PR_AssertCurrentThreadOwnsLock(), but
220 * this particular order makes the assertion more likely to
221 * catch errors. */
222 PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self()));
223 }
224
225 /**************************************************************/
226 /**************************************************************/
227 /***************************CONDITIONS*************************/
228 /**************************************************************/
229 /**************************************************************/
230
231
232 /*
233 * This code is used to compute the absolute time for the wakeup.
234 * It's moderately ugly, so it's defined here and called in a
235 * couple of places.
236 */
237 #define PT_NANOPERMICRO 1000UL
238 #define PT_BILLION 1000000000UL
239
240 static PRIntn pt_TimedWait(
241 pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout)
242 {
243 int rv;
244 struct timeval now;
245 struct timespec tmo;
246 PRUint32 ticks = PR_TicksPerSecond();
247
248 tmo.tv_sec = (PRInt32)(timeout / ticks);
249 tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks));
250 tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_ns ec);
251
252 /* pthreads wants this in absolute time, off we go ... */
253 (void)GETTIMEOFDAY(&now);
254 /* that one's usecs, this one's nsecs - grrrr! */
255 tmo.tv_sec += now.tv_sec;
256 tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec);
257 tmo.tv_sec += tmo.tv_nsec / PT_BILLION;
258 tmo.tv_nsec %= PT_BILLION;
259
260 rv = pthread_cond_timedwait(cv, ml, &tmo);
261
262 /* NSPR doesn't report timeouts */
263 #ifdef _PR_DCETHREADS
264 if (rv == -1) return (errno == EAGAIN) ? 0 : errno;
265 else return rv;
266 #else
267 return (rv == ETIMEDOUT) ? 0 : rv;
268 #endif
269 } /* pt_TimedWait */
270
271
272 /*
273 * Notifies just get posted to the protecting mutex. The
274 * actual notification is done when the lock is released so that
275 * MP systems don't contend for a lock that they can't have.
276 */
277 static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast)
278 {
279 PRIntn index = 0;
280 _PT_Notified *notified = &cvar->lock->notified;
281
282 PR_ASSERT(PR_TRUE == cvar->lock->locked);
283 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
284 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex));
285
286 while (1)
287 {
288 for (index = 0; index < notified->length; ++index)
289 {
290 if (notified->cv[index].cv == cvar)
291 {
292 if (broadcast)
293 notified->cv[index].times = -1;
294 else if (-1 != notified->cv[index].times)
295 notified->cv[index].times += 1;
296 goto finished; /* we're finished */
297 }
298 }
299 /* if not full, enter new CV in this array */
300 if (notified->length < PT_CV_NOTIFIED_LENGTH) break;
301
302 /* if there's no link, create an empty array and link it */
303 if (NULL == notified->link)
304 notified->link = PR_NEWZAP(_PT_Notified);
305 notified = notified->link;
306 }
307
308 /* A brand new entry in the array */
309 (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending);
310 notified->cv[index].times = (broadcast) ? -1 : 1;
311 notified->cv[index].cv = cvar;
312 notified->length += 1;
313
314 finished:
315 PR_ASSERT(PR_TRUE == cvar->lock->locked);
316 PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self()));
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 PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void)
431 {
432 PRMonitor *mon;
433 PRCondVar *cvar;
434 int rv;
435
436 if (!_pr_initialized) _PR_ImplicitInitialization();
437
438 cvar = PR_NEWZAP(PRCondVar);
439 if (NULL == cvar)
440 {
441 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
442 return NULL;
443 }
444 mon = PR_NEWZAP(PRMonitor);
445 if (mon == NULL)
446 {
447 PR_Free(cvar);
448 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
449 return NULL;
450 }
451
452 rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr);
453 PR_ASSERT(0 == rv);
454 if (0 != rv)
455 {
456 PR_Free(mon);
457 PR_Free(cvar);
458 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
459 return NULL;
460 }
461
462 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
463
464 mon->cvar = cvar;
465 rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr);
466 PR_ASSERT(0 == rv);
467 mon->entryCount = 0;
468 mon->cvar->lock = &mon->lock;
469 if (0 != rv)
470 {
471 pthread_mutex_destroy(&mon->lock.mutex);
472 PR_Free(mon);
473 PR_Free(cvar);
474 PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0);
475 return NULL;
476 }
477 return mon;
478 } /* PR_NewMonitor */
479
480 PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name)
481 {
482 PRMonitor* mon = PR_NewMonitor();
483 if (mon)
484 mon->name = name;
485 return mon;
486 }
487
488 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon)
489 {
490 int rv;
491 PR_ASSERT(mon != NULL);
492 PR_DestroyCondVar(mon->cvar);
493 rv = pthread_mutex_destroy(&mon->lock.mutex); PR_ASSERT(0 == rv);
494 #if defined(DEBUG)
495 memset(mon, 0xaf, sizeof(PRMonitor));
496 #endif
497 PR_Free(mon);
498 } /* PR_DestroyMonitor */
499
500
501 /* The GC uses this; it is quite arguably a bad interface. I'm just
502 * duplicating it for now - XXXMB
503 */
504 PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon)
505 {
506 pthread_t self = pthread_self();
507 if (pthread_equal(mon->owner, self))
508 return mon->entryCount;
509 return 0;
510 }
511
512 PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon)
513 {
514 PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(&mon->lock);
515 }
516
517 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon)
518 {
519 pthread_t self = pthread_self();
520
521 PR_ASSERT(mon != NULL);
522 /*
523 * This is safe only if mon->owner (a pthread_t) can be
524 * read in one instruction. Perhaps mon->owner should be
525 * a "PRThread *"?
526 */
527 if (!pthread_equal(mon->owner, self))
528 {
529 PR_Lock(&mon->lock);
530 /* and now I have the lock */
531 PR_ASSERT(0 == mon->entryCount);
532 PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner));
533 _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner);
534 }
535 mon->entryCount += 1;
536 } /* PR_EnterMonitor */
537
538 PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon)
539 {
540 pthread_t self = pthread_self();
541
542 PR_ASSERT(mon != NULL);
543 /* The lock better be that - locked */
544 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
545 /* we'd better be the owner */
546 PR_ASSERT(pthread_equal(mon->owner, self));
547 if (!pthread_equal(mon->owner, self))
548 return PR_FAILURE;
549
550 /* if it's locked and we have it, then the entries should be > 0 */
551 PR_ASSERT(mon->entryCount > 0);
552 mon->entryCount -= 1; /* reduce by one */
553 if (mon->entryCount == 0)
554 {
555 /* and if it transitioned to zero - unlock */
556 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknow n */
557 PR_Unlock(&mon->lock);
558 }
559 return PR_SUCCESS;
560 } /* PR_ExitMonitor */
561
562 PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout)
563 {
564 PRStatus rv;
565 PRInt16 saved_entries;
566 pthread_t saved_owner;
567
568 PR_ASSERT(mon != NULL);
569 /* we'd better be locked */
570 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
571 /* and the entries better be positive */
572 PR_ASSERT(mon->entryCount > 0);
573 /* and it better be by us */
574 PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
575
576 /* tuck these away 'till later */
577 saved_entries = mon->entryCount;
578 mon->entryCount = 0;
579 _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner);
580 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner);
581
582 rv = PR_WaitCondVar(mon->cvar, timeout);
583
584 /* reinstate the intresting information */
585 mon->entryCount = saved_entries;
586 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner);
587
588 return rv;
589 } /* PR_Wait */
590
591 PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon)
592 {
593 PR_ASSERT(NULL != mon);
594 /* we'd better be locked */
595 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
596 /* and the entries better be positive */
597 PR_ASSERT(mon->entryCount > 0);
598 /* and it better be by us */
599 PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
600
601 pt_PostNotifyToCvar(mon->cvar, PR_FALSE);
602
603 return PR_SUCCESS;
604 } /* PR_Notify */
605
606 PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon)
607 {
608 PR_ASSERT(mon != NULL);
609 /* we'd better be locked */
610 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex));
611 /* and the entries better be positive */
612 PR_ASSERT(mon->entryCount > 0);
613 /* and it better be by us */
614 PR_ASSERT(pthread_equal(mon->owner, pthread_self()));
615
616 pt_PostNotifyToCvar(mon->cvar, PR_TRUE);
617
618 return PR_SUCCESS;
619 } /* PR_NotifyAll */
620
621 /**************************************************************/
622 /**************************************************************/
623 /**************************SEMAPHORES**************************/
624 /**************************************************************/
625 /**************************************************************/
626 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore)
627 {
628 static PRBool unwarned = PR_TRUE;
629 if (unwarned) unwarned = _PR_Obsolete(
630 "PR_PostSem", "locks & condition variables");
631 PR_Lock(semaphore->cvar->lock);
632 PR_NotifyCondVar(semaphore->cvar);
633 semaphore->count += 1;
634 PR_Unlock(semaphore->cvar->lock);
635 } /* PR_PostSem */
636
637 PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore)
638 {
639 PRStatus status = PR_SUCCESS;
640 static PRBool unwarned = PR_TRUE;
641 if (unwarned) unwarned = _PR_Obsolete(
642 "PR_WaitSem", "locks & condition variables");
643 PR_Lock(semaphore->cvar->lock);
644 while ((semaphore->count == 0) && (PR_SUCCESS == status))
645 status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT) ;
646 if (PR_SUCCESS == status) semaphore->count -= 1;
647 PR_Unlock(semaphore->cvar->lock);
648 return status;
649 } /* PR_WaitSem */
650
651 PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore)
652 {
653 static PRBool unwarned = PR_TRUE;
654 if (unwarned) unwarned = _PR_Obsolete(
655 "PR_DestroySem", "locks & condition variables");
656 PR_DestroyLock(semaphore->cvar->lock);
657 PR_DestroyCondVar(semaphore->cvar);
658 PR_Free(semaphore);
659 } /* PR_DestroySem */
660
661 PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value)
662 {
663 PRSemaphore *semaphore;
664 static PRBool unwarned = PR_TRUE;
665 if (!_pr_initialized) _PR_ImplicitInitialization();
666
667 if (unwarned) unwarned = _PR_Obsolete(
668 "PR_NewSem", "locks & condition variables");
669
670 semaphore = PR_NEWZAP(PRSemaphore);
671 if (NULL != semaphore)
672 {
673 PRLock *lock = PR_NewLock();
674 if (NULL != lock)
675 {
676 semaphore->cvar = PR_NewCondVar(lock);
677 if (NULL != semaphore->cvar)
678 {
679 semaphore->count = value;
680 return semaphore;
681 }
682 PR_DestroyLock(lock);
683 }
684 PR_Free(semaphore);
685 }
686 return NULL;
687 }
688
689 /*
690 * Define the interprocess named semaphore functions.
691 * There are three implementations:
692 * 1. POSIX semaphore based;
693 * 2. System V semaphore based;
694 * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR).
695 */
696
697 #ifdef _PR_HAVE_POSIX_SEMAPHORES
698 #include <fcntl.h>
699
700 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
701 const char *name,
702 PRIntn flags,
703 PRIntn mode,
704 PRUintn value)
705 {
706 PRSem *sem;
707 char osname[PR_IPC_NAME_SIZE];
708
709 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
710 == PR_FAILURE)
711 {
712 return NULL;
713 }
714
715 sem = PR_NEW(PRSem);
716 if (NULL == sem)
717 {
718 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
719 return NULL;
720 }
721
722 if (flags & PR_SEM_CREATE)
723 {
724 int oflag = O_CREAT;
725
726 if (flags & PR_SEM_EXCL) oflag |= O_EXCL;
727 sem->sem = sem_open(osname, oflag, mode, value);
728 }
729 else
730 {
731 #ifdef HPUX
732 /* Pass 0 as the mode and value arguments to work around a bug. */
733 sem->sem = sem_open(osname, 0, 0, 0);
734 #else
735 sem->sem = sem_open(osname, 0);
736 #endif
737 }
738 if ((sem_t *) -1 == sem->sem)
739 {
740 _PR_MD_MAP_DEFAULT_ERROR(errno);
741 PR_Free(sem);
742 return NULL;
743 }
744 return sem;
745 }
746
747 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
748 {
749 int rv;
750 rv = sem_wait(sem->sem);
751 if (0 != rv)
752 {
753 _PR_MD_MAP_DEFAULT_ERROR(errno);
754 return PR_FAILURE;
755 }
756 return PR_SUCCESS;
757 }
758
759 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
760 {
761 int rv;
762 rv = sem_post(sem->sem);
763 if (0 != rv)
764 {
765 _PR_MD_MAP_DEFAULT_ERROR(errno);
766 return PR_FAILURE;
767 }
768 return PR_SUCCESS;
769 }
770
771 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
772 {
773 int rv;
774 rv = sem_close(sem->sem);
775 if (0 != rv)
776 {
777 _PR_MD_MAP_DEFAULT_ERROR(errno);
778 return PR_FAILURE;
779 }
780 PR_Free(sem);
781 return PR_SUCCESS;
782 }
783
784 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
785 {
786 int rv;
787 char osname[PR_IPC_NAME_SIZE];
788
789 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
790 == PR_FAILURE)
791 {
792 return PR_FAILURE;
793 }
794 rv = sem_unlink(osname);
795 if (0 != rv)
796 {
797 _PR_MD_MAP_DEFAULT_ERROR(errno);
798 return PR_FAILURE;
799 }
800 return PR_SUCCESS;
801 }
802
803 #elif defined(_PR_HAVE_SYSV_SEMAPHORES)
804
805 #include <fcntl.h>
806 #include <sys/sem.h>
807
808 /*
809 * From the semctl(2) man page in glibc 2.0
810 */
811 #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \
812 || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \
813 || defined(DARWIN) || defined(SYMBIAN)
814 /* union semun is defined by including <sys/sem.h> */
815 #else
816 /* according to X/OPEN we have to define it ourselves */
817 union semun {
818 int val;
819 struct semid_ds *buf;
820 unsigned short *array;
821 };
822 #endif
823
824 /*
825 * 'a' (97) is the final closing price of NSCP stock.
826 */
827 #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */
828
829 #define NSPR_SEM_MODE 0666
830
831 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
832 const char *name,
833 PRIntn flags,
834 PRIntn mode,
835 PRUintn value)
836 {
837 PRSem *sem;
838 key_t key;
839 union semun arg;
840 struct sembuf sop;
841 struct semid_ds seminfo;
842 #define MAX_TRIES 60
843 PRIntn i;
844 char osname[PR_IPC_NAME_SIZE];
845
846 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
847 == PR_FAILURE)
848 {
849 return NULL;
850 }
851
852 /* Make sure the file exists before calling ftok. */
853 if (flags & PR_SEM_CREATE)
854 {
855 int osfd = open(osname, O_RDWR|O_CREAT, mode);
856 if (-1 == osfd)
857 {
858 _PR_MD_MAP_OPEN_ERROR(errno);
859 return NULL;
860 }
861 if (close(osfd) == -1)
862 {
863 _PR_MD_MAP_CLOSE_ERROR(errno);
864 return NULL;
865 }
866 }
867 key = ftok(osname, NSPR_IPC_KEY_ID);
868 if ((key_t)-1 == key)
869 {
870 _PR_MD_MAP_DEFAULT_ERROR(errno);
871 return NULL;
872 }
873
874 sem = PR_NEW(PRSem);
875 if (NULL == sem)
876 {
877 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
878 return NULL;
879 }
880
881 if (flags & PR_SEM_CREATE)
882 {
883 sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL);
884 if (sem->semid >= 0)
885 {
886 /* creator of a semaphore is responsible for initializing it */
887 arg.val = 0;
888 if (semctl(sem->semid, 0, SETVAL, arg) == -1)
889 {
890 _PR_MD_MAP_DEFAULT_ERROR(errno);
891 PR_Free(sem);
892 return NULL;
893 }
894 /* call semop to set sem_otime to nonzero */
895 sop.sem_num = 0;
896 sop.sem_op = value;
897 sop.sem_flg = 0;
898 if (semop(sem->semid, &sop, 1) == -1)
899 {
900 _PR_MD_MAP_DEFAULT_ERROR(errno);
901 PR_Free(sem);
902 return NULL;
903 }
904 return sem;
905 }
906
907 if (errno != EEXIST || flags & PR_SEM_EXCL)
908 {
909 _PR_MD_MAP_DEFAULT_ERROR(errno);
910 PR_Free(sem);
911 return NULL;
912 }
913 }
914
915 sem->semid = semget(key, 1, NSPR_SEM_MODE);
916 if (sem->semid == -1)
917 {
918 _PR_MD_MAP_DEFAULT_ERROR(errno);
919 PR_Free(sem);
920 return NULL;
921 }
922 for (i = 0; i < MAX_TRIES; i++)
923 {
924 arg.buf = &seminfo;
925 semctl(sem->semid, 0, IPC_STAT, arg);
926 if (seminfo.sem_otime != 0) break;
927 sleep(1);
928 }
929 if (i == MAX_TRIES)
930 {
931 PR_SetError(PR_IO_TIMEOUT_ERROR, 0);
932 PR_Free(sem);
933 return NULL;
934 }
935 return sem;
936 }
937
938 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
939 {
940 struct sembuf sop;
941
942 sop.sem_num = 0;
943 sop.sem_op = -1;
944 sop.sem_flg = 0;
945 if (semop(sem->semid, &sop, 1) == -1)
946 {
947 _PR_MD_MAP_DEFAULT_ERROR(errno);
948 return PR_FAILURE;
949 }
950 return PR_SUCCESS;
951 }
952
953 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
954 {
955 struct sembuf sop;
956
957 sop.sem_num = 0;
958 sop.sem_op = 1;
959 sop.sem_flg = 0;
960 if (semop(sem->semid, &sop, 1) == -1)
961 {
962 _PR_MD_MAP_DEFAULT_ERROR(errno);
963 return PR_FAILURE;
964 }
965 return PR_SUCCESS;
966 }
967
968 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
969 {
970 PR_Free(sem);
971 return PR_SUCCESS;
972 }
973
974 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
975 {
976 key_t key;
977 int semid;
978 /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
979 union semun unused;
980 char osname[PR_IPC_NAME_SIZE];
981
982 if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem)
983 == PR_FAILURE)
984 {
985 return PR_FAILURE;
986 }
987 key = ftok(osname, NSPR_IPC_KEY_ID);
988 if ((key_t) -1 == key)
989 {
990 _PR_MD_MAP_DEFAULT_ERROR(errno);
991 return PR_FAILURE;
992 }
993 if (unlink(osname) == -1)
994 {
995 _PR_MD_MAP_UNLINK_ERROR(errno);
996 return PR_FAILURE;
997 }
998 semid = semget(key, 1, NSPR_SEM_MODE);
999 if (-1 == semid)
1000 {
1001 _PR_MD_MAP_DEFAULT_ERROR(errno);
1002 return PR_FAILURE;
1003 }
1004 unused.val = 0;
1005 if (semctl(semid, 0, IPC_RMID, unused) == -1)
1006 {
1007 _PR_MD_MAP_DEFAULT_ERROR(errno);
1008 return PR_FAILURE;
1009 }
1010 return PR_SUCCESS;
1011 }
1012
1013 #else /* neither POSIX nor System V semaphores are available */
1014
1015 PR_IMPLEMENT(PRSem *) PR_OpenSemaphore(
1016 const char *name,
1017 PRIntn flags,
1018 PRIntn mode,
1019 PRUintn value)
1020 {
1021 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1022 return NULL;
1023 }
1024
1025 PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem)
1026 {
1027 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1028 return PR_FAILURE;
1029 }
1030
1031 PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem)
1032 {
1033 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1034 return PR_FAILURE;
1035 }
1036
1037 PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem)
1038 {
1039 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1040 return PR_FAILURE;
1041 }
1042
1043 PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
1044 {
1045 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
1046 return PR_FAILURE;
1047 }
1048
1049 #endif /* end of interprocess named semaphore functions */
1050
1051 /**************************************************************/
1052 /**************************************************************/
1053 /******************ROUTINES FOR DCE EMULATION******************/
1054 /**************************************************************/
1055 /**************************************************************/
1056
1057 #include "prpdce.h"
1058
1059 PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
1060 {
1061 PRIntn rv = pthread_mutex_trylock(&lock->mutex);
1062 if (rv == PT_TRYLOCK_SUCCESS)
1063 {
1064 PR_ASSERT(PR_FALSE == lock->locked);
1065 lock->locked = PR_TRUE;
1066 lock->owner = pthread_self();
1067 }
1068 /* XXX set error code? */
1069 return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
1070 } /* PRP_TryLock */
1071
1072 PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
1073 {
1074 PRCondVar *cv;
1075
1076 if (!_pr_initialized) _PR_ImplicitInitialization();
1077
1078 cv = PR_NEW(PRCondVar);
1079 if (cv != NULL)
1080 {
1081 int rv;
1082 rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr);
1083 PR_ASSERT(0 == rv);
1084 cv->lock = _PR_NAKED_CV_LOCK;
1085 }
1086 return cv;
1087 } /* PRP_NewNakedCondVar */
1088
1089 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar)
1090 {
1091 int rv;
1092 rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv);
1093 #if defined(DEBUG)
1094 memset(cvar, 0xaf, sizeof(PRCondVar));
1095 #endif
1096 PR_Free(cvar);
1097 } /* PRP_DestroyNakedCondVar */
1098
1099 PR_IMPLEMENT(PRStatus) PRP_NakedWait(
1100 PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout)
1101 {
1102 PRIntn rv;
1103 PR_ASSERT(cvar != NULL);
1104 /* XXX do we really want to assert this in a naked wait? */
1105 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex));
1106 if (timeout == PR_INTERVAL_NO_TIMEOUT)
1107 rv = pthread_cond_wait(&cvar->cv, &ml->mutex);
1108 else
1109 rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout);
1110 if (rv != 0)
1111 {
1112 _PR_MD_MAP_DEFAULT_ERROR(rv);
1113 return PR_FAILURE;
1114 }
1115 return PR_SUCCESS;
1116 } /* PRP_NakedWait */
1117
1118 PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar)
1119 {
1120 int rv;
1121 PR_ASSERT(cvar != NULL);
1122 rv = pthread_cond_signal(&cvar->cv);
1123 PR_ASSERT(0 == rv);
1124 return PR_SUCCESS;
1125 } /* PRP_NakedNotify */
1126
1127 PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar)
1128 {
1129 int rv;
1130 PR_ASSERT(cvar != NULL);
1131 rv = pthread_cond_broadcast(&cvar->cv);
1132 PR_ASSERT(0 == rv);
1133 return PR_SUCCESS;
1134 } /* PRP_NakedBroadcast */
1135
1136 #endif /* defined(_PR_PTHREADS) */
1137
1138 /* ptsynch.c */
OLDNEW
« no previous file with comments | « mozilla/nsprpub/pr/src/pthreads/ptmisc.c ('k') | mozilla/nsprpub/pr/src/pthreads/ptthread.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698