⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 prrwlock.c

📁 Netscape NSPR库源码
💻 C
字号:
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//*  * 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 Portable Runtime (NSPR). *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1998-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 "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_DEBUGstatic PRUintn	pr_thread_rwlock_key;			/* TPD key for lock stack */static PRUintn	pr_thread_rwlock_alloc_failed;#define	_PR_RWLOCK_RANK_ORDER_LIMIT	10typedef 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	 */	_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	 */	_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	 */	_PR_UNSET_THREAD_RWLOCK_RANK(rwlock);#endif	return;}#ifndef _PR_RWLOCK_RANK_ORDER_DEBUGvoid _PR_InitRWLocks(void) { }#elsevoid _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;	if ((lock_stack = PR_GetThreadPrivate(pr_thread_rwlock_key)) == NULL)		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);	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 	/* _PR_RWLOCK_RANK_ORDER_DEBUG */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -