1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is the Netscape Portable Runtime (NSPR).
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
40 ** Descritpion: Implemenation for thread synchronization using pthreads
41 ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h
44 #if defined(_PR_PTHREADS)
47 #include "obsolete/prsem.h"
53 static pthread_mutexattr_t _pt_mattr
;
54 static pthread_condattr_t _pt_cvar_attr
;
57 extern PTDebug pt_debug
; /* this is shared between several modules */
59 #if defined(_PR_DCETHREADS)
60 static pthread_t pt_zero_tid
; /* a null pthread_t (pthread_t is a struct
61 * in DCE threads) to compare with */
62 #endif /* defined(_PR_DCETHREADS) */
63 #endif /* defined(DEBUG) */
67 * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK.
68 * Newer versions return EBUSY. We still need to support both.
71 pt_pthread_mutex_is_locked(pthread_mutex_t
*m
)
73 int rv
= pthread_mutex_trylock(m
);
74 return (EBUSY
== rv
|| EDEADLK
== rv
);
78 /**************************************************************/
79 /**************************************************************/
80 /*****************************LOCKS****************************/
81 /**************************************************************/
82 /**************************************************************/
84 void _PR_InitLocks(void)
87 rv
= _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr
);
91 #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2)
92 rv
= pthread_mutexattr_settype(&_pt_mattr
, PTHREAD_MUTEX_ADAPTIVE_NP
);
97 rv
= _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr
);
101 static void pt_PostNotifies(PRLock
*lock
, PRBool unlock
)
105 _PT_Notified
*notified
, *prev
= NULL
;
107 * Time to actually notify any conditions that were affected
108 * while the lock was held. Get a copy of the list that's in
109 * the lock structure and then zero the original. If it's
110 * linked to other such structures, we own that storage.
112 post
= lock
->notified
; /* a safe copy; we own the lock */
115 memset(&lock
->notified
, 0, sizeof(_PT_Notified
)); /* reset */
117 lock
->notified
.length
= 0; /* these are really sufficient */
118 lock
->notified
.link
= NULL
;
121 /* should (may) we release lock before notifying? */
124 rv
= pthread_mutex_unlock(&lock
->mutex
);
128 notified
= &post
; /* this is where we start */
131 for (index
= 0; index
< notified
->length
; ++index
)
133 PRCondVar
*cv
= notified
->cv
[index
].cv
;
134 PR_ASSERT(NULL
!= cv
);
135 PR_ASSERT(0 != notified
->cv
[index
].times
);
136 if (-1 == notified
->cv
[index
].times
)
138 rv
= pthread_cond_broadcast(&cv
->cv
);
143 while (notified
->cv
[index
].times
-- > 0)
145 rv
= pthread_cond_signal(&cv
->cv
);
150 pt_debug
.cvars_notified
+= 1;
151 if (0 > PR_AtomicDecrement(&cv
->notify_pending
))
153 pt_debug
.delayed_cv_deletes
+= 1;
154 PR_DestroyCondVar(cv
);
156 #else /* defined(DEBUG) */
157 if (0 > PR_AtomicDecrement(&cv
->notify_pending
))
158 PR_DestroyCondVar(cv
);
159 #endif /* defined(DEBUG) */
162 notified
= notified
->link
;
163 if (&post
!= prev
) PR_DELETE(prev
);
164 } while (NULL
!= notified
);
165 } /* pt_PostNotifies */
167 PR_IMPLEMENT(PRLock
*) PR_NewLock(void)
172 if (!_pr_initialized
) _PR_ImplicitInitialization();
174 lock
= PR_NEWZAP(PRLock
);
177 rv
= _PT_PTHREAD_MUTEX_INIT(lock
->mutex
, _pt_mattr
);
181 pt_debug
.locks_created
+= 1;
186 PR_IMPLEMENT(void) PR_DestroyLock(PRLock
*lock
)
189 PR_ASSERT(NULL
!= lock
);
190 PR_ASSERT(PR_FALSE
== lock
->locked
);
191 PR_ASSERT(0 == lock
->notified
.length
);
192 PR_ASSERT(NULL
== lock
->notified
.link
);
193 rv
= pthread_mutex_destroy(&lock
->mutex
);
196 memset(lock
, 0xaf, sizeof(PRLock
));
197 pt_debug
.locks_destroyed
+= 1;
200 } /* PR_DestroyLock */
202 PR_IMPLEMENT(void) PR_Lock(PRLock
*lock
)
205 PR_ASSERT(lock
!= NULL
);
206 rv
= pthread_mutex_lock(&lock
->mutex
);
208 PR_ASSERT(0 == lock
->notified
.length
);
209 PR_ASSERT(NULL
== lock
->notified
.link
);
210 PR_ASSERT(PR_FALSE
== lock
->locked
);
211 lock
->locked
= PR_TRUE
;
212 lock
->owner
= pthread_self();
214 pt_debug
.locks_acquired
+= 1;
218 PR_IMPLEMENT(PRStatus
) PR_Unlock(PRLock
*lock
)
222 PR_ASSERT(lock
!= NULL
);
223 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock
->mutex
));
224 PR_ASSERT(PR_TRUE
== lock
->locked
);
225 PR_ASSERT(pthread_equal(lock
->owner
, pthread_self()));
227 if (!lock
->locked
|| !pthread_equal(lock
->owner
, pthread_self()))
230 lock
->locked
= PR_FALSE
;
231 if (0 == lock
->notified
.length
) /* shortcut */
233 rv
= pthread_mutex_unlock(&lock
->mutex
);
236 else pt_PostNotifies(lock
, PR_TRUE
);
239 pt_debug
.locks_released
+= 1;
245 /**************************************************************/
246 /**************************************************************/
247 /***************************CONDITIONS*************************/
248 /**************************************************************/
249 /**************************************************************/
253 * This code is used to compute the absolute time for the wakeup.
254 * It's moderately ugly, so it's defined here and called in a
257 #define PT_NANOPERMICRO 1000UL
258 #define PT_BILLION 1000000000UL
260 static PRIntn
pt_TimedWait(
261 pthread_cond_t
*cv
, pthread_mutex_t
*ml
, PRIntervalTime timeout
)
266 PRUint32 ticks
= PR_TicksPerSecond();
268 tmo
.tv_sec
= (PRInt32
)(timeout
/ ticks
);
269 tmo
.tv_nsec
= (PRInt32
)(timeout
- (tmo
.tv_sec
* ticks
));
270 tmo
.tv_nsec
= (PRInt32
)PR_IntervalToMicroseconds(PT_NANOPERMICRO
* tmo
.tv_nsec
);
272 /* pthreads wants this in absolute time, off we go ... */
273 (void)GETTIMEOFDAY(&now
);
274 /* that one's usecs, this one's nsecs - grrrr! */
275 tmo
.tv_sec
+= now
.tv_sec
;
276 tmo
.tv_nsec
+= (PT_NANOPERMICRO
* now
.tv_usec
);
277 tmo
.tv_sec
+= tmo
.tv_nsec
/ PT_BILLION
;
278 tmo
.tv_nsec
%= PT_BILLION
;
280 rv
= pthread_cond_timedwait(cv
, ml
, &tmo
);
282 /* NSPR doesn't report timeouts */
283 #ifdef _PR_DCETHREADS
284 if (rv
== -1) return (errno
== EAGAIN
) ? 0 : errno
;
287 return (rv
== ETIMEDOUT
) ? 0 : rv
;
293 * Notifies just get posted to the protecting mutex. The
294 * actual notification is done when the lock is released so that
295 * MP systems don't contend for a lock that they can't have.
297 static void pt_PostNotifyToCvar(PRCondVar
*cvar
, PRBool broadcast
)
300 _PT_Notified
*notified
= &cvar
->lock
->notified
;
302 PR_ASSERT(PR_TRUE
== cvar
->lock
->locked
);
303 PR_ASSERT(pthread_equal(cvar
->lock
->owner
, pthread_self()));
304 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar
->lock
->mutex
));
308 for (index
= 0; index
< notified
->length
; ++index
)
310 if (notified
->cv
[index
].cv
== cvar
)
313 notified
->cv
[index
].times
= -1;
314 else if (-1 != notified
->cv
[index
].times
)
315 notified
->cv
[index
].times
+= 1;
316 goto finished
; /* we're finished */
319 /* if not full, enter new CV in this array */
320 if (notified
->length
< PT_CV_NOTIFIED_LENGTH
) break;
322 /* if there's no link, create an empty array and link it */
323 if (NULL
== notified
->link
)
324 notified
->link
= PR_NEWZAP(_PT_Notified
);
325 notified
= notified
->link
;
328 /* A brand new entry in the array */
329 (void)PR_AtomicIncrement(&cvar
->notify_pending
);
330 notified
->cv
[index
].times
= (broadcast
) ? -1 : 1;
331 notified
->cv
[index
].cv
= cvar
;
332 notified
->length
+= 1;
335 PR_ASSERT(PR_TRUE
== cvar
->lock
->locked
);
336 PR_ASSERT(pthread_equal(cvar
->lock
->owner
, pthread_self()));
337 } /* pt_PostNotifyToCvar */
339 PR_IMPLEMENT(PRCondVar
*) PR_NewCondVar(PRLock
*lock
)
341 PRCondVar
*cv
= PR_NEW(PRCondVar
);
342 PR_ASSERT(lock
!= NULL
);
345 int rv
= _PT_PTHREAD_COND_INIT(cv
->cv
, _pt_cvar_attr
);
348 cv
->notify_pending
= 0;
350 pt_debug
.cvars_created
+= 1;
354 } /* PR_NewCondVar */
356 PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar
*cvar
)
358 if (0 > PR_AtomicDecrement(&cvar
->notify_pending
))
360 PRIntn rv
= pthread_cond_destroy(&cvar
->cv
); PR_ASSERT(0 == rv
);
362 memset(cvar
, 0xaf, sizeof(PRCondVar
));
363 pt_debug
.cvars_destroyed
+= 1;
367 } /* PR_DestroyCondVar */
369 PR_IMPLEMENT(PRStatus
) PR_WaitCondVar(PRCondVar
*cvar
, PRIntervalTime timeout
)
372 PRThread
*thred
= PR_GetCurrentThread();
374 PR_ASSERT(cvar
!= NULL
);
375 /* We'd better be locked */
376 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar
->lock
->mutex
));
377 PR_ASSERT(PR_TRUE
== cvar
->lock
->locked
);
378 /* and it better be by us */
379 PR_ASSERT(pthread_equal(cvar
->lock
->owner
, pthread_self()));
381 if (_PT_THREAD_INTERRUPTED(thred
)) goto aborted
;
384 * The thread waiting is used for PR_Interrupt
386 thred
->waiting
= cvar
; /* this is where we're waiting */
389 * If we have pending notifies, post them now.
391 * This is not optimal. We're going to post these notifies
392 * while we're holding the lock. That means on MP systems
393 * that they are going to collide for the lock that we will
394 * hold until we actually wait.
396 if (0 != cvar
->lock
->notified
.length
)
397 pt_PostNotifies(cvar
->lock
, PR_FALSE
);
400 * We're surrendering the lock, so clear out the locked field.
402 cvar
->lock
->locked
= PR_FALSE
;
404 if (timeout
== PR_INTERVAL_NO_TIMEOUT
)
405 rv
= pthread_cond_wait(&cvar
->cv
, &cvar
->lock
->mutex
);
407 rv
= pt_TimedWait(&cvar
->cv
, &cvar
->lock
->mutex
, timeout
);
409 /* We just got the lock back - this better be empty */
410 PR_ASSERT(PR_FALSE
== cvar
->lock
->locked
);
411 cvar
->lock
->locked
= PR_TRUE
;
412 cvar
->lock
->owner
= pthread_self();
414 PR_ASSERT(0 == cvar
->lock
->notified
.length
);
415 thred
->waiting
= NULL
; /* and now we're not */
416 if (_PT_THREAD_INTERRUPTED(thred
)) goto aborted
;
419 _PR_MD_MAP_DEFAULT_ERROR(rv
);
425 PR_SetError(PR_PENDING_INTERRUPT_ERROR
, 0);
426 thred
->state
&= ~PT_THREAD_ABORTED
;
428 } /* PR_WaitCondVar */
430 PR_IMPLEMENT(PRStatus
) PR_NotifyCondVar(PRCondVar
*cvar
)
432 PR_ASSERT(cvar
!= NULL
);
433 pt_PostNotifyToCvar(cvar
, PR_FALSE
);
435 } /* PR_NotifyCondVar */
437 PR_IMPLEMENT(PRStatus
) PR_NotifyAllCondVar(PRCondVar
*cvar
)
439 PR_ASSERT(cvar
!= NULL
);
440 pt_PostNotifyToCvar(cvar
, PR_TRUE
);
442 } /* PR_NotifyAllCondVar */
444 /**************************************************************/
445 /**************************************************************/
446 /***************************MONITORS***************************/
447 /**************************************************************/
448 /**************************************************************/
450 PR_IMPLEMENT(PRMonitor
*) PR_NewMonitor(void)
455 if (!_pr_initialized
) _PR_ImplicitInitialization();
457 cvar
= PR_NEWZAP(PRCondVar
);
460 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
463 mon
= PR_NEWZAP(PRMonitor
);
467 rv
= _PT_PTHREAD_MUTEX_INIT(mon
->lock
.mutex
, _pt_mattr
);
470 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon
->owner
);
473 rv
= _PT_PTHREAD_COND_INIT(mon
->cvar
->cv
, _pt_cvar_attr
);
476 mon
->cvar
->lock
= &mon
->lock
;
485 } /* PR_NewMonitor */
487 PR_IMPLEMENT(PRMonitor
*) PR_NewNamedMonitor(const char* name
)
489 PRMonitor
* mon
= PR_NewMonitor();
495 PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor
*mon
)
498 PR_ASSERT(mon
!= NULL
);
499 PR_DestroyCondVar(mon
->cvar
);
500 rv
= pthread_mutex_destroy(&mon
->lock
.mutex
); PR_ASSERT(0 == rv
);
502 memset(mon
, 0xaf, sizeof(PRMonitor
));
505 } /* PR_DestroyMonitor */
508 /* The GC uses this; it is quite arguably a bad interface. I'm just
509 * duplicating it for now - XXXMB
511 PR_IMPLEMENT(PRIntn
) PR_GetMonitorEntryCount(PRMonitor
*mon
)
513 pthread_t self
= pthread_self();
514 if (pthread_equal(mon
->owner
, self
))
515 return mon
->entryCount
;
519 PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor
*mon
)
521 pthread_t self
= pthread_self();
523 PR_ASSERT(mon
!= NULL
);
525 * This is safe only if mon->owner (a pthread_t) can be
526 * read in one instruction. Perhaps mon->owner should be
529 if (!pthread_equal(mon
->owner
, self
))
532 /* and now I have the lock */
533 PR_ASSERT(0 == mon
->entryCount
);
534 PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon
->owner
));
535 _PT_PTHREAD_COPY_THR_HANDLE(self
, mon
->owner
);
537 mon
->entryCount
+= 1;
538 } /* PR_EnterMonitor */
540 PR_IMPLEMENT(PRStatus
) PR_ExitMonitor(PRMonitor
*mon
)
542 pthread_t self
= pthread_self();
544 PR_ASSERT(mon
!= NULL
);
545 /* The lock better be that - locked */
546 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon
->lock
.mutex
));
547 /* we'd better be the owner */
548 PR_ASSERT(pthread_equal(mon
->owner
, self
));
549 if (!pthread_equal(mon
->owner
, self
))
552 /* if it's locked and we have it, then the entries should be > 0 */
553 PR_ASSERT(mon
->entryCount
> 0);
554 mon
->entryCount
-= 1; /* reduce by one */
555 if (mon
->entryCount
== 0)
557 /* and if it transitioned to zero - unlock */
558 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon
->owner
); /* make the owner unknown */
559 PR_Unlock(&mon
->lock
);
562 } /* PR_ExitMonitor */
564 PR_IMPLEMENT(PRStatus
) PR_Wait(PRMonitor
*mon
, PRIntervalTime timeout
)
567 PRInt16 saved_entries
;
568 pthread_t saved_owner
;
570 PR_ASSERT(mon
!= NULL
);
571 /* we'd better be locked */
572 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon
->lock
.mutex
));
573 /* and the entries better be positive */
574 PR_ASSERT(mon
->entryCount
> 0);
575 /* and it better be by us */
576 PR_ASSERT(pthread_equal(mon
->owner
, pthread_self()));
578 /* tuck these away 'till later */
579 saved_entries
= mon
->entryCount
;
581 _PT_PTHREAD_COPY_THR_HANDLE(mon
->owner
, saved_owner
);
582 _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon
->owner
);
584 rv
= PR_WaitCondVar(mon
->cvar
, timeout
);
586 /* reinstate the intresting information */
587 mon
->entryCount
= saved_entries
;
588 _PT_PTHREAD_COPY_THR_HANDLE(saved_owner
, mon
->owner
);
593 PR_IMPLEMENT(PRStatus
) PR_Notify(PRMonitor
*mon
)
595 PR_ASSERT(NULL
!= mon
);
596 /* we'd better be locked */
597 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon
->lock
.mutex
));
598 /* and the entries better be positive */
599 PR_ASSERT(mon
->entryCount
> 0);
600 /* and it better be by us */
601 PR_ASSERT(pthread_equal(mon
->owner
, pthread_self()));
603 pt_PostNotifyToCvar(mon
->cvar
, PR_FALSE
);
608 PR_IMPLEMENT(PRStatus
) PR_NotifyAll(PRMonitor
*mon
)
610 PR_ASSERT(mon
!= NULL
);
611 /* we'd better be locked */
612 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon
->lock
.mutex
));
613 /* and the entries better be positive */
614 PR_ASSERT(mon
->entryCount
> 0);
615 /* and it better be by us */
616 PR_ASSERT(pthread_equal(mon
->owner
, pthread_self()));
618 pt_PostNotifyToCvar(mon
->cvar
, PR_TRUE
);
623 /**************************************************************/
624 /**************************************************************/
625 /**************************SEMAPHORES**************************/
626 /**************************************************************/
627 /**************************************************************/
628 PR_IMPLEMENT(void) PR_PostSem(PRSemaphore
*semaphore
)
630 static PRBool unwarned
= PR_TRUE
;
631 if (unwarned
) unwarned
= _PR_Obsolete(
632 "PR_PostSem", "locks & condition variables");
633 PR_Lock(semaphore
->cvar
->lock
);
634 PR_NotifyCondVar(semaphore
->cvar
);
635 semaphore
->count
+= 1;
636 PR_Unlock(semaphore
->cvar
->lock
);
639 PR_IMPLEMENT(PRStatus
) PR_WaitSem(PRSemaphore
*semaphore
)
641 PRStatus status
= PR_SUCCESS
;
642 static PRBool unwarned
= PR_TRUE
;
643 if (unwarned
) unwarned
= _PR_Obsolete(
644 "PR_WaitSem", "locks & condition variables");
645 PR_Lock(semaphore
->cvar
->lock
);
646 while ((semaphore
->count
== 0) && (PR_SUCCESS
== status
))
647 status
= PR_WaitCondVar(semaphore
->cvar
, PR_INTERVAL_NO_TIMEOUT
);
648 if (PR_SUCCESS
== status
) semaphore
->count
-= 1;
649 PR_Unlock(semaphore
->cvar
->lock
);
653 PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore
*semaphore
)
655 static PRBool unwarned
= PR_TRUE
;
656 if (unwarned
) unwarned
= _PR_Obsolete(
657 "PR_DestroySem", "locks & condition variables");
658 PR_DestroyLock(semaphore
->cvar
->lock
);
659 PR_DestroyCondVar(semaphore
->cvar
);
660 PR_DELETE(semaphore
);
661 } /* PR_DestroySem */
663 PR_IMPLEMENT(PRSemaphore
*) PR_NewSem(PRUintn value
)
665 PRSemaphore
*semaphore
;
666 static PRBool unwarned
= PR_TRUE
;
667 if (!_pr_initialized
) _PR_ImplicitInitialization();
669 if (unwarned
) unwarned
= _PR_Obsolete(
670 "PR_NewSem", "locks & condition variables");
672 semaphore
= PR_NEWZAP(PRSemaphore
);
673 if (NULL
!= semaphore
)
675 PRLock
*lock
= PR_NewLock();
678 semaphore
->cvar
= PR_NewCondVar(lock
);
679 if (NULL
!= semaphore
->cvar
)
681 semaphore
->count
= value
;
684 PR_DestroyLock(lock
);
686 PR_DELETE(semaphore
);
692 * Define the interprocess named semaphore functions.
693 * There are three implementations:
694 * 1. POSIX semaphore based;
695 * 2. System V semaphore based;
696 * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR).
699 #ifdef _PR_HAVE_POSIX_SEMAPHORES
702 PR_IMPLEMENT(PRSem
*) PR_OpenSemaphore(
709 char osname
[PR_IPC_NAME_SIZE
];
711 if (_PR_MakeNativeIPCName(name
, osname
, sizeof(osname
), _PRIPCSem
)
720 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
724 if (flags
& PR_SEM_CREATE
)
728 if (flags
& PR_SEM_EXCL
) oflag
|= O_EXCL
;
729 sem
->sem
= sem_open(osname
, oflag
, mode
, value
);
734 /* Pass 0 as the mode and value arguments to work around a bug. */
735 sem
->sem
= sem_open(osname
, 0, 0, 0);
737 sem
->sem
= sem_open(osname
, 0);
740 if ((sem_t
*) -1 == sem
->sem
)
742 _PR_MD_MAP_DEFAULT_ERROR(errno
);
749 PR_IMPLEMENT(PRStatus
) PR_WaitSemaphore(PRSem
*sem
)
752 rv
= sem_wait(sem
->sem
);
755 _PR_MD_MAP_DEFAULT_ERROR(errno
);
761 PR_IMPLEMENT(PRStatus
) PR_PostSemaphore(PRSem
*sem
)
764 rv
= sem_post(sem
->sem
);
767 _PR_MD_MAP_DEFAULT_ERROR(errno
);
773 PR_IMPLEMENT(PRStatus
) PR_CloseSemaphore(PRSem
*sem
)
776 rv
= sem_close(sem
->sem
);
779 _PR_MD_MAP_DEFAULT_ERROR(errno
);
786 PR_IMPLEMENT(PRStatus
) PR_DeleteSemaphore(const char *name
)
789 char osname
[PR_IPC_NAME_SIZE
];
791 if (_PR_MakeNativeIPCName(name
, osname
, sizeof(osname
), _PRIPCSem
)
796 rv
= sem_unlink(osname
);
799 _PR_MD_MAP_DEFAULT_ERROR(errno
);
805 #elif defined(_PR_HAVE_SYSV_SEMAPHORES)
811 * From the semctl(2) man page in glibc 2.0
813 #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \
814 || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI)
815 /* union semun is defined by including <sys/sem.h> */
817 /* according to X/OPEN we have to define it ourselves */
820 struct semid_ds
*buf
;
821 unsigned short *array
;
826 * 'a' (97) is the final closing price of NSCP stock.
828 #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */
830 #define NSPR_SEM_MODE 0666
832 PR_IMPLEMENT(PRSem
*) PR_OpenSemaphore(
842 struct semid_ds seminfo
;
845 char osname
[PR_IPC_NAME_SIZE
];
847 if (_PR_MakeNativeIPCName(name
, osname
, sizeof(osname
), _PRIPCSem
)
853 /* Make sure the file exists before calling ftok. */
854 if (flags
& PR_SEM_CREATE
)
856 int osfd
= open(osname
, O_RDWR
|O_CREAT
, mode
);
859 _PR_MD_MAP_OPEN_ERROR(errno
);
862 if (close(osfd
) == -1)
864 _PR_MD_MAP_CLOSE_ERROR(errno
);
868 key
= ftok(osname
, NSPR_IPC_KEY_ID
);
869 if ((key_t
)-1 == key
)
871 _PR_MD_MAP_DEFAULT_ERROR(errno
);
878 PR_SetError(PR_OUT_OF_MEMORY_ERROR
, 0);
882 if (flags
& PR_SEM_CREATE
)
884 sem
->semid
= semget(key
, 1, mode
|IPC_CREAT
|IPC_EXCL
);
887 /* creator of a semaphore is responsible for initializing it */
889 if (semctl(sem
->semid
, 0, SETVAL
, arg
) == -1)
891 _PR_MD_MAP_DEFAULT_ERROR(errno
);
895 /* call semop to set sem_otime to nonzero */
899 if (semop(sem
->semid
, &sop
, 1) == -1)
901 _PR_MD_MAP_DEFAULT_ERROR(errno
);
908 if (errno
!= EEXIST
|| flags
& PR_SEM_EXCL
)
910 _PR_MD_MAP_DEFAULT_ERROR(errno
);
916 sem
->semid
= semget(key
, 1, NSPR_SEM_MODE
);
917 if (sem
->semid
== -1)
919 _PR_MD_MAP_DEFAULT_ERROR(errno
);
923 for (i
= 0; i
< MAX_TRIES
; i
++)
926 semctl(sem
->semid
, 0, IPC_STAT
, arg
);
927 if (seminfo
.sem_otime
!= 0) break;
932 PR_SetError(PR_IO_TIMEOUT_ERROR
, 0);
939 PR_IMPLEMENT(PRStatus
) PR_WaitSemaphore(PRSem
*sem
)
946 if (semop(sem
->semid
, &sop
, 1) == -1)
948 _PR_MD_MAP_DEFAULT_ERROR(errno
);
954 PR_IMPLEMENT(PRStatus
) PR_PostSemaphore(PRSem
*sem
)
961 if (semop(sem
->semid
, &sop
, 1) == -1)
963 _PR_MD_MAP_DEFAULT_ERROR(errno
);
969 PR_IMPLEMENT(PRStatus
) PR_CloseSemaphore(PRSem
*sem
)
975 PR_IMPLEMENT(PRStatus
) PR_DeleteSemaphore(const char *name
)
979 /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */
981 char osname
[PR_IPC_NAME_SIZE
];
983 if (_PR_MakeNativeIPCName(name
, osname
, sizeof(osname
), _PRIPCSem
)
988 key
= ftok(osname
, NSPR_IPC_KEY_ID
);
989 if ((key_t
) -1 == key
)
991 _PR_MD_MAP_DEFAULT_ERROR(errno
);
994 if (unlink(osname
) == -1)
996 _PR_MD_MAP_UNLINK_ERROR(errno
);
999 semid
= semget(key
, 1, NSPR_SEM_MODE
);
1002 _PR_MD_MAP_DEFAULT_ERROR(errno
);
1006 if (semctl(semid
, 0, IPC_RMID
, unused
) == -1)
1008 _PR_MD_MAP_DEFAULT_ERROR(errno
);
1014 #else /* neither POSIX nor System V semaphores are available */
1016 PR_IMPLEMENT(PRSem
*) PR_OpenSemaphore(
1022 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
1026 PR_IMPLEMENT(PRStatus
) PR_WaitSemaphore(PRSem
*sem
)
1028 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
1032 PR_IMPLEMENT(PRStatus
) PR_PostSemaphore(PRSem
*sem
)
1034 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
1038 PR_IMPLEMENT(PRStatus
) PR_CloseSemaphore(PRSem
*sem
)
1040 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
1044 PR_IMPLEMENT(PRStatus
) PR_DeleteSemaphore(const char *name
)
1046 PR_SetError(PR_NOT_IMPLEMENTED_ERROR
, 0);
1050 #endif /* end of interprocess named semaphore functions */
1052 /**************************************************************/
1053 /**************************************************************/
1054 /******************ROUTINES FOR DCE EMULATION******************/
1055 /**************************************************************/
1056 /**************************************************************/
1060 PR_IMPLEMENT(PRStatus
) PRP_TryLock(PRLock
*lock
)
1062 PRIntn rv
= pthread_mutex_trylock(&lock
->mutex
);
1063 if (rv
== PT_TRYLOCK_SUCCESS
)
1065 PR_ASSERT(PR_FALSE
== lock
->locked
);
1066 lock
->locked
= PR_TRUE
;
1067 lock
->owner
= pthread_self();
1069 /* XXX set error code? */
1070 return (PT_TRYLOCK_SUCCESS
== rv
) ? PR_SUCCESS
: PR_FAILURE
;
1073 PR_IMPLEMENT(PRCondVar
*) PRP_NewNakedCondVar(void)
1077 if (!_pr_initialized
) _PR_ImplicitInitialization();
1079 cv
= PR_NEW(PRCondVar
);
1083 rv
= _PT_PTHREAD_COND_INIT(cv
->cv
, _pt_cvar_attr
);
1085 cv
->lock
= _PR_NAKED_CV_LOCK
;
1088 } /* PRP_NewNakedCondVar */
1090 PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar
*cvar
)
1093 rv
= pthread_cond_destroy(&cvar
->cv
); PR_ASSERT(0 == rv
);
1095 memset(cvar
, 0xaf, sizeof(PRCondVar
));
1098 } /* PRP_DestroyNakedCondVar */
1100 PR_IMPLEMENT(PRStatus
) PRP_NakedWait(
1101 PRCondVar
*cvar
, PRLock
*ml
, PRIntervalTime timeout
)
1104 PR_ASSERT(cvar
!= NULL
);
1105 /* XXX do we really want to assert this in a naked wait? */
1106 PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml
->mutex
));
1107 if (timeout
== PR_INTERVAL_NO_TIMEOUT
)
1108 rv
= pthread_cond_wait(&cvar
->cv
, &ml
->mutex
);
1110 rv
= pt_TimedWait(&cvar
->cv
, &ml
->mutex
, timeout
);
1113 _PR_MD_MAP_DEFAULT_ERROR(rv
);
1117 } /* PRP_NakedWait */
1119 PR_IMPLEMENT(PRStatus
) PRP_NakedNotify(PRCondVar
*cvar
)
1122 PR_ASSERT(cvar
!= NULL
);
1123 rv
= pthread_cond_signal(&cvar
->cv
);
1126 } /* PRP_NakedNotify */
1128 PR_IMPLEMENT(PRStatus
) PRP_NakedBroadcast(PRCondVar
*cvar
)
1131 PR_ASSERT(cvar
!= NULL
);
1132 rv
= pthread_cond_broadcast(&cvar
->cv
);
1135 } /* PRP_NakedBroadcast */
1137 #endif /* defined(_PR_PTHREADS) */