Added simple recursive mutex adapted from my afd one. Works both above

and below DISPATCH_LEVEL.

svn path=/trunk/; revision=11056
This commit is contained in:
Art Yerkes 2004-09-25 21:32:18 +00:00
parent 3a4c09d746
commit 1eb1e27110
3 changed files with 116 additions and 3 deletions

View file

@ -0,0 +1,27 @@
#ifndef _ROSRTL_RECMUTEX_H
#define _ROSRTL_RECMUTEX_H
typedef struct _RECURSIVE_MUTEX {
/* Lock. */
FAST_MUTEX Mutex;
/* Number of times this object was locked */
UINT LockCount;
/* CurrentThread */
PVOID CurrentThread;
/* Notification event which signals that another thread can take over */
KEVENT StateLockedEvent;
/* IRQL from spin lock */
KIRQL OldIrql;
/* Is Locked */
BOOLEAN Locked;
/* Is reader or writer phase */
BOOLEAN Writer;
/* Spin lock needed for */
KSPIN_LOCK SpinLock;
} RECURSIVE_MUTEX, *PRECURSIVE_MUTEX;
extern VOID RecursiveMutexInit( PRECURSIVE_MUTEX RecMutex );
extern UINT RecursiveMutexEnter( PRECURSIVE_MUTEX RecMutex, BOOL ToRead );
extern VOID RecursiveMutexLeave( PRECURSIVE_MUTEX RecMutex );
#endif/*_ROSRTL_RECMUTEX_H*/

View file

@ -1,4 +1,4 @@
# $Id: makefile,v 1.16 2004/09/15 18:57:01 weiden Exp $
# $Id: makefile,v 1.17 2004/09/25 21:32:17 arty Exp $
PATH_TO_TOP = ../..
@ -32,6 +32,8 @@ MISC_OBJECTS = \
FILE_OBJECTS = \
file/sparse.o
RECMUTEX_OBJECTS = recmutex/recmutex.o
include $(PATH_TO_TOP)/config
include makefile.$(ARCH)
@ -43,8 +45,8 @@ TARGET_NAME = rosrtl
TARGET_CFLAGS = -D__USE_W32API -Wall -Werror
TARGET_OBJECTS = $(THREAD_OBJECTS) $(MISC_OBJECTS) $(STRING_OBJECTS) \
$(REGISTRY_OBJECTS) $(FILE_OBJECTS)
$(REGISTRY_OBJECTS) $(FILE_OBJECTS) $(RECMUTEX_OBJECTS)
DEP_OBJECTS = $(TARGET_OBJECTS)
include $(PATH_TO_TOP)/rules.mak

View file

@ -0,0 +1,84 @@
#define NTOS_MODE_USER
#include <ntos.h>
#include <rosrtl/recmutex.h>
VOID RecursiveMutexInit( PRECURSIVE_MUTEX RecMutex ) {
RtlZeroMemory( RecMutex, sizeof(*RecMutex) );
KeInitializeSpinLock( &RecMutex->SpinLock );
ExInitializeFastMutex( &RecMutex->Mutex );
KeInitializeEvent( &RecMutex->StateLockedEvent,
NotificationEvent, FALSE );
}
/* NOTE: When we leave, the FAST_MUTEX must have been released. The result
* is that we always exit in the same irql as entering */
UINT RecursiveMutexEnter( PRECURSIVE_MUTEX RecMutex, BOOL ToWrite ) {
NTSTATUS Status = STATUS_SUCCESS;
PVOID CurrentThread = KeGetCurrentThread();
/* Wait for the previous user to unlock the RecMutex state. There might be
* multiple waiters waiting to change the state. We need to check each
* time we get the event whether somebody still has the state locked */
if( !RecMutex ) return FALSE;
if( CurrentThread == RecMutex->CurrentThread ||
(!ToWrite && !RecMutex->Writer) ) {
RecMutex->LockCount++;
return TRUE;
}
if( KeGetCurrentIrql() == PASSIVE_LEVEL ) {
ExAcquireFastMutex( &RecMutex->Mutex );
RecMutex->OldIrql = PASSIVE_LEVEL;
while( RecMutex->Locked ) {
ExReleaseFastMutex( &RecMutex->Mutex );
Status = KeWaitForSingleObject( &RecMutex->StateLockedEvent,
UserRequest,
KernelMode,
FALSE,
NULL );
ExAcquireFastMutex( &RecMutex->Mutex );
if( Status == STATUS_SUCCESS ) break;
}
RecMutex->Locked = TRUE;
RecMutex->Writer = ToWrite;
RecMutex->CurrentThread = CurrentThread;
RecMutex->LockCount++;
ExReleaseFastMutex( &RecMutex->Mutex );
} else {
KeAcquireSpinLock( &RecMutex->SpinLock, &RecMutex->OldIrql );
RecMutex->Locked = TRUE;
RecMutex->Writer = ToWrite;
RecMutex->CurrentThread = CurrentThread;
RecMutex->LockCount++;
}
return TRUE;
}
VOID RecursiveMutexLeave( PRECURSIVE_MUTEX RecMutex ) {
if( RecMutex->LockCount == 0 ) {
return;
} else
RecMutex->LockCount--;
if( !RecMutex->LockCount ) {
RecMutex->CurrentThread = NULL;
if( RecMutex->OldIrql == PASSIVE_LEVEL ) {
ExAcquireFastMutex( &RecMutex->Mutex );
RecMutex->Locked = FALSE;
RecMutex->Writer = FALSE;
ExReleaseFastMutex( &RecMutex->Mutex );
} else {
RecMutex->Locked = FALSE;
RecMutex->Writer = FALSE;
KeReleaseSpinLock( &RecMutex->SpinLock, RecMutex->OldIrql );
}
RecMutex->OldIrql = PASSIVE_LEVEL;
KePulseEvent( &RecMutex->StateLockedEvent, IO_NETWORK_INCREMENT,
FALSE );
}
}