diff options
Diffstat (limited to 'security/nss/lib/util/nssrwlk.c')
-rw-r--r-- | security/nss/lib/util/nssrwlk.c | 512 |
1 files changed, 0 insertions, 512 deletions
diff --git a/security/nss/lib/util/nssrwlk.c b/security/nss/lib/util/nssrwlk.c deleted file mode 100644 index 3fac4520c..000000000 --- a/security/nss/lib/util/nssrwlk.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * The contents of this file are subject to the Mozilla Public - * License Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS - * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - * implied. See the License for the specific language governing - * rights and limitations under the License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is Netscape - * Communications Corporation. Portions created by Netscape are - * Copyright (C) 1994-2000 Netscape Communications Corporation. All - * Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the - * terms of the GNU General Public License Version 2 or later (the - * "GPL"), in which case the provisions of the GPL are applicable - * instead of those above. If you wish to allow use of your - * version of this file only under the terms of the GPL and not to - * allow others to use your version of this file under the MPL, - * indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by - * the GPL. If you do not delete the provisions above, a recipient - * may use your version of this file under either the MPL or the - * GPL. - */ - -#include "nssrwlk.h" -#include "nspr.h" - -PR_BEGIN_EXTERN_C - -/* - * Reader-writer lock - */ -struct nssRWLockStr { - PZLock * rw_lock; - char * rw_name; /* lock name */ - PRUint32 rw_rank; /* rank of the lock */ - PRInt32 rw_writer_locks; /* == 0, if unlocked */ - PRInt32 rw_reader_locks; /* == 0, if unlocked */ - /* > 0 , # of read locks */ - PRUint32 rw_waiting_readers; /* number of waiting readers */ - PRUint32 rw_waiting_writers; /* number of waiting writers */ - PZCondVar * rw_reader_waitq; /* cvar for readers */ - PZCondVar * rw_writer_waitq; /* cvar for writers */ - PRThread * rw_owner; /* lock owner for write-lock */ - /* Non-null if write lock held. */ -}; - -PR_END_EXTERN_C - -#include <string.h> - -#ifdef DEBUG_RANK_ORDER -#define NSS_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using - rank-order for locks - */ -#endif - -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - -static PRUintn nss_thread_rwlock_initialized; -static PRUintn nss_thread_rwlock; /* TPD key for lock stack */ -static PRUintn nss_thread_rwlock_alloc_failed; - -#define _NSS_RWLOCK_RANK_ORDER_LIMIT 10 - -typedef struct thread_rwlock_stack { - PRInt32 trs_index; /* top of stack */ - NSSRWLock *trs_stack[_NSS_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock - pointers */ -} thread_rwlock_stack; - -/* forward static declarations. */ -static PRUint32 nssRWLock_GetThreadRank(PRThread *me); -static void nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock); -static void nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock); -static void nssRWLock_ReleaseLockStack(void *lock_stack); - -#endif - -#define UNTIL(x) while(!(x)) - -/* - * Reader/Writer Locks - */ - -/* - * NSSRWLock_New - * Create a reader-writer lock, with the given lock rank and lock name - * - */ - -PR_IMPLEMENT(NSSRWLock *) -NSSRWLock_New(PRUint32 lock_rank, const char *lock_name) -{ - NSSRWLock *rwlock; - - rwlock = PR_NEWZAP(NSSRWLock); - if (rwlock == NULL) - return NULL; - - rwlock->rw_lock = PZ_NewLock(nssILockRWLock); - if (rwlock->rw_lock == NULL) { - goto loser; - } - rwlock->rw_reader_waitq = PZ_NewCondVar(rwlock->rw_lock); - if (rwlock->rw_reader_waitq == NULL) { - goto loser; - } - rwlock->rw_writer_waitq = PZ_NewCondVar(rwlock->rw_lock); - if (rwlock->rw_writer_waitq == NULL) { - goto loser; - } - if (lock_name != NULL) { - rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1); - if (rwlock->rw_name == NULL) { - goto loser; - } - strcpy(rwlock->rw_name, lock_name); - } else { - rwlock->rw_name = NULL; - } - rwlock->rw_rank = lock_rank; - rwlock->rw_waiting_readers = 0; - rwlock->rw_waiting_writers = 0; - rwlock->rw_reader_locks = 0; - rwlock->rw_writer_locks = 0; - - return rwlock; - -loser: - NSSRWLock_Destroy(rwlock); - return(NULL); -} - -/* -** Destroy the given RWLock "lock". -*/ -PR_IMPLEMENT(void) -NSSRWLock_Destroy(NSSRWLock *rwlock) -{ - PR_ASSERT(rwlock != NULL); - PR_ASSERT(rwlock->rw_waiting_readers == 0); - - /* XXX Shouldn't we lock the PZLock before destroying this?? */ - - if (rwlock->rw_name) - PR_Free(rwlock->rw_name); - if (rwlock->rw_reader_waitq) - PZ_DestroyCondVar(rwlock->rw_reader_waitq); - if (rwlock->rw_writer_waitq) - PZ_DestroyCondVar(rwlock->rw_writer_waitq); - if (rwlock->rw_lock) - PZ_DestroyLock(rwlock->rw_lock); - PR_DELETE(rwlock); -} - -/*********************************************************************** -** Given the address of a NULL pointer to a NSSRWLock, -** atomically initializes that pointer to a newly created NSSRWLock. -** Returns the value placed into that pointer, or NULL. -** If the lock cannot be created because of resource constraints, -** the pointer will be left NULL. -** -***********************************************************************/ -PR_IMPLEMENT(NSSRWLock *) -nssRWLock_AtomicCreate( NSSRWLock ** prwlock, - PRUint32 lock_rank, - const char * lock_name) -{ - NSSRWLock * rwlock; - static PRInt32 initializers; - - PR_ASSERT(prwlock != NULL); - - /* atomically initialize the lock */ - while (NULL == (rwlock = *prwlock)) { - PRInt32 myAttempt = PR_AtomicIncrement(&initializers); - if (myAttempt == 1) { - *prwlock = rwlock = NSSRWLock_New(lock_rank, lock_name); - (void) PR_AtomicDecrement(&initializers); - break; - } - PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield() */ - (void) PR_AtomicDecrement(&initializers); - } - - return rwlock; -} - -/* -** Read-lock the RWLock. -*/ -PR_IMPLEMENT(void) -NSSRWLock_LockRead(NSSRWLock *rwlock) -{ - PRThread *me = PR_GetCurrentThread(); - - PZ_Lock(rwlock->rw_lock); -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - - /* - * assert that rank ordering is not violated; the rank of 'rwlock' should - * be equal to or greater than the highest rank of all the locks held by - * the thread. - */ - PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) || - (rwlock->rw_rank >= nssRWLock_GetThreadRank(me))); -#endif - /* - * wait if write-locked or if a writer is waiting; preference for writers - */ - UNTIL ( (rwlock->rw_owner == me) || /* I own it, or */ - ((rwlock->rw_owner == NULL) && /* no-one owns it, and */ - (rwlock->rw_waiting_writers == 0))) { /* no-one is waiting to own */ - - rwlock->rw_waiting_readers++; - PZ_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT); - rwlock->rw_waiting_readers--; - } - rwlock->rw_reader_locks++; /* Increment read-lock count */ - - PZ_Unlock(rwlock->rw_lock); - -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - nssRWLock_SetThreadRank(me, rwlock);/* update thread's lock rank */ -#endif -} - -/* Unlock a Read lock held on this RW lock. -*/ -PR_IMPLEMENT(void) -NSSRWLock_UnlockRead(NSSRWLock *rwlock) -{ - PRThread *me = PR_GetCurrentThread(); - - PZ_Lock(rwlock->rw_lock); - - PR_ASSERT(rwlock->rw_reader_locks > 0); /* lock must be read locked */ - - if (( rwlock->rw_reader_locks > 0) && /* caller isn't screwey */ - (--rwlock->rw_reader_locks == 0) && /* not read locked any more */ - ( rwlock->rw_owner == NULL) && /* not write locked */ - ( rwlock->rw_waiting_writers > 0)) { /* someone's waiting. */ - - PZ_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */ - } - - PZ_Unlock(rwlock->rw_lock); - -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - /* - * update thread's lock rank - */ - nssRWLock_UnsetThreadRank(me, rwlock); -#endif - return; -} - -/* -** Write-lock the RWLock. -*/ -PR_IMPLEMENT(void) -NSSRWLock_LockWrite(NSSRWLock *rwlock) -{ - PRInt32 lock_acquired = 0; - PRThread *me = PR_GetCurrentThread(); - - PZ_Lock(rwlock->rw_lock); -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - /* - * assert that rank ordering is not violated; the rank of 'rwlock' should - * be equal to or greater than the highest rank of all the locks held by - * the thread. - */ - PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) || - (rwlock->rw_rank >= nssRWLock_GetThreadRank(me))); -#endif - /* - * wait if read locked or write locked. - */ - PR_ASSERT(rwlock->rw_reader_locks >= 0); - PR_ASSERT(me != NULL); - - UNTIL ( (rwlock->rw_owner == me) || /* I own write lock, or */ - ((rwlock->rw_owner == NULL) && /* no writer and */ - (rwlock->rw_reader_locks == 0))) { /* no readers, either. */ - - rwlock->rw_waiting_writers++; - PZ_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT); - rwlock->rw_waiting_writers--; - PR_ASSERT(rwlock->rw_reader_locks >= 0); - } - - PR_ASSERT(rwlock->rw_reader_locks == 0); - /* - * apply write lock - */ - rwlock->rw_owner = me; - rwlock->rw_writer_locks++; /* Increment write-lock count */ - - PZ_Unlock(rwlock->rw_lock); - -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - /* - * update thread's lock rank - */ - nssRWLock_SetThreadRank(me,rwlock); -#endif -} - -/* Unlock a Read lock held on this RW lock. -*/ -PR_IMPLEMENT(void) -NSSRWLock_UnlockWrite(NSSRWLock *rwlock) -{ - PRThread *me = PR_GetCurrentThread(); - - PZ_Lock(rwlock->rw_lock); - PR_ASSERT(rwlock->rw_owner == me); /* lock must be write-locked by me. */ - PR_ASSERT(rwlock->rw_writer_locks > 0); /* lock must be write locked */ - - if ( rwlock->rw_owner == me && /* I own it, and */ - rwlock->rw_writer_locks > 0 && /* I own it, and */ - --rwlock->rw_writer_locks == 0) { /* I'm all done with it */ - - rwlock->rw_owner = NULL; /* I don't own it any more. */ - - if (rwlock->rw_reader_locks == 0) { /* no readers, wake up somebody. */ - /* Give preference to waiting writers. */ - if (rwlock->rw_waiting_writers > 0) - PZ_NotifyCondVar(rwlock->rw_writer_waitq); - else if (rwlock->rw_waiting_readers > 0) - PZ_NotifyAllCondVar(rwlock->rw_reader_waitq); - } - } - PZ_Unlock(rwlock->rw_lock); - -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - /* - * update thread's lock rank - */ - nssRWLock_UnsetThreadRank(me, rwlock); -#endif - return; -} - -/* This is primarily for debugging, i.e. for inclusion in ASSERT calls. */ -PR_IMPLEMENT(PRBool) -NSSRWLock_HaveWriteLock(NSSRWLock *rwlock) { - PRBool ownWriteLock; - PRThread *me = PR_GetCurrentThread(); - - /* This lock call isn't really necessary. - ** If this thread is the owner, that fact cannot change during this call, - ** because this thread is in this call. - ** If this thread is NOT the owner, the owner could change, but it - ** could not become this thread. - */ -#if UNNECESSARY - PZ_Lock(rwlock->rw_lock); -#endif - ownWriteLock = (PRBool)(me == rwlock->rw_owner); -#if UNNECESSARY - PZ_Unlock(rwlock->rw_lock); -#endif - return ownWriteLock; -} - -#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG - -/* - * nssRWLock_SetThreadRank - * Set a thread's lock rank, which is the highest of the ranks of all - * the locks held by the thread. Pointers to the locks are added to a - * per-thread list, which is anchored off a thread-private data key. - */ - -static void -nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock) -{ - thread_rwlock_stack *lock_stack; - PRStatus rv; - - /* - * allocated thread-private-data for rwlock list, if not already allocated - */ - if (!nss_thread_rwlock_initialized) { - /* - * allocate tpd, only if not failed already - */ - if (!nss_thread_rwlock_alloc_failed) { - if (PR_NewThreadPrivateIndex(&nss_thread_rwlock, - nssRWLock_ReleaseLockStack) - == PR_FAILURE) { - nss_thread_rwlock_alloc_failed = 1; - return; - } - } else - return; - } - /* - * allocate a lock stack - */ - if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL) { - lock_stack = (thread_rwlock_stack *) - PR_CALLOC(1 * sizeof(thread_rwlock_stack)); - if (lock_stack) { - rv = PR_SetThreadPrivate(nss_thread_rwlock, lock_stack); - if (rv == PR_FAILURE) { - PR_DELETE(lock_stack); - nss_thread_rwlock_alloc_failed = 1; - return; - } - } else { - nss_thread_rwlock_alloc_failed = 1; - return; - } - } - /* - * add rwlock to lock stack, if limit is not exceeded - */ - if (lock_stack) { - if (lock_stack->trs_index < _NSS_RWLOCK_RANK_ORDER_LIMIT) - lock_stack->trs_stack[lock_stack->trs_index++] = rwlock; - } - nss_thread_rwlock_initialized = 1; -} - -static void -nssRWLock_ReleaseLockStack(void *lock_stack) -{ - PR_ASSERT(lock_stack); - PR_DELETE(lock_stack); -} - -/* - * nssRWLock_GetThreadRank - * - * return thread's lock rank. If thread-private-data for the lock - * stack is not allocated, return NSS_RWLOCK_RANK_NONE. - */ - -static PRUint32 -nssRWLock_GetThreadRank(PRThread *me) -{ - thread_rwlock_stack *lock_stack; - - if (nss_thread_rwlock_initialized) { - if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL) - return (NSS_RWLOCK_RANK_NONE); - else - return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank); - - } else - return (NSS_RWLOCK_RANK_NONE); -} - -/* - * nssRWLock_UnsetThreadRank - * - * remove the rwlock from the lock stack. Since locks may not be - * unlocked in a FIFO order, the entire lock stack is searched. - */ - -static void -nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock) -{ - thread_rwlock_stack *lock_stack; - int new_index = 0, index, done = 0; - - if (!nss_thread_rwlock_initialized) - return; - - lock_stack = PR_GetThreadPrivate(nss_thread_rwlock); - - PR_ASSERT(lock_stack != NULL); - - index = lock_stack->trs_index - 1; - while (index-- >= 0) { - if ((lock_stack->trs_stack[index] == rwlock) && !done) { - /* - * reset the slot for rwlock - */ - lock_stack->trs_stack[index] = NULL; - done = 1; - } - /* - * search for the lowest-numbered empty slot, above which there are - * no non-empty slots - */ - if ((lock_stack->trs_stack[index] != NULL) && !new_index) - new_index = index + 1; - if (done && new_index) - break; - } - /* - * set top of stack to highest numbered empty slot - */ - lock_stack->trs_index = new_index; - -} - -#endif /* NSS_RWLOCK_RANK_ORDER_DEBUG */ |