a74e7626dec8d1660dfa05c236b02bd9012c21e4
[reactos.git] / reactos / ntoskrnl / ex / mutant.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/mutant.c
5 * PURPOSE: Executive Management of Mutants
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Thomas Weidenmueller
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, ExpInitializeMutantImplementation)
18 #endif
19
20 /* DATA **********************************************************************/
21
22 POBJECT_TYPE ExMutantObjectType = NULL;
23
24 GENERIC_MAPPING ExpMutantMapping =
25 {
26 STANDARD_RIGHTS_READ | SYNCHRONIZE | MUTANT_QUERY_STATE,
27 STANDARD_RIGHTS_WRITE | SYNCHRONIZE,
28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | MUTANT_QUERY_STATE,
29 MUTANT_ALL_ACCESS
30 };
31
32 static const INFORMATION_CLASS_INFO ExMutantInfoClass[] =
33 {
34 /* MutantBasicInformation */
35 ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
36 };
37
38 /* FUNCTIONS *****************************************************************/
39
40 VOID
41 NTAPI
42 ExpDeleteMutant(PVOID ObjectBody)
43 {
44 DPRINT("ExpDeleteMutant(ObjectBody 0x%p)\n", ObjectBody);
45
46 /* Make sure to release the Mutant */
47 KeReleaseMutant((PKMUTANT)ObjectBody,
48 MUTANT_INCREMENT,
49 TRUE,
50 FALSE);
51 }
52
53 VOID
54 INIT_FUNCTION
55 NTAPI
56 ExpInitializeMutantImplementation(VOID)
57 {
58 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
59 UNICODE_STRING Name;
60 DPRINT("Creating Mutant Object Type\n");
61
62 /* Create the Event Pair Object Type */
63 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
64 RtlInitUnicodeString(&Name, L"Mutant");
65 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
66 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KMUTANT);
67 ObjectTypeInitializer.GenericMapping = ExpMutantMapping;
68 ObjectTypeInitializer.PoolType = NonPagedPool;
69 ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
70 ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
71 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExMutantObjectType);
72 }
73
74 /*
75 * @implemented
76 */
77 NTSTATUS
78 NTAPI
79 NtCreateMutant(OUT PHANDLE MutantHandle,
80 IN ACCESS_MASK DesiredAccess,
81 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
82 IN BOOLEAN InitialOwner)
83 {
84 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
85 HANDLE hMutant;
86 PKMUTANT Mutant;
87 NTSTATUS Status = STATUS_SUCCESS;
88 PAGED_CODE();
89 DPRINT("NtCreateMutant(0x%p, 0x%x, 0x%p)\n",
90 MutantHandle, DesiredAccess, ObjectAttributes);
91
92 /* Check if we were called from user-mode */
93 if(PreviousMode != KernelMode)
94 {
95 /* Enter SEH Block */
96 _SEH_TRY
97 {
98 /* Check handle pointer */
99 ProbeForWriteHandle(MutantHandle);
100 }
101 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
102 {
103 Status = _SEH_GetExceptionCode();
104 }
105 _SEH_END;
106
107 /* Bail out if pointer was invalid */
108 if(!NT_SUCCESS(Status)) return Status;
109 }
110
111 /* Create the Mutant Object*/
112 Status = ObCreateObject(PreviousMode,
113 ExMutantObjectType,
114 ObjectAttributes,
115 PreviousMode,
116 NULL,
117 sizeof(KMUTANT),
118 0,
119 0,
120 (PVOID*)&Mutant);
121
122 /* Check for success */
123 if(NT_SUCCESS(Status))
124 {
125 /* Initalize the Kernel Mutant */
126 DPRINT("Initializing the Mutant\n");
127 KeInitializeMutant(Mutant, InitialOwner);
128
129 /* Insert the Object */
130 Status = ObInsertObject((PVOID)Mutant,
131 NULL,
132 DesiredAccess,
133 0,
134 NULL,
135 &hMutant);
136 ObDereferenceObject(Mutant);
137
138 /* Check for success */
139 if(NT_SUCCESS(Status))
140 {
141 /* Enter SEH for return */
142 _SEH_TRY
143 {
144 /* Return the handle to the caller */
145 *MutantHandle = hMutant;
146 }
147 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
148 {
149 Status = _SEH_GetExceptionCode();
150 }
151 _SEH_END;
152 }
153 }
154
155 /* Return Status */
156 return Status;
157 }
158
159 /*
160 * @implemented
161 */
162 NTSTATUS
163 NTAPI
164 NtOpenMutant(OUT PHANDLE MutantHandle,
165 IN ACCESS_MASK DesiredAccess,
166 IN POBJECT_ATTRIBUTES ObjectAttributes)
167 {
168 HANDLE hMutant;
169 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
170 NTSTATUS Status = STATUS_SUCCESS;
171 PAGED_CODE();
172 DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n",
173 MutantHandle, DesiredAccess, ObjectAttributes);
174
175 /* Check if we were called from user-mode */
176 if(PreviousMode != KernelMode)
177 {
178 /* Enter SEH Block */
179 _SEH_TRY
180 {
181 /* Check handle pointer */
182 ProbeForWriteHandle(MutantHandle);
183 }
184 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
185 {
186 Status = _SEH_GetExceptionCode();
187 }
188 _SEH_END;
189
190 /* Bail out if pointer was invalid */
191 if(!NT_SUCCESS(Status)) return Status;
192 }
193
194 /* Open the Object */
195 Status = ObOpenObjectByName(ObjectAttributes,
196 ExMutantObjectType,
197 NULL,
198 PreviousMode,
199 DesiredAccess,
200 NULL,
201 &hMutant);
202
203 /* Check for success */
204 if(NT_SUCCESS(Status))
205 {
206 /* Enter SEH for return */
207 _SEH_TRY
208 {
209 /* Return the handle to the caller */
210 *MutantHandle = hMutant;
211 }
212 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
213 {
214 Status = _SEH_GetExceptionCode();
215 }
216 _SEH_END;
217 }
218
219 /* Return Status */
220 return Status;
221 }
222
223 /*
224 * @implemented
225 */
226 NTSTATUS
227 NTAPI
228 NtQueryMutant(IN HANDLE MutantHandle,
229 IN MUTANT_INFORMATION_CLASS MutantInformationClass,
230 OUT PVOID MutantInformation,
231 IN ULONG MutantInformationLength,
232 OUT PULONG ResultLength OPTIONAL)
233 {
234 PKMUTANT Mutant;
235 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
236 NTSTATUS Status = STATUS_SUCCESS;
237 PMUTANT_BASIC_INFORMATION BasicInfo =
238 (PMUTANT_BASIC_INFORMATION)MutantInformation;
239 PAGED_CODE();
240
241 /* Check buffers and parameters */
242 Status = DefaultQueryInfoBufferCheck(MutantInformationClass,
243 ExMutantInfoClass,
244 sizeof(ExMutantInfoClass) /
245 sizeof(ExMutantInfoClass[0]),
246 MutantInformation,
247 MutantInformationLength,
248 ResultLength,
249 PreviousMode);
250 if(!NT_SUCCESS(Status))
251 {
252 DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status);
253 return Status;
254 }
255
256 /* Open the Object */
257 Status = ObReferenceObjectByHandle(MutantHandle,
258 MUTANT_QUERY_STATE,
259 ExMutantObjectType,
260 PreviousMode,
261 (PVOID*)&Mutant,
262 NULL);
263 /* Check for Status */
264 if(NT_SUCCESS(Status))
265 {
266 /* Enter SEH Block for return */
267 _SEH_TRY
268 {
269 /* Fill out the Basic Information Requested */
270 DPRINT("Returning Mutant Information\n");
271 BasicInfo->CurrentCount = KeReadStateMutant(Mutant);
272 BasicInfo->OwnedByCaller = (Mutant->OwnerThread ==
273 KeGetCurrentThread());
274 BasicInfo->AbandonedState = Mutant->Abandoned;
275
276 /* Return the Result Length if requested */
277 if(ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION);
278 }
279 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
280 {
281 Status = _SEH_GetExceptionCode();
282 }
283 _SEH_END;
284
285 /* Release the Object */
286 ObDereferenceObject(Mutant);
287 }
288
289 /* Return Status */
290 return Status;
291 }
292
293 /*
294 * @implemented
295 */
296 NTSTATUS
297 NTAPI
298 NtReleaseMutant(IN HANDLE MutantHandle,
299 IN PLONG PreviousCount OPTIONAL)
300 {
301 PKMUTANT Mutant;
302 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
303 NTSTATUS Status = STATUS_SUCCESS;
304 PAGED_CODE();
305 DPRINT("NtReleaseMutant(MutantHandle 0x%p PreviousCount 0x%p)\n",
306 MutantHandle,
307 PreviousCount);
308
309 /* Check if we were called from user-mode */
310 if((PreviousCount) && (PreviousMode != KernelMode))
311 {
312 /* Entry SEH Block */
313 _SEH_TRY
314 {
315 /* Make sure the state pointer is valid */
316 ProbeForWriteLong(PreviousCount);
317 }
318 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
319 {
320 Status = _SEH_GetExceptionCode();
321 }
322 _SEH_END;
323
324 /* Bail out if pointer was invalid */
325 if(!NT_SUCCESS(Status)) return Status;
326 }
327
328 /* Open the Object */
329 Status = ObReferenceObjectByHandle(MutantHandle,
330 MUTANT_QUERY_STATE,
331 ExMutantObjectType,
332 PreviousMode,
333 (PVOID*)&Mutant,
334 NULL);
335
336 /* Check for Success and release if such */
337 if(NT_SUCCESS(Status))
338 {
339 /*
340 * Release the mutant. doing so might raise an exception which we're
341 * required to catch!
342 */
343 _SEH_TRY
344 {
345 /* Release the mutant */
346 LONG Prev = KeReleaseMutant(Mutant,
347 MUTANT_INCREMENT,
348 FALSE,
349 FALSE);
350
351 /* Return the previous count if requested */
352 if(PreviousCount) *PreviousCount = Prev;
353 }
354 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
355 {
356 Status = _SEH_GetExceptionCode();
357 }
358 _SEH_END;
359
360 /* Dereference it */
361 ObDereferenceObject(Mutant);
362 }
363
364 /* Return Status */
365 return Status;
366 }
367
368 /* EOF */