2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/mutex.c
5 * PURPOSE: Implements Mutexes and Mutants (that silly davec...)
8 * Alex Ionescu (alex@relsoft.net) - Reorganized/commented some of the code.
9 * Simplified some functions, fixed some return values and
10 * corrected some minor bugs, added debug output.
11 * David Welch (welch@mcmail.com)
14 /* INCLUDES *****************************************************************/
18 #include <internal/debug.h>
20 /* FUNCTIONS *****************************************************************/
27 KeInitializeMutant(IN PKMUTANT Mutant
,
28 IN BOOLEAN InitialOwner
)
30 ULONG Signaled
= TRUE
;
31 PKTHREAD CurrentThread
= NULL
;
34 DPRINT("KeInitializeMutant: %x\n", Mutant
);
36 /* Check if we have an initial owner */
37 if (InitialOwner
== TRUE
) {
39 /* In this case, the object is not signaled */
42 /* We also need to associate a thread */
43 CurrentThread
= KeGetCurrentThread();
45 /* We're about to touch the Thread, so lock the Dispatcher */
46 OldIrql
= KeAcquireDispatcherDatabaseLock();
48 /* And insert it into its list */
49 InsertTailList(&CurrentThread
->MutantListHead
, &Mutant
->MutantListEntry
);
51 /* Release Dispatcher Lock */
52 KeReleaseDispatcherDatabaseLock(OldIrql
);
53 DPRINT("Mutant with Initial Owner\n");
57 /* In this case, we don't have an owner yet */
58 Mutant
->OwnerThread
= NULL
;
61 /* Now we set up the Dispatcher Header */
62 KeInitializeDispatcherHeader(&Mutant
->Header
,
64 sizeof(KMUTANT
) / sizeof(ULONG
),
67 /* Initialize the default data */
68 Mutant
->OwnerThread
= CurrentThread
;
69 Mutant
->Abandoned
= FALSE
;
70 Mutant
->ApcDisable
= 0;
78 KeInitializeMutex(IN PKMUTEX Mutex
,
81 DPRINT("KeInitializeMutex: %x\n", Mutex
);
84 /* Set up the Dispatcher Header */
85 KeInitializeDispatcherHeader(&Mutex
->Header
,
87 sizeof(KMUTEX
) / sizeof(ULONG
),
90 /* Initialize the default data */
91 Mutex
->OwnerThread
= NULL
;
92 Mutex
->Abandoned
= FALSE
;
93 Mutex
->ApcDisable
= 1;
94 InitializeListHead(&Mutex
->Header
.WaitListHead
);
102 KeReadStateMutant(IN PKMUTANT Mutant
)
104 /* Return the Signal State */
105 return(Mutant
->Header
.SignalState
);
113 KeReadStateMutex(IN PKMUTEX Mutex
)
115 /* Return the Signal State */
116 return(Mutex
->Header
.SignalState
);
124 KeReleaseMutant(IN PKMUTANT Mutant
,
125 IN KPRIORITY Increment
,
131 PKTHREAD CurrentThread
= KeGetCurrentThread();
133 DPRINT("KeReleaseMutant: %x\n", Mutant
);
135 /* Lock the Dispatcher Database */
136 OldIrql
= KeAcquireDispatcherDatabaseLock();
138 /* Save the Previous State */
139 PreviousState
= Mutant
->Header
.SignalState
;
141 /* Check if it is to be abandonned */
142 if (Abandon
== FALSE
) {
144 /* Make sure that the Owner Thread is the current Thread */
145 if (Mutant
->OwnerThread
!= CurrentThread
) {
147 KeReleaseDispatcherDatabaseLock(OldIrql
);
149 DPRINT1("Trying to touch a Mutant that the caller doesn't own!\n");
150 ExRaiseStatus(STATUS_MUTANT_NOT_OWNED
);
153 /* If the thread owns it, then increase the signal state */
154 Mutant
->Header
.SignalState
++;
158 /* It's going to be abandonned */
159 DPRINT("Abandonning the Mutant\n");
160 Mutant
->Header
.SignalState
= 1;
161 Mutant
->Abandoned
= TRUE
;
164 /* Check if the signal state is only single */
165 if (Mutant
->Header
.SignalState
== 1) {
167 /* Check if it's below 0 now */
168 if (PreviousState
<= 0) {
170 /* Remove the mutant from the list */
171 DPRINT("Removing Mutant\n");
172 RemoveEntryList(&Mutant
->MutantListEntry
);
175 DPRINT("Re-enabling APCs\n");
176 CurrentThread
->KernelApcDisable
+= Mutant
->ApcDisable
;
178 /* Force an Interrupt if Apcs are pending */
179 if (!IsListEmpty(&CurrentThread
->ApcState
.ApcListHead
[KernelMode
])) {
181 /* Make sure they aren't disabled though */
182 if (!CurrentThread
->KernelApcDisable
) {
184 /* Request the Interrupt */
185 DPRINT("Requesting APC Interupt\n");
186 HalRequestSoftwareInterrupt(APC_LEVEL
);
191 /* Remove the Owning Thread and wake it */
192 Mutant
->OwnerThread
= NULL
;
194 /* Check if the Wait List isn't empty */
195 DPRINT("Checking whether to wake the Mutant\n");
196 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
)) {
198 /* Wake the Mutant */
199 DPRINT("Waking the Mutant\n");
200 KiWaitTest(&Mutant
->Header
, Increment
);
204 /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
207 /* Release the Lock */
208 KeReleaseDispatcherDatabaseLock(OldIrql
);
213 CurrentThread
->WaitNext
= TRUE
;
214 CurrentThread
->WaitIrql
= OldIrql
;
217 /* Return the previous state */
218 return PreviousState
;
226 KeReleaseMutex(IN PKMUTEX Mutex
,
230 /* There's no difference at this level between the two */
231 return KeReleaseMutant(Mutex
, IO_NO_INCREMENT
, FALSE
, Wait
);
239 KeWaitForMutexObject(IN PKMUTEX Mutex
,
240 IN KWAIT_REASON WaitReason
,
241 IN KPROCESSOR_MODE WaitMode
,
242 IN BOOLEAN Alertable
,
243 IN PLARGE_INTEGER Timeout
)
245 /* This is a simple macro. Export the function here though */
246 return KeWaitForSingleObject(Mutex
,