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: * pkix_pl_rwlock.c andre@0: * andre@0: * Read/Write Lock Functions andre@0: * andre@0: */ andre@0: andre@0: #include "pkix_pl_rwlock.h" andre@0: andre@0: /* --Private-Functions-------------------------------------------- */ andre@0: andre@0: static PKIX_Error * andre@0: pkix_pl_RWLock_Destroy( andre@0: PKIX_PL_Object *object, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_RWLock* rwlock = NULL; andre@0: andre@0: PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_Destroy"); andre@0: PKIX_NULLCHECK_ONE(object); andre@0: andre@0: PKIX_CHECK(pkix_CheckType(object, PKIX_RWLOCK_TYPE, plContext), andre@0: PKIX_OBJECTNOTRWLOCK); andre@0: andre@0: rwlock = (PKIX_PL_RWLock*) object; andre@0: andre@0: PKIX_RWLOCK_DEBUG("Calling PR_DestroyRWLock)\n"); andre@0: PR_DestroyRWLock(rwlock->lock); andre@0: rwlock->lock = NULL; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: /* andre@0: * FUNCTION: pkix_pl_RWLock_RegisterSelf andre@0: * DESCRIPTION: andre@0: * Registers PKIX_RWLOCK_TYPE and its related functions with systemClasses[] andre@0: * THREAD SAFETY: andre@0: * Not Thread Safe - for performance and complexity reasons andre@0: * andre@0: * Since this function is only called by PKIX_PL_Initialize, which should andre@0: * only be called once, it is acceptable that this function is not andre@0: * thread-safe. andre@0: */ andre@0: PKIX_Error * andre@0: pkix_pl_RWLock_RegisterSelf( andre@0: void *plContext) andre@0: { andre@0: andre@0: extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES]; andre@0: pkix_ClassTable_Entry entry; andre@0: andre@0: PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_RegisterSelf"); andre@0: andre@0: entry.description = "RWLock"; andre@0: entry.objCounter = 0; andre@0: entry.typeObjectSize = sizeof(PKIX_PL_RWLock); andre@0: entry.destructor = pkix_pl_RWLock_Destroy; andre@0: entry.equalsFunction = NULL; andre@0: entry.hashcodeFunction = NULL; andre@0: entry.toStringFunction = NULL; andre@0: entry.comparator = NULL; andre@0: entry.duplicateFunction = NULL; andre@0: andre@0: systemClasses[PKIX_RWLOCK_TYPE] = entry; andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: /* --Public-Functions--------------------------------------------- */ andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_RWLock_Create( andre@0: PKIX_PL_RWLock **pNewLock, andre@0: void *plContext) andre@0: { andre@0: PKIX_PL_RWLock *rwLock = NULL; andre@0: andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_RWLock_Create"); andre@0: PKIX_NULLCHECK_ONE(pNewLock); andre@0: andre@0: PKIX_CHECK(PKIX_PL_Object_Alloc andre@0: (PKIX_RWLOCK_TYPE, andre@0: sizeof (PKIX_PL_RWLock), andre@0: (PKIX_PL_Object **)&rwLock, andre@0: plContext), andre@0: PKIX_ERRORALLOCATINGRWLOCK); andre@0: andre@0: PKIX_RWLOCK_DEBUG("\tCalling PR_NewRWLock)\n"); andre@0: rwLock->lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "PKIX RWLock"); andre@0: andre@0: if (rwLock->lock == NULL) { andre@0: PKIX_DECREF(rwLock); andre@0: PKIX_ERROR(PKIX_OUTOFMEMORY); andre@0: } andre@0: andre@0: rwLock->readCount = 0; andre@0: rwLock->writeLocked = PKIX_FALSE; andre@0: andre@0: *pNewLock = rwLock; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_AcquireReaderLock( andre@0: PKIX_PL_RWLock *lock, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireReaderLock"); andre@0: PKIX_NULLCHECK_ONE(lock); andre@0: andre@0: PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Rlock)\n"); andre@0: (void) PR_RWLock_Rlock(lock->lock); andre@0: andre@0: lock->readCount++; andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_ReleaseReaderLock( andre@0: PKIX_PL_RWLock *lock, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseReaderLock"); andre@0: PKIX_NULLCHECK_ONE(lock); andre@0: andre@0: PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n"); andre@0: (void) PR_RWLock_Unlock(lock->lock); andre@0: andre@0: lock->readCount--; andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_IsReaderLockHeld( andre@0: PKIX_PL_RWLock *lock, andre@0: PKIX_Boolean *pIsHeld, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_IsReaderLockHeld"); andre@0: PKIX_NULLCHECK_TWO(lock, pIsHeld); andre@0: andre@0: *pIsHeld = (lock->readCount > 0)?PKIX_TRUE:PKIX_FALSE; andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_AcquireWriterLock( andre@0: PKIX_PL_RWLock *lock, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireWriterLock"); andre@0: PKIX_NULLCHECK_ONE(lock); andre@0: andre@0: PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Wlock\n"); andre@0: (void) PR_RWLock_Wlock(lock->lock); andre@0: andre@0: if (lock->readCount > 0) { andre@0: PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT); andre@0: } andre@0: andre@0: /* We should never acquire a write lock if the lock is held */ andre@0: lock->writeLocked = PKIX_TRUE; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_ReleaseWriterLock( andre@0: PKIX_PL_RWLock *lock, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseWriterLock"); andre@0: PKIX_NULLCHECK_ONE(lock); andre@0: andre@0: if (lock->readCount > 0) { andre@0: PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT); andre@0: } andre@0: andre@0: PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n"); andre@0: (void) PR_RWLock_Unlock(lock->lock); andre@0: andre@0: /* XXX Need to think about thread safety here */ andre@0: /* There should be a single lock holder */ andre@0: lock->writeLocked = PKIX_FALSE; andre@0: andre@0: cleanup: andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: } andre@0: andre@0: PKIX_Error * andre@0: PKIX_PL_IsWriterLockHeld( andre@0: PKIX_PL_RWLock *lock, andre@0: PKIX_Boolean *pIsHeld, andre@0: void *plContext) andre@0: { andre@0: PKIX_ENTER(RWLOCK, "PKIX_PL_IsWriterLockHeld"); andre@0: PKIX_NULLCHECK_TWO(lock, pIsHeld); andre@0: andre@0: *pIsHeld = lock->writeLocked; andre@0: andre@0: PKIX_RETURN(RWLOCK); andre@0: }