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