diff nspr/pr/src/threads/prrwlock.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nspr/pr/src/threads/prrwlock.c	Mon Jul 28 10:47:06 2014 +0200
@@ -0,0 +1,483 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 "primpl.h"
+
+#include <string.h>
+
+#if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
+
+#include <pthread.h>
+#define HAVE_UNIX98_RWLOCK
+#define RWLOCK_T pthread_rwlock_t
+#define RWLOCK_INIT(lock) pthread_rwlock_init(lock, NULL)
+#define RWLOCK_DESTROY(lock) pthread_rwlock_destroy(lock)
+#define RWLOCK_RDLOCK(lock) pthread_rwlock_rdlock(lock)
+#define RWLOCK_WRLOCK(lock) pthread_rwlock_wrlock(lock)
+#define RWLOCK_UNLOCK(lock) pthread_rwlock_unlock(lock)
+
+#elif defined(SOLARIS) && (defined(_PR_PTHREADS) \
+        || defined(_PR_GLOBAL_THREADS_ONLY))
+
+#include <synch.h>
+#define HAVE_UI_RWLOCK
+#define RWLOCK_T rwlock_t
+#define RWLOCK_INIT(lock) rwlock_init(lock, USYNC_THREAD, NULL)
+#define RWLOCK_DESTROY(lock) rwlock_destroy(lock)
+#define RWLOCK_RDLOCK(lock) rw_rdlock(lock)
+#define RWLOCK_WRLOCK(lock) rw_wrlock(lock)
+#define RWLOCK_UNLOCK(lock) rw_unlock(lock)
+
+#endif
+
+/*
+ * Reader-writer lock
+ */
+struct PRRWLock {
+	char			*rw_name;			/* lock name					*/
+	PRUint32		rw_rank;			/* rank of the lock				*/
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	RWLOCK_T		rw_lock;
+#else
+    PRLock			*rw_lock;
+	PRInt32			rw_lock_cnt;		/* ==  0, if unlocked			*/
+										/* == -1, if write-locked		*/
+										/* > 0	, # of read locks		*/
+	PRUint32		rw_reader_cnt;		/* number of waiting readers	*/
+	PRUint32		rw_writer_cnt;		/* number of waiting writers	*/
+	PRCondVar   	*rw_reader_waitq;	/* cvar for readers 			*/
+	PRCondVar   	*rw_writer_waitq;	/* cvar for writers				*/
+#ifdef DEBUG
+    PRThread 		*rw_owner;			/* lock owner for write-lock	*/
+#endif
+#endif
+};
+
+#ifdef DEBUG
+#define _PR_RWLOCK_RANK_ORDER_DEBUG	/* enable deadlock detection using
+									   rank-order for locks
+									*/
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+
+static PRUintn	pr_thread_rwlock_key;			/* TPD key for lock stack */
+static PRUintn	pr_thread_rwlock_alloc_failed;
+
+#define	_PR_RWLOCK_RANK_ORDER_LIMIT	10
+
+typedef struct thread_rwlock_stack {
+	PRInt32		trs_index;									/* top of stack */
+	PRRWLock	*trs_stack[_PR_RWLOCK_RANK_ORDER_LIMIT];	/* stack of lock
+														 	   pointers */
+
+} thread_rwlock_stack;
+
+static void _PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
+static PRUint32 _PR_GET_THREAD_RWLOCK_RANK(void);
+static void _PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock);
+static void _PR_RELEASE_LOCK_STACK(void *lock_stack);
+
+#endif
+
+/*
+ * Reader/Writer Locks
+ */
+
+/*
+ * PR_NewRWLock
+ *		Create a reader-writer lock, with the given lock rank and lock name
+ *	
+ */
+
+PR_IMPLEMENT(PRRWLock *)
+PR_NewRWLock(PRUint32 lock_rank, const char *lock_name)
+{
+    PRRWLock *rwlock;
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	int err;
+#endif
+
+    if (!_pr_initialized) _PR_ImplicitInitialization();
+
+    rwlock = PR_NEWZAP(PRRWLock);
+    if (rwlock == NULL)
+		return NULL;
+
+	rwlock->rw_rank = lock_rank;
+	if (lock_name != NULL) {
+		rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
+    	if (rwlock->rw_name == NULL) {
+			PR_DELETE(rwlock);
+			return(NULL);
+		}
+		strcpy(rwlock->rw_name, lock_name);
+	} else {
+		rwlock->rw_name = NULL;
+	}
+	
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_INIT(&rwlock->rw_lock);
+	if (err != 0) {
+		PR_SetError(PR_UNKNOWN_ERROR, err);
+		PR_Free(rwlock->rw_name);
+		PR_DELETE(rwlock);
+		return NULL;
+	}
+	return rwlock;
+#else
+	rwlock->rw_lock = PR_NewLock();
+    if (rwlock->rw_lock == NULL) {
+		goto failed;
+	}
+	rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock);
+    if (rwlock->rw_reader_waitq == NULL) {
+		goto failed;
+	}
+	rwlock->rw_writer_waitq = PR_NewCondVar(rwlock->rw_lock);
+    if (rwlock->rw_writer_waitq == NULL) {
+		goto failed;
+	}
+	rwlock->rw_reader_cnt = 0;
+	rwlock->rw_writer_cnt = 0;
+	rwlock->rw_lock_cnt = 0;
+	return rwlock;
+
+failed:
+	if (rwlock->rw_reader_waitq != NULL) {
+		PR_DestroyCondVar(rwlock->rw_reader_waitq);	
+	}
+	if (rwlock->rw_lock != NULL) {
+		PR_DestroyLock(rwlock->rw_lock);
+	}
+	PR_Free(rwlock->rw_name);
+	PR_DELETE(rwlock);
+	return NULL;
+#endif
+}
+
+/*
+** Destroy the given RWLock "lock".
+*/
+PR_IMPLEMENT(void)
+PR_DestroyRWLock(PRRWLock *rwlock)
+{
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	int err;
+	err = RWLOCK_DESTROY(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_ASSERT(rwlock->rw_reader_cnt == 0);
+	PR_DestroyCondVar(rwlock->rw_reader_waitq);	
+	PR_DestroyCondVar(rwlock->rw_writer_waitq);	
+	PR_DestroyLock(rwlock->rw_lock);
+#endif
+	if (rwlock->rw_name != NULL)
+		PR_Free(rwlock->rw_name);
+    PR_DELETE(rwlock);
+}
+
+/*
+** Read-lock the RWLock.
+*/
+PR_IMPLEMENT(void)
+PR_RWLock_Rlock(PRRWLock *rwlock)
+{
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+int err;
+#endif
+
+#ifdef _PR_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 == PR_RWLOCK_RANK_NONE) || 
+					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
+#endif
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_RDLOCK(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_Lock(rwlock->rw_lock);
+	/*
+	 * wait if write-locked or if a writer is waiting; preference for writers
+	 */
+	while ((rwlock->rw_lock_cnt < 0) ||
+			(rwlock->rw_writer_cnt > 0)) {
+		rwlock->rw_reader_cnt++;
+		PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
+		rwlock->rw_reader_cnt--;
+	}
+	/*
+	 * Increment read-lock count
+	 */
+	rwlock->rw_lock_cnt++;
+
+	PR_Unlock(rwlock->rw_lock);
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * update thread's lock rank
+	 */
+	if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
+		_PR_SET_THREAD_RWLOCK_RANK(rwlock);
+#endif
+}
+
+/*
+** Write-lock the RWLock.
+*/
+PR_IMPLEMENT(void)
+PR_RWLock_Wlock(PRRWLock *rwlock)
+{
+#if defined(DEBUG)
+PRThread *me = PR_GetCurrentThread();
+#endif
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+int err;
+#endif
+
+#ifdef _PR_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 == PR_RWLOCK_RANK_NONE) || 
+					(rwlock->rw_rank >= _PR_GET_THREAD_RWLOCK_RANK()));
+#endif
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_WRLOCK(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_Lock(rwlock->rw_lock);
+	/*
+	 * wait if read locked
+	 */
+	while (rwlock->rw_lock_cnt != 0) {
+		rwlock->rw_writer_cnt++;
+		PR_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
+		rwlock->rw_writer_cnt--;
+	}
+	/*
+	 * apply write lock
+	 */
+	rwlock->rw_lock_cnt--;
+	PR_ASSERT(rwlock->rw_lock_cnt == -1);
+#ifdef DEBUG
+	PR_ASSERT(me != NULL);
+	rwlock->rw_owner = me;
+#endif
+	PR_Unlock(rwlock->rw_lock);
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * update thread's lock rank
+	 */
+	if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
+		_PR_SET_THREAD_RWLOCK_RANK(rwlock);
+#endif
+}
+
+/*
+** Unlock the RW lock.
+*/
+PR_IMPLEMENT(void)
+PR_RWLock_Unlock(PRRWLock *rwlock)
+{
+#if defined(DEBUG)
+PRThread *me = PR_GetCurrentThread();
+#endif
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+int err;
+#endif
+
+#if defined(HAVE_UNIX98_RWLOCK) || defined(HAVE_UI_RWLOCK)
+	err = RWLOCK_UNLOCK(&rwlock->rw_lock);
+	PR_ASSERT(err == 0);
+#else
+	PR_Lock(rwlock->rw_lock);
+	/*
+	 * lock must be read or write-locked
+	 */
+	PR_ASSERT(rwlock->rw_lock_cnt != 0);
+	if (rwlock->rw_lock_cnt > 0) {
+
+		/*
+		 * decrement read-lock count
+		 */
+		rwlock->rw_lock_cnt--;
+		if (rwlock->rw_lock_cnt == 0) {
+			/*
+			 * lock is not read-locked anymore; wakeup a waiting writer
+			 */
+			if (rwlock->rw_writer_cnt > 0)
+				PR_NotifyCondVar(rwlock->rw_writer_waitq);
+		}
+	} else {
+		PR_ASSERT(rwlock->rw_lock_cnt == -1);
+
+		rwlock->rw_lock_cnt = 0;
+#ifdef DEBUG
+    	PR_ASSERT(rwlock->rw_owner == me);
+    	rwlock->rw_owner = NULL;
+#endif
+		/*
+		 * wakeup a writer, if present; preference for writers
+		 */
+		if (rwlock->rw_writer_cnt > 0)
+			PR_NotifyCondVar(rwlock->rw_writer_waitq);
+		/*
+		 * else, wakeup all readers, if any
+		 */
+		else if (rwlock->rw_reader_cnt > 0)
+			PR_NotifyAllCondVar(rwlock->rw_reader_waitq);
+	}
+	PR_Unlock(rwlock->rw_lock);
+#endif
+
+#ifdef _PR_RWLOCK_RANK_ORDER_DEBUG
+	/*
+	 * update thread's lock rank
+	 */
+	if (rwlock->rw_rank != PR_RWLOCK_RANK_NONE)
+		_PR_UNSET_THREAD_RWLOCK_RANK(rwlock);
+#endif
+	return;
+}
+
+#ifndef _PR_RWLOCK_RANK_ORDER_DEBUG
+
+void _PR_InitRWLocks(void) { }
+
+#else
+
+void _PR_InitRWLocks(void)
+{
+	/*
+	 * allocated thread-private-data index for rwlock list
+	 */
+	if (PR_NewThreadPrivateIndex(&pr_thread_rwlock_key,
+			_PR_RELEASE_LOCK_STACK) == PR_FAILURE) {
+		pr_thread_rwlock_alloc_failed = 1;
+		return;
+	}
+}
+
+/*
+ * _PR_SET_THREAD_RWLOCK_RANK
+ *		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
+_PR_SET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
+{
+thread_rwlock_stack *lock_stack;
+PRStatus rv;
+
+	/*
+	 * allocate a lock stack
+	 */
+	if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL) {
+		lock_stack = (thread_rwlock_stack *)
+						PR_CALLOC(1 * sizeof(thread_rwlock_stack));
+		if (lock_stack) {
+			rv = PR_SetThreadPrivate(pr_thread_rwlock_key, lock_stack);
+			if (rv == PR_FAILURE) {
+				PR_DELETE(lock_stack);
+				pr_thread_rwlock_alloc_failed = 1;
+				return;
+			}
+		} else {
+			pr_thread_rwlock_alloc_failed = 1;
+			return;
+		}
+	}
+	/*
+	 * add rwlock to lock stack, if limit is not exceeded
+	 */
+	if (lock_stack) {
+		if (lock_stack->trs_index < _PR_RWLOCK_RANK_ORDER_LIMIT)
+			lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;	
+	}
+}
+
+static void
+_PR_RELEASE_LOCK_STACK(void *lock_stack)
+{
+	PR_ASSERT(lock_stack);
+	PR_DELETE(lock_stack);
+}
+
+/*
+ * _PR_GET_THREAD_RWLOCK_RANK
+ *
+ *		return thread's lock rank. If thread-private-data for the lock
+ *		stack is not allocated, return PR_RWLOCK_RANK_NONE.
+ */
+	
+static PRUint32
+_PR_GET_THREAD_RWLOCK_RANK(void)
+{
+	thread_rwlock_stack *lock_stack;
+
+	lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
+	if (lock_stack == NULL || lock_stack->trs_index == 0)
+		return (PR_RWLOCK_RANK_NONE);
+	else
+		return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
+}
+
+/*
+ * _PR_UNSET_THREAD_RWLOCK_RANK
+ *
+ *		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
+_PR_UNSET_THREAD_RWLOCK_RANK(PRRWLock *rwlock)
+{
+	thread_rwlock_stack *lock_stack;
+	int new_index = 0, index, done = 0;
+
+	lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key);
+
+	PR_ASSERT(lock_stack != NULL);
+
+	for (index = lock_stack->trs_index - 1; index >= 0; index--) {
+		if (!done && (lock_stack->trs_stack[index] == rwlock))  {
+			/*
+			 * 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 (!new_index && (lock_stack->trs_stack[index] != NULL))
+			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 	/* _PR_RWLOCK_RANK_ORDER_DEBUG */
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)