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 #include "primpl.h" 7 #include "obsolete/prsem.h" 8 9 /************************************************************************/ 10 11 /* 12 ** Create a new semaphore. 13 */ PR_NewSem(PRUintn value)14PR_IMPLEMENT(PRSemaphore*) PR_NewSem(PRUintn value) 15 { 16 PRSemaphore *sem; 17 PRCondVar *cvar; 18 PRLock *lock; 19 20 sem = PR_NEWZAP(PRSemaphore); 21 if (sem) { 22 #ifdef HAVE_CVAR_BUILT_ON_SEM 23 _PR_MD_NEW_SEM(&sem->md, value); 24 #else 25 lock = PR_NewLock(); 26 if (!lock) { 27 PR_DELETE(sem); 28 return NULL; 29 } 30 31 cvar = PR_NewCondVar(lock); 32 if (!cvar) { 33 PR_DestroyLock(lock); 34 PR_DELETE(sem); 35 return NULL; 36 } 37 sem->cvar = cvar; 38 sem->count = value; 39 #endif 40 } 41 return sem; 42 } 43 44 /* 45 ** Destroy a semaphore. There must be no thread waiting on the semaphore. 46 ** The caller is responsible for guaranteeing that the semaphore is 47 ** no longer in use. 48 */ PR_DestroySem(PRSemaphore * sem)49PR_IMPLEMENT(void) PR_DestroySem(PRSemaphore *sem) 50 { 51 #ifdef HAVE_CVAR_BUILT_ON_SEM 52 _PR_MD_DESTROY_SEM(&sem->md); 53 #else 54 PR_ASSERT(sem->waiters == 0); 55 56 PR_DestroyLock(sem->cvar->lock); 57 PR_DestroyCondVar(sem->cvar); 58 #endif 59 PR_DELETE(sem); 60 } 61 62 /* 63 ** Wait on a Semaphore. 64 ** 65 ** This routine allows a calling thread to wait or proceed depending upon the 66 ** state of the semahore sem. The thread can proceed only if the counter value 67 ** of the semaphore sem is currently greater than 0. If the value of semaphore 68 ** sem is positive, it is decremented by one and the routine returns immediately 69 ** allowing the calling thread to continue. If the value of semaphore sem is 0, 70 ** the calling thread blocks awaiting the semaphore to be released by another 71 ** thread. 72 ** 73 ** This routine can return PR_PENDING_INTERRUPT if the waiting thread 74 ** has been interrupted. 75 */ PR_WaitSem(PRSemaphore * sem)76PR_IMPLEMENT(PRStatus) PR_WaitSem(PRSemaphore *sem) 77 { 78 PRStatus status = PR_SUCCESS; 79 80 #ifdef HAVE_CVAR_BUILT_ON_SEM 81 return _PR_MD_WAIT_SEM(&sem->md); 82 #else 83 PR_Lock(sem->cvar->lock); 84 while (sem->count == 0) { 85 sem->waiters++; 86 status = PR_WaitCondVar(sem->cvar, PR_INTERVAL_NO_TIMEOUT); 87 sem->waiters--; 88 if (status != PR_SUCCESS) 89 break; 90 } 91 if (status == PR_SUCCESS) 92 sem->count--; 93 PR_Unlock(sem->cvar->lock); 94 #endif 95 96 return (status); 97 } 98 99 /* 100 ** This routine increments the counter value of the semaphore. If other threads 101 ** are blocked for the semaphore, then the scheduler will determine which ONE 102 ** thread will be unblocked. 103 */ PR_PostSem(PRSemaphore * sem)104PR_IMPLEMENT(void) PR_PostSem(PRSemaphore *sem) 105 { 106 #ifdef HAVE_CVAR_BUILT_ON_SEM 107 _PR_MD_POST_SEM(&sem->md); 108 #else 109 PR_Lock(sem->cvar->lock); 110 if (sem->waiters) 111 PR_NotifyCondVar(sem->cvar); 112 sem->count++; 113 PR_Unlock(sem->cvar->lock); 114 #endif 115 } 116 117 #if DEBUG 118 /* 119 ** Returns the value of the semaphore referenced by sem without affecting 120 ** the state of the semaphore. The value represents the semaphore vaule 121 ** at the time of the call, but may not be the actual value when the 122 ** caller inspects it. (FOR DEBUGGING ONLY) 123 */ PR_GetValueSem(PRSemaphore * sem)124PR_IMPLEMENT(PRUintn) PR_GetValueSem(PRSemaphore *sem) 125 { 126 PRUintn rv; 127 128 #ifdef HAVE_CVAR_BUILT_ON_SEM 129 rv = _PR_MD_GET_VALUE_SEM(&sem->md); 130 #else 131 PR_Lock(sem->cvar->lock); 132 rv = sem->count; 133 PR_Unlock(sem->cvar->lock); 134 #endif 135 136 return rv; 137 } 138 #endif 139