PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) { PRStatus rv; PRInt16 saved_entries; pthread_t saved_owner; PR_ASSERT(mon != NULL); /* we'd better be locked */ PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); /* and the entries better be positive */ PR_ASSERT(mon->entryCount > 0); /* and it better be by us */ PR_ASSERT(pthread_equal(mon->owner, pthread_self())); /* tuck these away 'till later */ saved_entries = mon->entryCount; mon->entryCount = 0; _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); rv = PR_WaitCondVar(mon->cvar, timeout); /* reinstate the intresting information */ mon->entryCount = saved_entries; _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); return rv; } /* PR_Wait */
PR_IMPLEMENT(PRStatus) PR_Wait(PRMonitor *mon, PRIntervalTime timeout) { PRStatus rv; PRUint32 saved_entries; pthread_t saved_owner; PR_ASSERT(mon != NULL); rv = pthread_mutex_lock(&mon->lock); PR_ASSERT(0 == rv); /* the entries better be positive */ PR_ASSERT(mon->entryCount > 0); /* and it better be owned by us */ PR_ASSERT(pthread_equal(mon->owner, pthread_self())); /* tuck these away 'till later */ saved_entries = mon->entryCount; mon->entryCount = 0; _PT_PTHREAD_COPY_THR_HANDLE(mon->owner, saved_owner); _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* * If we have pending notifies, post them now. * * This is not optimal. We're going to post these notifies * while we're holding the lock. That means on MP systems * that they are going to collide for the lock that we will * hold until we actually wait. */ if (0 != mon->notifyTimes) { pt_PostNotifiesFromMonitor(&mon->waitCV, mon->notifyTimes); mon->notifyTimes = 0; } rv = pthread_cond_signal(&mon->entryCV); PR_ASSERT(0 == rv); if (timeout == PR_INTERVAL_NO_TIMEOUT) rv = pthread_cond_wait(&mon->waitCV, &mon->lock); else rv = pt_TimedWait(&mon->waitCV, &mon->lock, timeout); PR_ASSERT(0 == rv); while (mon->entryCount != 0) { rv = pthread_cond_wait(&mon->entryCV, &mon->lock); PR_ASSERT(0 == rv); } PR_ASSERT(0 == mon->notifyTimes); /* reinstate the interesting information */ mon->entryCount = saved_entries; _PT_PTHREAD_COPY_THR_HANDLE(saved_owner, mon->owner); rv = pthread_mutex_unlock(&mon->lock); PR_ASSERT(0 == rv); return rv; } /* PR_Wait */
PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) { pthread_t self = pthread_self(); PRIntn rv; PRBool notifyEntryWaiter = PR_FALSE; PRIntn notifyTimes = 0; PR_ASSERT(mon != NULL); rv = pthread_mutex_lock(&mon->lock); PR_ASSERT(0 == rv); /* the entries should be > 0 and we'd better be the owner */ PR_ASSERT(mon->entryCount > 0); PR_ASSERT(pthread_equal(mon->owner, self)); if (mon->entryCount == 0 || !pthread_equal(mon->owner, self)) { rv = pthread_mutex_unlock(&mon->lock); PR_ASSERT(0 == rv); return PR_FAILURE; } mon->entryCount -= 1; /* reduce by one */ if (mon->entryCount == 0) { /* and if it transitioned to zero - notify an entry waiter */ /* make the owner unknown */ _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); notifyEntryWaiter = PR_TRUE; notifyTimes = mon->notifyTimes; mon->notifyTimes = 0; /* We will access the members of 'mon' after unlocking mon->lock. * Add a reference. */ PR_ATOMIC_INCREMENT(&mon->refCount); } rv = pthread_mutex_unlock(&mon->lock); PR_ASSERT(0 == rv); if (notifyEntryWaiter) { if (notifyTimes) pt_PostNotifiesFromMonitor(&mon->waitCV, notifyTimes); rv = pthread_cond_signal(&mon->entryCV); PR_ASSERT(0 == rv); /* We are done accessing the members of 'mon'. Release the * reference. */ PR_DestroyMonitor(mon); } return PR_SUCCESS; } /* PR_ExitMonitor */
PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) { PRMonitor *mon; int rv; if (!_pr_initialized) _PR_ImplicitInitialization(); mon = PR_NEWZAP(PRMonitor); if (mon == NULL) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } rv = _PT_PTHREAD_MUTEX_INIT(mon->lock, _pt_mattr); PR_ASSERT(0 == rv); if (0 != rv) goto error1; _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); rv = _PT_PTHREAD_COND_INIT(mon->entryCV, _pt_cvar_attr); PR_ASSERT(0 == rv); if (0 != rv) goto error2; rv = _PT_PTHREAD_COND_INIT(mon->waitCV, _pt_cvar_attr); PR_ASSERT(0 == rv); if (0 != rv) goto error3; mon->notifyTimes = 0; mon->entryCount = 0; mon->refCount = 1; mon->name = NULL; return mon; error3: pthread_cond_destroy(&mon->entryCV); error2: pthread_mutex_destroy(&mon->lock); error1: PR_Free(mon); PR_SetError(PR_OPERATION_NOT_SUPPORTED_ERROR, 0); return NULL; } /* PR_NewMonitor */
PR_IMPLEMENT(PRStatus) PR_ExitMonitor(PRMonitor *mon) { pthread_t self = pthread_self(); PR_ASSERT(mon != NULL); /* The lock better be that - locked */ PR_ASSERT(_PT_PTHREAD_MUTEX_IS_LOCKED(mon->lock.mutex)); /* we'd better be the owner */ PR_ASSERT(pthread_equal(mon->owner, self)); if (!pthread_equal(mon->owner, self)) return PR_FAILURE; /* if it's locked and we have it, then the entries should be > 0 */ PR_ASSERT(mon->entryCount > 0); mon->entryCount -= 1; /* reduce by one */ if (mon->entryCount == 0) { /* and if it transitioned to zero - unlock */ _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); /* make the owner unknown */ PR_Unlock(&mon->lock); } return PR_SUCCESS; } /* PR_ExitMonitor */
PR_IMPLEMENT(PRMonitor*) PR_NewMonitor(void) { PRMonitor *mon; PRCondVar *cvar; if (!_pr_initialized) _PR_ImplicitInitialization(); cvar = PR_NEWZAP(PRCondVar); if (NULL == cvar) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } mon = PR_NEWZAP(PRMonitor); if (mon != NULL) { int rv; rv = _PT_PTHREAD_MUTEX_INIT(mon->lock.mutex, _pt_mattr); PR_ASSERT(0 == rv); _PT_PTHREAD_INVALIDATE_THR_HANDLE(mon->owner); mon->cvar = cvar; rv = _PT_PTHREAD_COND_INIT(mon->cvar->cv, _pt_cvar_attr); PR_ASSERT(0 == rv); mon->entryCount = 0; mon->cvar->lock = &mon->lock; if (0 != rv) { PR_DELETE(mon); PR_DELETE(cvar); mon = NULL; } } return mon; } /* PR_NewMonitor */