Sync to trunk head(r38096)
[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 <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 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &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 _SEH2_TRY
97 {
98 /* Check handle pointer */
99 ProbeForWriteHandle(MutantHandle);
100 }
101 _SEH2_EXCEPT(ExSystemExceptionFilter())
102 {
103 Status = _SEH2_GetExceptionCode();
104 }
105 _SEH2_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
137 /* Check for success */
138 if(NT_SUCCESS(Status))
139 {
140 /* Enter SEH for return */
141 _SEH2_TRY
142 {
143 /* Return the handle to the caller */
144 *MutantHandle = hMutant;
145 }
146 _SEH2_EXCEPT(ExSystemExceptionFilter())
147 {
148 Status = _SEH2_GetExceptionCode();
149 }
150 _SEH2_END;
151 }
152 }
153
154 /* Return Status */
155 return Status;
156 }
157
158 /*
159 * @implemented
160 */
161 NTSTATUS
162 NTAPI
163 NtOpenMutant(OUT PHANDLE MutantHandle,
164 IN ACCESS_MASK DesiredAccess,
165 IN POBJECT_ATTRIBUTES ObjectAttributes)
166 {
167 HANDLE hMutant;
168 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
169 NTSTATUS Status = STATUS_SUCCESS;
170 PAGED_CODE();
171 DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n",
172 MutantHandle, DesiredAccess, ObjectAttributes);
173
174 /* Check if we were called from user-mode */
175 if(PreviousMode != KernelMode)
176 {
177 /* Enter SEH Block */
178 _SEH2_TRY
179 {
180 /* Check handle pointer */
181 ProbeForWriteHandle(MutantHandle);
182 }
183 _SEH2_EXCEPT(ExSystemExceptionFilter())
184 {
185 Status = _SEH2_GetExceptionCode();
186 }
187 _SEH2_END;
188
189 /* Bail out if pointer was invalid */
190 if(!NT_SUCCESS(Status)) return Status;
191 }
192
193 /* Open the Object */
194 Status = ObOpenObjectByName(ObjectAttributes,
195 ExMutantObjectType,
196 PreviousMode,
197 NULL,
198 DesiredAccess,
199 NULL,
200 &hMutant);
201
202 /* Check for success */
203 if(NT_SUCCESS(Status))
204 {
205 /* Enter SEH for return */
206 _SEH2_TRY
207 {
208 /* Return the handle to the caller */
209 *MutantHandle = hMutant;
210 }
211 _SEH2_EXCEPT(ExSystemExceptionFilter())
212 {
213 Status = _SEH2_GetExceptionCode();
214 }
215 _SEH2_END;
216 }
217
218 /* Return Status */
219 return Status;
220 }
221
222 /*
223 * @implemented
224 */
225 NTSTATUS
226 NTAPI
227 NtQueryMutant(IN HANDLE MutantHandle,
228 IN MUTANT_INFORMATION_CLASS MutantInformationClass,
229 OUT PVOID MutantInformation,
230 IN ULONG MutantInformationLength,
231 OUT PULONG ResultLength OPTIONAL)
232 {
233 PKMUTANT Mutant;
234 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
235 NTSTATUS Status = STATUS_SUCCESS;
236 PMUTANT_BASIC_INFORMATION BasicInfo =
237 (PMUTANT_BASIC_INFORMATION)MutantInformation;
238 PAGED_CODE();
239
240 /* Check buffers and parameters */
241 Status = DefaultQueryInfoBufferCheck(MutantInformationClass,
242 ExMutantInfoClass,
243 sizeof(ExMutantInfoClass) /
244 sizeof(ExMutantInfoClass[0]),
245 MutantInformation,
246 MutantInformationLength,
247 ResultLength,
248 NULL,
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 _SEH2_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 _SEH2_EXCEPT(ExSystemExceptionFilter())
280 {
281 Status = _SEH2_GetExceptionCode();
282 }
283 _SEH2_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 _SEH2_TRY
314 {
315 /* Make sure the state pointer is valid */
316 ProbeForWriteLong(PreviousCount);
317 }
318 _SEH2_EXCEPT(ExSystemExceptionFilter())
319 {
320 Status = _SEH2_GetExceptionCode();
321 }
322 _SEH2_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 _SEH2_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 _SEH2_EXCEPT(ExSystemExceptionFilter())
355 {
356 Status = _SEH2_GetExceptionCode();
357 }
358 _SEH2_END;
359
360 /* Dereference it */
361 ObDereferenceObject(Mutant);
362 }
363
364 /* Return Status */
365 return Status;
366 }
367
368 /* EOF */