strip whitespace from end of lines
[reactos.git] / reactos / ntoskrnl / ke / mutex.c
1 /*
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...)
6 *
7 * PROGRAMMERS:
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)
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <ntoskrnl.h>
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* FUNCTIONS *****************************************************************/
21
22 /*
23 * @implemented
24 */
25 VOID
26 STDCALL
27 KeInitializeMutant(IN PKMUTANT Mutant,
28 IN BOOLEAN InitialOwner)
29 {
30 ULONG Signaled = TRUE;
31 PKTHREAD CurrentThread = NULL;
32 KIRQL OldIrql;
33
34 DPRINT("KeInitializeMutant: %x\n", Mutant);
35
36 /* Check if we have an initial owner */
37 if (InitialOwner == TRUE) {
38
39 /* In this case, the object is not signaled */
40 Signaled = FALSE;
41
42 /* We also need to associate a thread */
43 CurrentThread = KeGetCurrentThread();
44
45 /* We're about to touch the Thread, so lock the Dispatcher */
46 OldIrql = KeAcquireDispatcherDatabaseLock();
47
48 /* And insert it into its list */
49 InsertTailList(&CurrentThread->MutantListHead, &Mutant->MutantListEntry);
50
51 /* Release Dispatcher Lock */
52 KeReleaseDispatcherDatabaseLock(OldIrql);
53 DPRINT("Mutant with Initial Owner\n");
54
55 } else {
56
57 /* In this case, we don't have an owner yet */
58 Mutant->OwnerThread = NULL;
59 }
60
61 /* Now we set up the Dispatcher Header */
62 KeInitializeDispatcherHeader(&Mutant->Header,
63 MutantObject,
64 sizeof(KMUTANT) / sizeof(ULONG),
65 Signaled);
66
67 /* Initialize the default data */
68 Mutant->OwnerThread = CurrentThread;
69 Mutant->Abandoned = FALSE;
70 Mutant->ApcDisable = 0;
71 }
72
73 /*
74 * @implemented
75 */
76 VOID
77 STDCALL
78 KeInitializeMutex(IN PKMUTEX Mutex,
79 IN ULONG Level)
80 {
81 DPRINT("KeInitializeMutex: %x\n", Mutex);
82
83
84 /* Set up the Dispatcher Header */
85 KeInitializeDispatcherHeader(&Mutex->Header,
86 MutantObject,
87 sizeof(KMUTEX) / sizeof(ULONG),
88 1);
89
90 /* Initialize the default data */
91 Mutex->OwnerThread = NULL;
92 Mutex->Abandoned = FALSE;
93 Mutex->ApcDisable = 1;
94 InitializeListHead(&Mutex->Header.WaitListHead);
95 }
96
97 /*
98 * @implemented
99 */
100 LONG
101 STDCALL
102 KeReadStateMutant(IN PKMUTANT Mutant)
103 {
104 /* Return the Signal State */
105 return(Mutant->Header.SignalState);
106 }
107
108 /*
109 * @implemented
110 */
111 LONG
112 STDCALL
113 KeReadStateMutex(IN PKMUTEX Mutex)
114 {
115 /* Return the Signal State */
116 return(Mutex->Header.SignalState);
117 }
118
119 /*
120 * @implemented
121 */
122 LONG
123 STDCALL
124 KeReleaseMutant(IN PKMUTANT Mutant,
125 IN KPRIORITY Increment,
126 IN BOOLEAN Abandon,
127 IN BOOLEAN Wait)
128 {
129 KIRQL OldIrql;
130 LONG PreviousState;
131 PKTHREAD CurrentThread = KeGetCurrentThread();
132
133 DPRINT("KeReleaseMutant: %x\n", Mutant);
134
135 /* Lock the Dispatcher Database */
136 OldIrql = KeAcquireDispatcherDatabaseLock();
137
138 /* Save the Previous State */
139 PreviousState = Mutant->Header.SignalState;
140
141 /* Check if it is to be abandonned */
142 if (Abandon == FALSE) {
143
144 /* Make sure that the Owner Thread is the current Thread */
145 if (Mutant->OwnerThread != CurrentThread) {
146
147 KeReleaseDispatcherDatabaseLock(OldIrql);
148
149 DPRINT1("Trying to touch a Mutant that the caller doesn't own!\n");
150 ExRaiseStatus(STATUS_MUTANT_NOT_OWNED);
151 }
152
153 /* If the thread owns it, then increase the signal state */
154 Mutant->Header.SignalState++;
155
156 } else {
157
158 /* It's going to be abandonned */
159 DPRINT("Abandonning the Mutant\n");
160 Mutant->Header.SignalState = 1;
161 Mutant->Abandoned = TRUE;
162 }
163
164 /* Check if the signal state is only single */
165 if (Mutant->Header.SignalState == 1) {
166
167 /* Check if it's below 0 now */
168 if (PreviousState <= 0) {
169
170 /* Remove the mutant from the list */
171 DPRINT("Removing Mutant\n");
172 RemoveEntryList(&Mutant->MutantListEntry);
173
174 /* Reenable APCs */
175 DPRINT("Re-enabling APCs\n");
176 CurrentThread->KernelApcDisable += Mutant->ApcDisable;
177
178 /* Force an Interrupt if Apcs are pending */
179 if (!IsListEmpty(&CurrentThread->ApcState.ApcListHead[KernelMode])) {
180
181 /* Make sure they aren't disabled though */
182 if (!CurrentThread->KernelApcDisable) {
183
184 /* Request the Interrupt */
185 DPRINT("Requesting APC Interupt\n");
186 HalRequestSoftwareInterrupt(APC_LEVEL);
187 }
188 }
189 }
190
191 /* Remove the Owning Thread and wake it */
192 Mutant->OwnerThread = NULL;
193
194 /* Check if the Wait List isn't empty */
195 DPRINT("Checking whether to wake the Mutant\n");
196 if (!IsListEmpty(&Mutant->Header.WaitListHead)) {
197
198 /* Wake the Mutant */
199 DPRINT("Waking the Mutant\n");
200 KiWaitTest(&Mutant->Header, Increment);
201 }
202 }
203
204 /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
205 if (Wait == FALSE) {
206
207 /* Release the Lock */
208 KeReleaseDispatcherDatabaseLock(OldIrql);
209
210 } else {
211
212 /* Set a wait */
213 CurrentThread->WaitNext = TRUE;
214 CurrentThread->WaitIrql = OldIrql;
215 }
216
217 /* Return the previous state */
218 return PreviousState;
219 }
220
221 /*
222 * @implemented
223 */
224 LONG
225 STDCALL
226 KeReleaseMutex(IN PKMUTEX Mutex,
227 IN BOOLEAN Wait)
228 {
229
230 /* There's no difference at this level between the two */
231 return KeReleaseMutant(Mutex, IO_NO_INCREMENT, FALSE, Wait);
232 }
233
234 /*
235 * @implemented
236 */
237 NTSTATUS
238 STDCALL
239 KeWaitForMutexObject(IN PKMUTEX Mutex,
240 IN KWAIT_REASON WaitReason,
241 IN KPROCESSOR_MODE WaitMode,
242 IN BOOLEAN Alertable,
243 IN PLARGE_INTEGER Timeout)
244 {
245 /* This is a simple macro. Export the function here though */
246 return KeWaitForSingleObject(Mutex,
247 WaitReason,
248 WaitMode,
249 Alertable,
250 Timeout);
251 }
252
253 /* EOF */