068ebd719ae63ecfc132efdf46445ea8bbc4d336
[reactos.git] / reactos / drivers / net / tcpip / recmutex / recmutex.c
1 #include <ntddk.h>
2 #include "recmutex.h"
3
4 VOID RecursiveMutexInit( PRECURSIVE_MUTEX RecMutex ) {
5 RtlZeroMemory( RecMutex, sizeof(*RecMutex) );
6 KeInitializeSpinLock( &RecMutex->SpinLock );
7 ExInitializeFastMutex( &RecMutex->Mutex );
8 KeInitializeEvent( &RecMutex->StateLockedEvent,
9 NotificationEvent, FALSE );
10 }
11
12 /* NOTE: When we leave, the FAST_MUTEX must have been released. The result
13 * is that we always exit in the same irql as entering */
14 UINT RecursiveMutexEnter( PRECURSIVE_MUTEX RecMutex, BOOL ToWrite ) {
15 NTSTATUS Status = STATUS_SUCCESS;
16 PVOID CurrentThread = KeGetCurrentThread();
17
18 /* Wait for the previous user to unlock the RecMutex state. There might be
19 * multiple waiters waiting to change the state. We need to check each
20 * time we get the event whether somebody still has the state locked */
21
22 if( !RecMutex ) return FALSE;
23
24 if( CurrentThread == RecMutex->CurrentThread ||
25 (!ToWrite && !RecMutex->Writer) ) {
26 RecMutex->LockCount++;
27 return TRUE;
28 }
29
30 if( KeGetCurrentIrql() == PASSIVE_LEVEL ) {
31 ExAcquireFastMutex( &RecMutex->Mutex );
32 RecMutex->OldIrql = PASSIVE_LEVEL;
33 while( RecMutex->Locked ) {
34 ExReleaseFastMutex( &RecMutex->Mutex );
35 Status = KeWaitForSingleObject( &RecMutex->StateLockedEvent,
36 UserRequest,
37 KernelMode,
38 FALSE,
39 NULL );
40 ExAcquireFastMutex( &RecMutex->Mutex );
41 if( Status == STATUS_SUCCESS ) break;
42 }
43 RecMutex->Locked = TRUE;
44 RecMutex->Writer = ToWrite;
45 RecMutex->CurrentThread = CurrentThread;
46 RecMutex->LockCount++;
47 ExReleaseFastMutex( &RecMutex->Mutex );
48 } else {
49 KeAcquireSpinLock( &RecMutex->SpinLock, &RecMutex->OldIrql );
50 RecMutex->Locked = TRUE;
51 RecMutex->Writer = ToWrite;
52 RecMutex->CurrentThread = CurrentThread;
53 RecMutex->LockCount++;
54 }
55
56 return TRUE;
57 }
58
59 VOID RecursiveMutexLeave( PRECURSIVE_MUTEX RecMutex ) {
60 if( RecMutex->LockCount == 0 ) {
61 return;
62 } else
63 RecMutex->LockCount--;
64
65 if( !RecMutex->LockCount ) {
66 RecMutex->CurrentThread = NULL;
67 if( RecMutex->OldIrql == PASSIVE_LEVEL ) {
68 ExAcquireFastMutex( &RecMutex->Mutex );
69 RecMutex->Locked = FALSE;
70 RecMutex->Writer = FALSE;
71 ExReleaseFastMutex( &RecMutex->Mutex );
72 } else {
73 RecMutex->Locked = FALSE;
74 RecMutex->Writer = FALSE;
75 KeReleaseSpinLock( &RecMutex->SpinLock, RecMutex->OldIrql );
76 }
77
78 RecMutex->OldIrql = PASSIVE_LEVEL;
79 KePulseEvent( &RecMutex->StateLockedEvent, IO_NETWORK_INCREMENT,
80 FALSE );
81 }
82 }
83