1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/mutex.c 5 * PURPOSE: Implements the Mutant Dispatcher Object 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* FUNCTIONS *****************************************************************/ 16 17 /* 18 * @implemented 19 */ 20 VOID 21 NTAPI 22 KeInitializeMutant(IN PKMUTANT Mutant, 23 IN BOOLEAN InitialOwner) 24 { 25 PKTHREAD CurrentThread; 26 KIRQL OldIrql; 27 28 /* Check if we have an initial owner */ 29 if (InitialOwner) 30 { 31 /* We also need to associate a thread */ 32 CurrentThread = KeGetCurrentThread(); 33 Mutant->OwnerThread = CurrentThread; 34 35 /* We're about to touch the Thread, so lock the Dispatcher */ 36 OldIrql = KiAcquireDispatcherLock(); 37 38 /* And insert it into its list */ 39 InsertTailList(&CurrentThread->MutantListHead, 40 &Mutant->MutantListEntry); 41 42 /* Release Dispatcher Lock */ 43 KiReleaseDispatcherLock(OldIrql); 44 } 45 else 46 { 47 /* In this case, we don't have an owner yet */ 48 Mutant->OwnerThread = NULL; 49 } 50 51 /* Now we set up the Dispatcher Header */ 52 Mutant->Header.Type = MutantObject; 53 Mutant->Header.Size = sizeof(KMUTANT) / sizeof(ULONG); 54 Mutant->Header.SignalState = InitialOwner ? 0 : 1; 55 InitializeListHead(&(Mutant->Header.WaitListHead)); 56 57 /* Initialize the default data */ 58 Mutant->Abandoned = FALSE; 59 Mutant->ApcDisable = 0; 60 } 61 62 /* 63 * @implemented 64 */ 65 VOID 66 NTAPI 67 KeInitializeMutex(IN PKMUTEX Mutex, 68 IN ULONG Level) 69 { 70 /* Set up the Dispatcher Header */ 71 Mutex->Header.Type = MutantObject; 72 Mutex->Header.Size = sizeof(KMUTEX) / sizeof(ULONG); 73 Mutex->Header.SignalState = 1; 74 InitializeListHead(&(Mutex->Header.WaitListHead)); 75 76 /* Initialize the default data */ 77 Mutex->OwnerThread = NULL; 78 Mutex->Abandoned = FALSE; 79 Mutex->ApcDisable = 1; 80 } 81 82 /* 83 * @implemented 84 */ 85 LONG 86 NTAPI 87 KeReadStateMutant(IN PKMUTANT Mutant) 88 { 89 /* Return the Signal State */ 90 return Mutant->Header.SignalState; 91 } 92 93 /* 94 * @implemented 95 */ 96 LONG 97 NTAPI 98 KeReleaseMutant(IN PKMUTANT Mutant, 99 IN KPRIORITY Increment, 100 IN BOOLEAN Abandon, 101 IN BOOLEAN Wait) 102 { 103 KIRQL OldIrql; 104 LONG PreviousState; 105 PKTHREAD CurrentThread = KeGetCurrentThread(); 106 BOOLEAN EnableApc = FALSE; 107 ASSERT_MUTANT(Mutant); 108 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 109 110 /* Lock the Dispatcher Database */ 111 OldIrql = KiAcquireDispatcherLock(); 112 113 /* Save the Previous State */ 114 PreviousState = Mutant->Header.SignalState; 115 116 /* Check if it is to be abandonned */ 117 if (Abandon == FALSE) 118 { 119 /* Make sure that the Owner Thread is the current Thread */ 120 if (Mutant->OwnerThread != CurrentThread) 121 { 122 /* Release the lock */ 123 KiReleaseDispatcherLock(OldIrql); 124 125 /* Raise an exception */ 126 ExRaiseStatus(Mutant->Abandoned ? STATUS_ABANDONED : 127 STATUS_MUTANT_NOT_OWNED); 128 } 129 130 /* If the thread owns it, then increase the signal state */ 131 Mutant->Header.SignalState++; 132 } 133 else 134 { 135 /* It's going to be abandonned */ 136 Mutant->Header.SignalState = 1; 137 Mutant->Abandoned = TRUE; 138 } 139 140 /* Check if the signal state is only single */ 141 if (Mutant->Header.SignalState == 1) 142 { 143 /* Check if it's below 0 now */ 144 if (PreviousState <= 0) 145 { 146 /* Remove the mutant from the list */ 147 RemoveEntryList(&Mutant->MutantListEntry); 148 149 /* Save if we need to re-enable APCs */ 150 EnableApc = Mutant->ApcDisable; 151 } 152 153 /* Remove the Owning Thread and wake it */ 154 Mutant->OwnerThread = NULL; 155 156 /* Check if the Wait List isn't empty */ 157 if (!IsListEmpty(&Mutant->Header.WaitListHead)) 158 { 159 /* Wake the Mutant */ 160 KiWaitTest(&Mutant->Header, Increment); 161 } 162 } 163 164 /* Check if the caller wants to wait after this release */ 165 if (Wait == FALSE) 166 { 167 /* Release the Lock */ 168 KiReleaseDispatcherLock(OldIrql); 169 } 170 else 171 { 172 /* Set a wait */ 173 CurrentThread->WaitNext = TRUE; 174 CurrentThread->WaitIrql = OldIrql; 175 } 176 177 /* Check if we need to re-enable APCs */ 178 if (EnableApc) KeLeaveCriticalRegion(); 179 180 /* Return the previous state */ 181 return PreviousState; 182 } 183 184 /* 185 * @implemented 186 */ 187 LONG 188 NTAPI 189 KeReleaseMutex(IN PKMUTEX Mutex, 190 IN BOOLEAN Wait) 191 { 192 ASSERT_MUTANT(Mutex); 193 194 /* There's no difference at this level between the two */ 195 return KeReleaseMutant(Mutex, 1, FALSE, Wait); 196 } 197 198 /* EOF */ 199