andre@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ andre@0: /* This Source Code Form is subject to the terms of the Mozilla Public andre@0: * License, v. 2.0. If a copy of the MPL was not distributed with this andre@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ andre@0: andre@0: /* andre@0: ** File: ptsynch.c andre@0: ** Descritpion: Implemenation for thread synchronization using pthreads andre@0: ** Exports: prlock.h, prcvar.h, prmon.h, prcmon.h andre@0: */ andre@0: andre@0: #if defined(_PR_PTHREADS) andre@0: andre@0: #include "primpl.h" andre@0: #include "obsolete/prsem.h" andre@0: andre@0: #include andre@0: #include andre@0: #include andre@0: andre@0: static pthread_mutexattr_t _pt_mattr; andre@0: static pthread_condattr_t _pt_cvar_attr; andre@0: andre@0: #if defined(DEBUG) andre@0: extern PTDebug pt_debug; /* this is shared between several modules */ andre@0: andre@0: #if defined(_PR_DCETHREADS) andre@0: static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct andre@0: * in DCE threads) to compare with */ andre@0: #endif /* defined(_PR_DCETHREADS) */ andre@0: #endif /* defined(DEBUG) */ andre@0: andre@0: #if defined(FREEBSD) andre@0: /* andre@0: * On older versions of FreeBSD, pthread_mutex_trylock returns EDEADLK. andre@0: * Newer versions return EBUSY. We still need to support both. andre@0: */ andre@0: static int andre@0: pt_pthread_mutex_is_locked(pthread_mutex_t *m) andre@0: { andre@0: int rv = pthread_mutex_trylock(m); andre@0: return (EBUSY == rv || EDEADLK == rv); andre@0: } andre@0: #endif andre@0: andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: /*****************************LOCKS****************************/ andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: andre@0: void _PR_InitLocks(void) andre@0: { andre@0: int rv; andre@0: rv = _PT_PTHREAD_MUTEXATTR_INIT(&_pt_mattr); andre@0: PR_ASSERT(0 == rv); andre@0: andre@0: #ifdef LINUX andre@0: #if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) andre@0: rv = pthread_mutexattr_settype(&_pt_mattr, PTHREAD_MUTEX_ADAPTIVE_NP); andre@0: PR_ASSERT(0 == rv); andre@0: #endif andre@0: #endif andre@0: andre@0: rv = _PT_PTHREAD_CONDATTR_INIT(&_pt_cvar_attr); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: andre@0: static void pt_PostNotifies(PRLock *lock, PRBool unlock) andre@0: { andre@0: PRIntn index, rv; andre@0: _PT_Notified post; andre@0: _PT_Notified *notified, *prev = NULL; andre@0: /* andre@0: * Time to actually notify any conditions that were affected andre@0: * while the lock was held. Get a copy of the list that's in andre@0: * the lock structure and then zero the original. If it's andre@0: * linked to other such structures, we own that storage. andre@0: */ andre@0: post = lock->notified; /* a safe copy; we own the lock */ andre@0: andre@0: #if defined(DEBUG) andre@0: memset(&lock->notified, 0, sizeof(_PT_Notified)); /* reset */ andre@0: #else andre@0: lock->notified.length = 0; /* these are really sufficient */ andre@0: lock->notified.link = NULL; andre@0: #endif andre@0: andre@0: /* should (may) we release lock before notifying? */ andre@0: if (unlock) andre@0: { andre@0: rv = pthread_mutex_unlock(&lock->mutex); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: andre@0: notified = &post; /* this is where we start */ andre@0: do andre@0: { andre@0: for (index = 0; index < notified->length; ++index) andre@0: { andre@0: PRCondVar *cv = notified->cv[index].cv; andre@0: PR_ASSERT(NULL != cv); andre@0: PR_ASSERT(0 != notified->cv[index].times); andre@0: if (-1 == notified->cv[index].times) andre@0: { andre@0: rv = pthread_cond_broadcast(&cv->cv); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: else andre@0: { andre@0: while (notified->cv[index].times-- > 0) andre@0: { andre@0: rv = pthread_cond_signal(&cv->cv); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: } andre@0: #if defined(DEBUG) andre@0: pt_debug.cvars_notified += 1; andre@0: if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) andre@0: { andre@0: pt_debug.delayed_cv_deletes += 1; andre@0: PR_DestroyCondVar(cv); andre@0: } andre@0: #else /* defined(DEBUG) */ andre@0: if (0 > PR_ATOMIC_DECREMENT(&cv->notify_pending)) andre@0: PR_DestroyCondVar(cv); andre@0: #endif /* defined(DEBUG) */ andre@0: } andre@0: prev = notified; andre@0: notified = notified->link; andre@0: if (&post != prev) PR_DELETE(prev); andre@0: } while (NULL != notified); andre@0: } /* pt_PostNotifies */ andre@0: andre@0: PR_IMPLEMENT(PRLock*) PR_NewLock(void) andre@0: { andre@0: PRIntn rv; andre@0: PRLock *lock; andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: lock = PR_NEWZAP(PRLock); andre@0: if (lock != NULL) andre@0: { andre@0: rv = _PT_PTHREAD_MUTEX_INIT(lock->mutex, _pt_mattr); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: #if defined(DEBUG) andre@0: pt_debug.locks_created += 1; andre@0: #endif andre@0: return lock; andre@0: } /* PR_NewLock */ andre@0: andre@0: PR_IMPLEMENT(void) PR_DestroyLock(PRLock *lock) andre@0: { andre@0: PRIntn rv; andre@0: PR_ASSERT(NULL != lock); andre@0: PR_ASSERT(PR_FALSE == lock->locked); andre@0: PR_ASSERT(0 == lock->notified.length); andre@0: PR_ASSERT(NULL == lock->notified.link); andre@0: rv = pthread_mutex_destroy(&lock->mutex); andre@0: PR_ASSERT(0 == rv); andre@0: #if defined(DEBUG) andre@0: memset(lock, 0xaf, sizeof(PRLock)); andre@0: pt_debug.locks_destroyed += 1; andre@0: #endif andre@0: PR_Free(lock); andre@0: } /* PR_DestroyLock */ andre@0: andre@0: PR_IMPLEMENT(void) PR_Lock(PRLock *lock) andre@0: { andre@0: /* Nb: PR_Lock must not call PR_GetCurrentThread to access the |id| or andre@0: * |tid| field of the current thread's PRThread structure because andre@0: * _pt_root calls PR_Lock before setting thred->id and thred->tid. */ andre@0: PRIntn rv; andre@0: PR_ASSERT(lock != NULL); andre@0: rv = pthread_mutex_lock(&lock->mutex); andre@0: PR_ASSERT(0 == rv); andre@0: PR_ASSERT(0 == lock->notified.length); andre@0: PR_ASSERT(NULL == lock->notified.link); andre@0: PR_ASSERT(PR_FALSE == lock->locked); andre@0: /* Nb: the order of the next two statements is not critical to andre@0: * the correctness of PR_AssertCurrentThreadOwnsLock(), but andre@0: * this particular order makes the assertion more likely to andre@0: * catch errors. */ andre@0: lock->owner = pthread_self(); andre@0: lock->locked = PR_TRUE; andre@0: #if defined(DEBUG) andre@0: pt_debug.locks_acquired += 1; andre@0: #endif andre@0: } /* PR_Lock */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_Unlock(PRLock *lock) andre@0: { andre@0: pthread_t self = pthread_self(); andre@0: PRIntn rv; andre@0: andre@0: PR_ASSERT(lock != NULL); andre@0: PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(lock->mutex)); andre@0: PR_ASSERT(PR_TRUE == lock->locked); andre@0: PR_ASSERT(pthread_equal(lock->owner, self)); andre@0: andre@0: if (!lock->locked || !pthread_equal(lock->owner, self)) andre@0: return PR_FAILURE; andre@0: andre@0: lock->locked = PR_FALSE; andre@0: if (0 == lock->notified.length) /* shortcut */ andre@0: { andre@0: rv = pthread_mutex_unlock(&lock->mutex); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: else pt_PostNotifies(lock, PR_TRUE); andre@0: andre@0: #if defined(DEBUG) andre@0: pt_debug.locks_released += 1; andre@0: #endif andre@0: return PR_SUCCESS; andre@0: } /* PR_Unlock */ andre@0: andre@0: PR_IMPLEMENT(void) PR_AssertCurrentThreadOwnsLock(PRLock *lock) andre@0: { andre@0: /* Nb: the order of the |locked| and |owner==me| checks is not critical andre@0: * to the correctness of PR_AssertCurrentThreadOwnsLock(), but andre@0: * this particular order makes the assertion more likely to andre@0: * catch errors. */ andre@0: PR_ASSERT(lock->locked && pthread_equal(lock->owner, pthread_self())); andre@0: } andre@0: andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: /***************************CONDITIONS*************************/ andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: andre@0: andre@0: /* andre@0: * This code is used to compute the absolute time for the wakeup. andre@0: * It's moderately ugly, so it's defined here and called in a andre@0: * couple of places. andre@0: */ andre@0: #define PT_NANOPERMICRO 1000UL andre@0: #define PT_BILLION 1000000000UL andre@0: andre@0: static PRIntn pt_TimedWait( andre@0: pthread_cond_t *cv, pthread_mutex_t *ml, PRIntervalTime timeout) andre@0: { andre@0: int rv; andre@0: struct timeval now; andre@0: struct timespec tmo; andre@0: PRUint32 ticks = PR_TicksPerSecond(); andre@0: andre@0: tmo.tv_sec = (PRInt32)(timeout / ticks); andre@0: tmo.tv_nsec = (PRInt32)(timeout - (tmo.tv_sec * ticks)); andre@0: tmo.tv_nsec = (PRInt32)PR_IntervalToMicroseconds(PT_NANOPERMICRO * tmo.tv_nsec); andre@0: andre@0: /* pthreads wants this in absolute time, off we go ... */ andre@0: (void)GETTIMEOFDAY(&now); andre@0: /* that one's usecs, this one's nsecs - grrrr! */ andre@0: tmo.tv_sec += now.tv_sec; andre@0: tmo.tv_nsec += (PT_NANOPERMICRO * now.tv_usec); andre@0: tmo.tv_sec += tmo.tv_nsec / PT_BILLION; andre@0: tmo.tv_nsec %= PT_BILLION; andre@0: andre@0: rv = pthread_cond_timedwait(cv, ml, &tmo); andre@0: andre@0: /* NSPR doesn't report timeouts */ andre@0: #ifdef _PR_DCETHREADS andre@0: if (rv == -1) return (errno == EAGAIN) ? 0 : errno; andre@0: else return rv; andre@0: #else andre@0: return (rv == ETIMEDOUT) ? 0 : rv; andre@0: #endif andre@0: } /* pt_TimedWait */ andre@0: andre@0: andre@0: /* andre@0: * Notifies just get posted to the protecting mutex. The andre@0: * actual notification is done when the lock is released so that andre@0: * MP systems don't contend for a lock that they can't have. andre@0: */ andre@0: static void pt_PostNotifyToCvar(PRCondVar *cvar, PRBool broadcast) andre@0: { andre@0: PRIntn index = 0; andre@0: _PT_Notified *notified = &cvar->lock->notified; andre@0: andre@0: PR_ASSERT(PR_TRUE == cvar->lock->locked); andre@0: PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); andre@0: PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); andre@0: andre@0: while (1) andre@0: { andre@0: for (index = 0; index < notified->length; ++index) andre@0: { andre@0: if (notified->cv[index].cv == cvar) andre@0: { andre@0: if (broadcast) andre@0: notified->cv[index].times = -1; andre@0: else if (-1 != notified->cv[index].times) andre@0: notified->cv[index].times += 1; andre@0: return; /* we're finished */ andre@0: } andre@0: } andre@0: /* if not full, enter new CV in this array */ andre@0: if (notified->length < PT_CV_NOTIFIED_LENGTH) break; andre@0: andre@0: /* if there's no link, create an empty array and link it */ andre@0: if (NULL == notified->link) andre@0: notified->link = PR_NEWZAP(_PT_Notified); andre@0: notified = notified->link; andre@0: } andre@0: andre@0: /* A brand new entry in the array */ andre@0: (void)PR_ATOMIC_INCREMENT(&cvar->notify_pending); andre@0: notified->cv[index].times = (broadcast) ? -1 : 1; andre@0: notified->cv[index].cv = cvar; andre@0: notified->length += 1; andre@0: } /* pt_PostNotifyToCvar */ andre@0: andre@0: PR_IMPLEMENT(PRCondVar*) PR_NewCondVar(PRLock *lock) andre@0: { andre@0: PRCondVar *cv = PR_NEW(PRCondVar); andre@0: PR_ASSERT(lock != NULL); andre@0: if (cv != NULL) andre@0: { andre@0: int rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); andre@0: PR_ASSERT(0 == rv); andre@0: cv->lock = lock; andre@0: cv->notify_pending = 0; andre@0: #if defined(DEBUG) andre@0: pt_debug.cvars_created += 1; andre@0: #endif andre@0: } andre@0: return cv; andre@0: } /* PR_NewCondVar */ andre@0: andre@0: PR_IMPLEMENT(void) PR_DestroyCondVar(PRCondVar *cvar) andre@0: { andre@0: if (0 > PR_ATOMIC_DECREMENT(&cvar->notify_pending)) andre@0: { andre@0: PRIntn rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); andre@0: #if defined(DEBUG) andre@0: memset(cvar, 0xaf, sizeof(PRCondVar)); andre@0: pt_debug.cvars_destroyed += 1; andre@0: #endif andre@0: PR_Free(cvar); andre@0: } andre@0: } /* PR_DestroyCondVar */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_WaitCondVar(PRCondVar *cvar, PRIntervalTime timeout) andre@0: { andre@0: PRIntn rv; andre@0: PRThread *thred = PR_GetCurrentThread(); andre@0: andre@0: PR_ASSERT(cvar != NULL); andre@0: /* We'd better be locked */ andre@0: PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(cvar->lock->mutex)); andre@0: PR_ASSERT(PR_TRUE == cvar->lock->locked); andre@0: /* and it better be by us */ andre@0: PR_ASSERT(pthread_equal(cvar->lock->owner, pthread_self())); andre@0: andre@0: if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; andre@0: andre@0: /* andre@0: * The thread waiting is used for PR_Interrupt andre@0: */ andre@0: thred->waiting = cvar; /* this is where we're waiting */ andre@0: andre@0: /* andre@0: * If we have pending notifies, post them now. andre@0: * andre@0: * This is not optimal. We're going to post these notifies andre@0: * while we're holding the lock. That means on MP systems andre@0: * that they are going to collide for the lock that we will andre@0: * hold until we actually wait. andre@0: */ andre@0: if (0 != cvar->lock->notified.length) andre@0: pt_PostNotifies(cvar->lock, PR_FALSE); andre@0: andre@0: /* andre@0: * We're surrendering the lock, so clear out the locked field. andre@0: */ andre@0: cvar->lock->locked = PR_FALSE; andre@0: andre@0: if (timeout == PR_INTERVAL_NO_TIMEOUT) andre@0: rv = pthread_cond_wait(&cvar->cv, &cvar->lock->mutex); andre@0: else andre@0: rv = pt_TimedWait(&cvar->cv, &cvar->lock->mutex, timeout); andre@0: andre@0: /* We just got the lock back - this better be empty */ andre@0: PR_ASSERT(PR_FALSE == cvar->lock->locked); andre@0: cvar->lock->locked = PR_TRUE; andre@0: cvar->lock->owner = pthread_self(); andre@0: andre@0: PR_ASSERT(0 == cvar->lock->notified.length); andre@0: thred->waiting = NULL; /* and now we're not */ andre@0: if (_PT_THREAD_INTERRUPTED(thred)) goto aborted; andre@0: if (rv != 0) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(rv); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: andre@0: aborted: andre@0: PR_SetError(PR_PENDING_INTERRUPT_ERROR, 0); andre@0: thred->state &= ~PT_THREAD_ABORTED; andre@0: return PR_FAILURE; andre@0: } /* PR_WaitCondVar */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_NotifyCondVar(PRCondVar *cvar) andre@0: { andre@0: PR_ASSERT(cvar != NULL); andre@0: pt_PostNotifyToCvar(cvar, PR_FALSE); andre@0: return PR_SUCCESS; andre@0: } /* PR_NotifyCondVar */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_NotifyAllCondVar(PRCondVar *cvar) andre@0: { andre@0: PR_ASSERT(cvar != NULL); andre@0: pt_PostNotifyToCvar(cvar, PR_TRUE); andre@0: return PR_SUCCESS; andre@0: } /* PR_NotifyAllCondVar */ andre@0: andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: /***************************MONITORS***************************/ andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: andre@0: /* andre@0: * Notifies just get posted to the monitor. The actual notification is done andre@0: * when the monitor is fully exited so that MP systems don't contend for a andre@0: * monitor that they can't enter. andre@0: */ andre@0: static void pt_PostNotifyToMonitor(PRMonitor *mon, PRBool broadcast) andre@0: { andre@0: PR_ASSERT(NULL != mon); andre@0: PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mon); andre@0: andre@0: /* mon->notifyTimes is protected by the monitor, so we don't need to andre@0: * acquire mon->lock. andre@0: */ andre@0: if (broadcast) andre@0: mon->notifyTimes = -1; andre@0: else if (-1 != mon->notifyTimes) andre@0: mon->notifyTimes += 1; andre@0: } /* pt_PostNotifyToMonitor */ andre@0: andre@0: static void pt_PostNotifiesFromMonitor(pthread_cond_t *cv, PRIntn times) andre@0: { andre@0: PRIntn rv; andre@0: andre@0: /* andre@0: * Time to actually notify any waits that were affected while the monitor andre@0: * was entered. andre@0: */ andre@0: PR_ASSERT(NULL != cv); andre@0: PR_ASSERT(0 != times); andre@0: if (-1 == times) andre@0: { andre@0: rv = pthread_cond_broadcast(cv); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: else andre@0: { andre@0: while (times-- > 0) andre@0: { andre@0: rv = pthread_cond_signal(cv); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: } andre@0: } /* pt_PostNotifiesFromMonitor */ andre@0: andre@0: PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) andre@0: { andre@0: PRMonitor *mon; andre@0: int rv; andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: mon = PR_NEWZAP(PRMonitor); andre@0: if (mon == NULL) andre@0: { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: andre@0: rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr); andre@0: PR_ASSERT(0 == rv); andre@0: if (0 != rv) andre@0: goto error1; andre@0: andre@0: _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); andre@0: andre@0: rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr); andre@0: PR_ASSERT(0 == rv); andre@0: if (0 != rv) andre@0: goto error2; andre@0: andre@0: rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr); andre@0: PR_ASSERT(0 == rv); andre@0: if (0 != rv) andre@0: goto error3; andre@0: andre@0: mon->notifyTimes = 0; andre@0: mon->entryCount = 0; andre@0: mon->refCount = 1; andre@0: mon->name = NULL; andre@0: return mon; andre@0: andre@0: error3: andre@0: pthread_cond_destroy(&mon->entryCV); andre@0: error2: andre@0: pthread_mutex_destroy(&mon->lock); andre@0: error1: andre@0: PR_Free(mon); andre@0: PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); andre@0: return NULL; andre@0: } /* PR_NewMonitor */ andre@0: andre@0: PR_IMPLEMENT(PRMonitor*) PR_NewNamedMonitor(const char* name) andre@0: { andre@0: PRMonitor* mon = PR_NewMonitor(); andre@0: if (mon) andre@0: mon->name = name; andre@0: return mon; andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_DestroyMonitor(PRMonitor *mon) andre@0: { andre@0: int rv; andre@0: andre@0: PR_ASSERT(mon != NULL); andre@0: if (PR_ATOMIC_DECREMENT(&mon->refCount) == 0) andre@0: { andre@0: rv = pthread_cond_destroy(&mon->waitCV); PR_ASSERT(0 == rv); andre@0: rv = pthread_cond_destroy(&mon->entryCV); PR_ASSERT(0 == rv); andre@0: rv = pthread_mutex_destroy(&mon->lock); PR_ASSERT(0 == rv); andre@0: #if defined(DEBUG) andre@0: memset(mon, 0xaf, sizeof(PRMonitor)); andre@0: #endif andre@0: PR_Free(mon); andre@0: } andre@0: } /* PR_DestroyMonitor */ andre@0: andre@0: /* The GC uses this; it is quite arguably a bad interface. I'm just andre@0: * duplicating it for now - XXXMB andre@0: */ andre@0: PR_IMPLEMENT(PRIntn) PR_GetMonitorEntryCount(PRMonitor *mon) andre@0: { andre@0: pthread_t self = pthread_self(); andre@0: PRIntn rv; andre@0: PRIntn count = 0; andre@0: andre@0: rv = pthread_mutex_lock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: if (pthread_equal(mon->owner, self)) andre@0: count = mon->entryCount; andre@0: rv = pthread_mutex_unlock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: return count; andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_AssertCurrentThreadInMonitor(PRMonitor *mon) andre@0: { andre@0: #if defined(DEBUG) || defined(FORCE_PR_ASSERT) andre@0: PRIntn rv; andre@0: andre@0: rv = pthread_mutex_lock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: PR_ASSERT(mon->entryCount != 0 && andre@0: pthread_equal(mon->owner, pthread_self())); andre@0: rv = pthread_mutex_unlock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: #endif andre@0: } andre@0: andre@0: PR_IMPLEMENT(void) PR_EnterMonitor(PRMonitor *mon) andre@0: { andre@0: pthread_t self = pthread_self(); andre@0: PRIntn rv; andre@0: andre@0: PR_ASSERT(mon != NULL); andre@0: rv = pthread_mutex_lock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: if (mon->entryCount != 0) andre@0: { andre@0: if (pthread_equal(mon->owner, self)) andre@0: goto done; andre@0: while (mon->entryCount != 0) andre@0: { andre@0: rv = pthread_cond_wait(&mon->entryCV, &mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: } andre@0: /* and now I have the monitor */ andre@0: PR_ASSERT(0 == mon->notifyTimes); andre@0: PR_ASSERT(_PT_PTHREAD_THR_HANDLE_IS_INVALID(mon->owner)); andre@0: _PT_PTHREAD_COPY_THR_HANDLE(self, mon->owner); andre@0: andre@0: done: andre@0: mon->entryCount += 1; andre@0: rv = pthread_mutex_unlock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: } /* PR_EnterMonitor */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) andre@0: { andre@0: pthread_t self = pthread_self(); andre@0: PRIntn rv; andre@0: PRBool notifyEntryWaiter = PR_FALSE; andre@0: PRIntn notifyTimes = 0; andre@0: andre@0: PR_ASSERT(mon != NULL); andre@0: rv = pthread_mutex_lock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: /* the entries should be > 0 and we'd better be the owner */ andre@0: PR_ASSERT(mon->entryCount > 0); andre@0: PR_ASSERT(pthread_equal(mon->owner, self)); andre@0: if (mon->entryCount == 0 || !pthread_equal(mon->owner, self)) andre@0: { andre@0: rv = pthread_mutex_unlock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: mon->entryCount -= 1; /* reduce by one */ andre@0: if (mon->entryCount == 0) andre@0: { andre@0: /* and if it transitioned to zero - notify an entry waiter */ andre@0: /* make the owner unknown */ andre@0: _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); andre@0: notifyEntryWaiter = PR_TRUE; andre@0: notifyTimes = mon->notifyTimes; andre@0: mon->notifyTimes = 0; andre@0: /* We will access the members of 'mon' after unlocking mon->lock. andre@0: * Add a reference. */ andre@0: PR_ATOMIC_INCREMENT(&mon->refCount); andre@0: } andre@0: rv = pthread_mutex_unlock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: if (notifyEntryWaiter) andre@0: { andre@0: if (notifyTimes) andre@0: pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes); andre@0: rv = pthread_cond_signal(&mon->entryCV); andre@0: PR_ASSERT(0 == rv); andre@0: /* We are done accessing the members of 'mon'. Release the andre@0: * reference. */ andre@0: PR_DestroyMonitor(mon); andre@0: } andre@0: return PR_SUCCESS; andre@0: } /* PR_ExitMonitor */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) andre@0: { andre@0: PRStatus rv; andre@0: PRUint32 saved_entries; andre@0: pthread_t saved_owner; andre@0: andre@0: PR_ASSERT(mon != NULL); andre@0: rv = pthread_mutex_lock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: /* the entries better be positive */ andre@0: PR_ASSERT(mon->entryCount > 0); andre@0: /* and it better be owned by us */ andre@0: PR_ASSERT(pthread_equal(mon->owner, pthread_self())); andre@0: andre@0: /* tuck these away 'till later */ andre@0: saved_entries = mon->entryCount; andre@0: mon->entryCount = 0; andre@0: _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); andre@0: _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); andre@0: /* andre@0: * If we have pending notifies, post them now. andre@0: * andre@0: * This is not optimal. We're going to post these notifies andre@0: * while we're holding the lock. That means on MP systems andre@0: * that they are going to collide for the lock that we will andre@0: * hold until we actually wait. andre@0: */ andre@0: if (0 != mon->notifyTimes) andre@0: { andre@0: pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes); andre@0: mon->notifyTimes = 0; andre@0: } andre@0: rv = pthread_cond_signal(&mon->entryCV); andre@0: PR_ASSERT(0 == rv); andre@0: andre@0: if (timeout == PR_INTERVAL_NO_TIMEOUT) andre@0: rv = pthread_cond_wait(&mon->waitCV, &mon->lock); andre@0: else andre@0: rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout); andre@0: PR_ASSERT(0 == rv); andre@0: andre@0: while (mon->entryCount != 0) andre@0: { andre@0: rv = pthread_cond_wait(&mon->entryCV, &mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: } andre@0: PR_ASSERT(0 == mon->notifyTimes); andre@0: /* reinstate the interesting information */ andre@0: mon->entryCount = saved_entries; andre@0: _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); andre@0: andre@0: rv = pthread_mutex_unlock(&mon->lock); andre@0: PR_ASSERT(0 == rv); andre@0: return rv; andre@0: } /* PR_Wait */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_Notify(PRMonitor *mon) andre@0: { andre@0: pt_PostNotifyToMonitor(mon, PR_FALSE); andre@0: return PR_SUCCESS; andre@0: } /* PR_Notify */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_NotifyAll(PRMonitor *mon) andre@0: { andre@0: pt_PostNotifyToMonitor(mon, PR_TRUE); andre@0: return PR_SUCCESS; andre@0: } /* PR_NotifyAll */ andre@0: andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: /**************************SEMAPHORES**************************/ andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *semaphore) andre@0: { andre@0: static PRBool unwarned = PR_TRUE; andre@0: if (unwarned) unwarned = _PR_Obsolete( andre@0: "PR_PostSem", "locks & condition variables"); andre@0: PR_Lock(semaphore->cvar->lock); andre@0: PR_NotifyCondVar(semaphore->cvar); andre@0: semaphore->count += 1; andre@0: PR_Unlock(semaphore->cvar->lock); andre@0: } /* PR_PostSem */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *semaphore) andre@0: { andre@0: PRStatus status = PR_SUCCESS; andre@0: static PRBool unwarned = PR_TRUE; andre@0: if (unwarned) unwarned = _PR_Obsolete( andre@0: "PR_WaitSem", "locks & condition variables"); andre@0: PR_Lock(semaphore->cvar->lock); andre@0: while ((semaphore->count == 0) && (PR_SUCCESS == status)) andre@0: status = PR_WaitCondVar(semaphore->cvar, PR_INTERVAL_NO_TIMEOUT); andre@0: if (PR_SUCCESS == status) semaphore->count -= 1; andre@0: PR_Unlock(semaphore->cvar->lock); andre@0: return status; andre@0: } /* PR_WaitSem */ andre@0: andre@0: PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *semaphore) andre@0: { andre@0: static PRBool unwarned = PR_TRUE; andre@0: if (unwarned) unwarned = _PR_Obsolete( andre@0: "PR_DestroySem", "locks & condition variables"); andre@0: PR_DestroyLock(semaphore->cvar->lock); andre@0: PR_DestroyCondVar(semaphore->cvar); andre@0: PR_Free(semaphore); andre@0: } /* PR_DestroySem */ andre@0: andre@0: PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) andre@0: { andre@0: PRSemaphore *semaphore; andre@0: static PRBool unwarned = PR_TRUE; andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: if (unwarned) unwarned = _PR_Obsolete( andre@0: "PR_NewSem", "locks & condition variables"); andre@0: andre@0: semaphore = PR_NEWZAP(PRSemaphore); andre@0: if (NULL != semaphore) andre@0: { andre@0: PRLock *lock = PR_NewLock(); andre@0: if (NULL != lock) andre@0: { andre@0: semaphore->cvar = PR_NewCondVar(lock); andre@0: if (NULL != semaphore->cvar) andre@0: { andre@0: semaphore->count = value; andre@0: return semaphore; andre@0: } andre@0: PR_DestroyLock(lock); andre@0: } andre@0: PR_Free(semaphore); andre@0: } andre@0: return NULL; andre@0: } andre@0: andre@0: /* andre@0: * Define the interprocess named semaphore functions. andre@0: * There are three implementations: andre@0: * 1. POSIX semaphore based; andre@0: * 2. System V semaphore based; andre@0: * 3. unsupported (fails with PR_NOT_IMPLEMENTED_ERROR). andre@0: */ andre@0: andre@0: #ifdef _PR_HAVE_POSIX_SEMAPHORES andre@0: #include andre@0: andre@0: PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( andre@0: const char *name, andre@0: PRIntn flags, andre@0: PRIntn mode, andre@0: PRUintn value) andre@0: { andre@0: PRSem *sem; andre@0: char osname[PR_IPC_NAME_SIZE]; andre@0: andre@0: if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) andre@0: == PR_FAILURE) andre@0: { andre@0: return NULL; andre@0: } andre@0: andre@0: sem = PR_NEW(PRSem); andre@0: if (NULL == sem) andre@0: { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: andre@0: if (flags & PR_SEM_CREATE) andre@0: { andre@0: int oflag = O_CREAT; andre@0: andre@0: if (flags & PR_SEM_EXCL) oflag |= O_EXCL; andre@0: sem->sem = sem_open(osname, oflag, mode, value); andre@0: } andre@0: else andre@0: { andre@0: #ifdef HPUX andre@0: /* Pass 0 as the mode and value arguments to work around a bug. */ andre@0: sem->sem = sem_open(osname, 0, 0, 0); andre@0: #else andre@0: sem->sem = sem_open(osname, 0); andre@0: #endif andre@0: } andre@0: if ((sem_t *) -1 == sem->sem) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: PR_Free(sem); andre@0: return NULL; andre@0: } andre@0: return sem; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) andre@0: { andre@0: int rv; andre@0: rv = sem_wait(sem->sem); andre@0: if (0 != rv) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) andre@0: { andre@0: int rv; andre@0: rv = sem_post(sem->sem); andre@0: if (0 != rv) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) andre@0: { andre@0: int rv; andre@0: rv = sem_close(sem->sem); andre@0: if (0 != rv) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: PR_Free(sem); andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) andre@0: { andre@0: int rv; andre@0: char osname[PR_IPC_NAME_SIZE]; andre@0: andre@0: if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) andre@0: == PR_FAILURE) andre@0: { andre@0: return PR_FAILURE; andre@0: } andre@0: rv = sem_unlink(osname); andre@0: if (0 != rv) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: #elif defined(_PR_HAVE_SYSV_SEMAPHORES) andre@0: andre@0: #include andre@0: #include andre@0: andre@0: /* andre@0: * From the semctl(2) man page in glibc 2.0 andre@0: */ andre@0: #if (defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)) \ andre@0: || defined(FREEBSD) || defined(OPENBSD) || defined(BSDI) \ andre@0: || defined(DARWIN) || defined(SYMBIAN) andre@0: /* union semun is defined by including */ andre@0: #else andre@0: /* according to X/OPEN we have to define it ourselves */ andre@0: union semun { andre@0: int val; andre@0: struct semid_ds *buf; andre@0: unsigned short *array; andre@0: }; andre@0: #endif andre@0: andre@0: /* andre@0: * 'a' (97) is the final closing price of NSCP stock. andre@0: */ andre@0: #define NSPR_IPC_KEY_ID 'a' /* the id argument for ftok() */ andre@0: andre@0: #define NSPR_SEM_MODE 0666 andre@0: andre@0: PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( andre@0: const char *name, andre@0: PRIntn flags, andre@0: PRIntn mode, andre@0: PRUintn value) andre@0: { andre@0: PRSem *sem; andre@0: key_t key; andre@0: union semun arg; andre@0: struct sembuf sop; andre@0: struct semid_ds seminfo; andre@0: #define MAX_TRIES 60 andre@0: PRIntn i; andre@0: char osname[PR_IPC_NAME_SIZE]; andre@0: andre@0: if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) andre@0: == PR_FAILURE) andre@0: { andre@0: return NULL; andre@0: } andre@0: andre@0: /* Make sure the file exists before calling ftok. */ andre@0: if (flags & PR_SEM_CREATE) andre@0: { andre@0: int osfd = open(osname, O_RDWR|O_CREAT, mode); andre@0: if (-1 == osfd) andre@0: { andre@0: _PR_MD_MAP_OPEN_ERROR(errno); andre@0: return NULL; andre@0: } andre@0: if (close(osfd) == -1) andre@0: { andre@0: _PR_MD_MAP_CLOSE_ERROR(errno); andre@0: return NULL; andre@0: } andre@0: } andre@0: key = ftok(osname, NSPR_IPC_KEY_ID); andre@0: if ((key_t)-1 == key) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return NULL; andre@0: } andre@0: andre@0: sem = PR_NEW(PRSem); andre@0: if (NULL == sem) andre@0: { andre@0: PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: andre@0: if (flags & PR_SEM_CREATE) andre@0: { andre@0: sem->semid = semget(key, 1, mode|IPC_CREAT|IPC_EXCL); andre@0: if (sem->semid >= 0) andre@0: { andre@0: /* creator of a semaphore is responsible for initializing it */ andre@0: arg.val = 0; andre@0: if (semctl(sem->semid, 0, SETVAL, arg) == -1) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: PR_Free(sem); andre@0: return NULL; andre@0: } andre@0: /* call semop to set sem_otime to nonzero */ andre@0: sop.sem_num = 0; andre@0: sop.sem_op = value; andre@0: sop.sem_flg = 0; andre@0: if (semop(sem->semid, &sop, 1) == -1) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: PR_Free(sem); andre@0: return NULL; andre@0: } andre@0: return sem; andre@0: } andre@0: andre@0: if (errno != EEXIST || flags & PR_SEM_EXCL) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: PR_Free(sem); andre@0: return NULL; andre@0: } andre@0: } andre@0: andre@0: sem->semid = semget(key, 1, NSPR_SEM_MODE); andre@0: if (sem->semid == -1) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: PR_Free(sem); andre@0: return NULL; andre@0: } andre@0: for (i = 0; i < MAX_TRIES; i++) andre@0: { andre@0: arg.buf = &seminfo; andre@0: semctl(sem->semid, 0, IPC_STAT, arg); andre@0: if (seminfo.sem_otime != 0) break; andre@0: sleep(1); andre@0: } andre@0: if (i == MAX_TRIES) andre@0: { andre@0: PR_SetError(PR_IO_TIMEOUT_ERROR, 0); andre@0: PR_Free(sem); andre@0: return NULL; andre@0: } andre@0: return sem; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) andre@0: { andre@0: struct sembuf sop; andre@0: andre@0: sop.sem_num = 0; andre@0: sop.sem_op = -1; andre@0: sop.sem_flg = 0; andre@0: if (semop(sem->semid, &sop, 1) == -1) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) andre@0: { andre@0: struct sembuf sop; andre@0: andre@0: sop.sem_num = 0; andre@0: sop.sem_op = 1; andre@0: sop.sem_flg = 0; andre@0: if (semop(sem->semid, &sop, 1) == -1) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) andre@0: { andre@0: PR_Free(sem); andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) andre@0: { andre@0: key_t key; andre@0: int semid; andre@0: /* On some systems (e.g., glibc 2.0) semctl requires a fourth argument */ andre@0: union semun unused; andre@0: char osname[PR_IPC_NAME_SIZE]; andre@0: andre@0: if (_PR_MakeNativeIPCName(name, osname, sizeof(osname), _PRIPCSem) andre@0: == PR_FAILURE) andre@0: { andre@0: return PR_FAILURE; andre@0: } andre@0: key = ftok(osname, NSPR_IPC_KEY_ID); andre@0: if ((key_t) -1 == key) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: if (unlink(osname) == -1) andre@0: { andre@0: _PR_MD_MAP_UNLINK_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: semid = semget(key, 1, NSPR_SEM_MODE); andre@0: if (-1 == semid) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: unused.val = 0; andre@0: if (semctl(semid, 0, IPC_RMID, unused) == -1) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(errno); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } andre@0: andre@0: #else /* neither POSIX nor System V semaphores are available */ andre@0: andre@0: PR_IMPLEMENT(PRSem *) PR_OpenSemaphore( andre@0: const char *name, andre@0: PRIntn flags, andre@0: PRIntn mode, andre@0: PRUintn value) andre@0: { andre@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); andre@0: return NULL; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_WaitSemaphore(PRSem *sem) andre@0: { andre@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_PostSemaphore(PRSem *sem) andre@0: { andre@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_CloseSemaphore(PRSem *sem) andre@0: { andre@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name) andre@0: { andre@0: PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); andre@0: return PR_FAILURE; andre@0: } andre@0: andre@0: #endif /* end of interprocess named semaphore functions */ andre@0: andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: /******************ROUTINES FOR DCE EMULATION******************/ andre@0: /**************************************************************/ andre@0: /**************************************************************/ andre@0: andre@0: #include "prpdce.h" andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock) andre@0: { andre@0: PRIntn rv = pthread_mutex_trylock(&lock->mutex); andre@0: if (rv == PT_TRYLOCK_SUCCESS) andre@0: { andre@0: PR_ASSERT(PR_FALSE == lock->locked); andre@0: lock->locked = PR_TRUE; andre@0: lock->owner = pthread_self(); andre@0: } andre@0: /* XXX set error code? */ andre@0: return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE; andre@0: } /* PRP_TryLock */ andre@0: andre@0: PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void) andre@0: { andre@0: PRCondVar *cv; andre@0: andre@0: if (!_pr_initialized) _PR_ImplicitInitialization(); andre@0: andre@0: cv = PR_NEW(PRCondVar); andre@0: if (cv != NULL) andre@0: { andre@0: int rv; andre@0: rv = _PT_PTHREAD_COND_INIT(cv->cv, _pt_cvar_attr); andre@0: PR_ASSERT(0 == rv); andre@0: cv->lock = _PR_NAKED_CV_LOCK; andre@0: } andre@0: return cv; andre@0: } /* PRP_NewNakedCondVar */ andre@0: andre@0: PR_IMPLEMENT(void) PRP_DestroyNakedCondVar(PRCondVar *cvar) andre@0: { andre@0: int rv; andre@0: rv = pthread_cond_destroy(&cvar->cv); PR_ASSERT(0 == rv); andre@0: #if defined(DEBUG) andre@0: memset(cvar, 0xaf, sizeof(PRCondVar)); andre@0: #endif andre@0: PR_Free(cvar); andre@0: } /* PRP_DestroyNakedCondVar */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_NakedWait( andre@0: PRCondVar *cvar, PRLock *ml, PRIntervalTime timeout) andre@0: { andre@0: PRIntn rv; andre@0: PR_ASSERT(cvar != NULL); andre@0: /* XXX do we really want to assert this in a naked wait? */ andre@0: PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(ml->mutex)); andre@0: if (timeout == PR_INTERVAL_NO_TIMEOUT) andre@0: rv = pthread_cond_wait(&cvar->cv, &ml->mutex); andre@0: else andre@0: rv = pt_TimedWait(&cvar->cv, &ml->mutex, timeout); andre@0: if (rv != 0) andre@0: { andre@0: _PR_MD_MAP_DEFAULT_ERROR(rv); andre@0: return PR_FAILURE; andre@0: } andre@0: return PR_SUCCESS; andre@0: } /* PRP_NakedWait */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_NakedNotify(PRCondVar *cvar) andre@0: { andre@0: int rv; andre@0: PR_ASSERT(cvar != NULL); andre@0: rv = pthread_cond_signal(&cvar->cv); andre@0: PR_ASSERT(0 == rv); andre@0: return PR_SUCCESS; andre@0: } /* PRP_NakedNotify */ andre@0: andre@0: PR_IMPLEMENT(PRStatus) PRP_NakedBroadcast(PRCondVar *cvar) andre@0: { andre@0: int rv; andre@0: PR_ASSERT(cvar != NULL); andre@0: rv = pthread_cond_broadcast(&cvar->cv); andre@0: PR_ASSERT(0 == rv); andre@0: return PR_SUCCESS; andre@0: } /* PRP_NakedBroadcast */ andre@0: andre@0: #endif /* defined(_PR_PTHREADS) */ andre@0: andre@0: /* ptsynch.c */