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