Index: mozilla/security/nss/lib/util/nssrwlk.c |
=================================================================== |
--- mozilla/security/nss/lib/util/nssrwlk.c (revision 191424) |
+++ mozilla/security/nss/lib/util/nssrwlk.c (working copy) |
@@ -1,447 +0,0 @@ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
- |
-#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 |
- * |
- */ |
- |
-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". |
-*/ |
-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); |
-} |
- |
-/* |
-** Read-lock the RWLock. |
-*/ |
-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. |
-*/ |
-void |
-NSSRWLock_UnlockRead(NSSRWLock *rwlock) |
-{ |
- 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. |
-*/ |
-void |
-NSSRWLock_LockWrite(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 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. |
-*/ |
-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. */ |
- |
- /* Give preference to waiting writers. */ |
- if (rwlock->rw_waiting_writers > 0) { |
- if (rwlock->rw_reader_locks == 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. */ |
-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 */ |