Sync with trunk.
[reactos.git] / 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 | MUTANT_QUERY_STATE,
27 STANDARD_RIGHTS_WRITE,
28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
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 BOOLEAN
54 INIT_FUNCTION
55 NTAPI
56 ExpInitializeMutantImplementation(VOID)
57 {
58 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
59 UNICODE_STRING Name;
60 NTSTATUS Status;
61 DPRINT("Creating Mutant Object Type\n");
62
63 /* Create the Event Pair Object Type */
64 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
65 RtlInitUnicodeString(&Name, L"Mutant");
66 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
67 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KMUTANT);
68 ObjectTypeInitializer.GenericMapping = ExpMutantMapping;
69 ObjectTypeInitializer.PoolType = NonPagedPool;
70 ObjectTypeInitializer.DeleteProcedure = ExpDeleteMutant;
71 ObjectTypeInitializer.ValidAccessMask = MUTANT_ALL_ACCESS;
72 Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExMutantObjectType);
73 if (!NT_SUCCESS(Status)) return FALSE;
74 return TRUE;
75 }
76
77 /*
78 * @implemented
79 */
80 NTSTATUS
81 NTAPI
82 NtCreateMutant(OUT PHANDLE MutantHandle,
83 IN ACCESS_MASK DesiredAccess,
84 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
85 IN BOOLEAN InitialOwner)
86 {
87 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
88 HANDLE hMutant;
89 PKMUTANT Mutant;
90 NTSTATUS Status;
91 PAGED_CODE();
92 DPRINT("NtCreateMutant(0x%p, 0x%x, 0x%p)\n",
93 MutantHandle, DesiredAccess, ObjectAttributes);
94
95 /* Check if we were called from user-mode */
96 if (PreviousMode != KernelMode)
97 {
98 /* Enter SEH Block */
99 _SEH2_TRY
100 {
101 /* Check handle pointer */
102 ProbeForWriteHandle(MutantHandle);
103 }
104 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
105 {
106 /* Return the exception code */
107 _SEH2_YIELD(return _SEH2_GetExceptionCode());
108 }
109 _SEH2_END;
110 }
111
112 /* Create the Mutant Object*/
113 Status = ObCreateObject(PreviousMode,
114 ExMutantObjectType,
115 ObjectAttributes,
116 PreviousMode,
117 NULL,
118 sizeof(KMUTANT),
119 0,
120 0,
121 (PVOID*)&Mutant);
122
123 /* Check for success */
124 if(NT_SUCCESS(Status))
125 {
126 /* Initialize the Kernel Mutant */
127 DPRINT("Initializing the Mutant\n");
128 KeInitializeMutant(Mutant, InitialOwner);
129
130 /* Insert the Object */
131 Status = ObInsertObject((PVOID)Mutant,
132 NULL,
133 DesiredAccess,
134 0,
135 NULL,
136 &hMutant);
137
138 /* Check for success */
139 if (NT_SUCCESS(Status))
140 {
141 /* Enter SEH for return */
142 _SEH2_TRY
143 {
144 /* Return the handle to the caller */
145 *MutantHandle = hMutant;
146 }
147 _SEH2_EXCEPT(ExSystemExceptionFilter())
148 {
149 /* Get the exception code */
150 Status = _SEH2_GetExceptionCode();
151 }
152 _SEH2_END;
153 }
154 }
155
156 /* Return Status */
157 return Status;
158 }
159
160 /*
161 * @implemented
162 */
163 NTSTATUS
164 NTAPI
165 NtOpenMutant(OUT PHANDLE MutantHandle,
166 IN ACCESS_MASK DesiredAccess,
167 IN POBJECT_ATTRIBUTES ObjectAttributes)
168 {
169 HANDLE hMutant;
170 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
171 NTSTATUS Status;
172 PAGED_CODE();
173 DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n",
174 MutantHandle, DesiredAccess, ObjectAttributes);
175
176 /* Check if we were called from user-mode */
177 if (PreviousMode != KernelMode)
178 {
179 /* Enter SEH Block */
180 _SEH2_TRY
181 {
182 /* Check handle pointer */
183 ProbeForWriteHandle(MutantHandle);
184 }
185 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
186 {
187 /* Return the exception code */
188 _SEH2_YIELD(return _SEH2_GetExceptionCode());
189 }
190 _SEH2_END;
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;
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;
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(EXCEPTION_EXECUTE_HANDLER)
319 {
320 /* Return the exception code */
321 _SEH2_YIELD(return _SEH2_GetExceptionCode());
322 }
323 _SEH2_END;
324 }
325
326 /* Open the Object */
327 Status = ObReferenceObjectByHandle(MutantHandle,
328 MUTANT_QUERY_STATE,
329 ExMutantObjectType,
330 PreviousMode,
331 (PVOID*)&Mutant,
332 NULL);
333
334 /* Check for Success and release if such */
335 if (NT_SUCCESS(Status))
336 {
337 /*
338 * Release the mutant. doing so might raise an exception which we're
339 * required to catch!
340 */
341 _SEH2_TRY
342 {
343 /* Release the mutant */
344 LONG Prev = KeReleaseMutant(Mutant,
345 MUTANT_INCREMENT,
346 FALSE,
347 FALSE);
348
349 /* Return the previous count if requested */
350 if (PreviousCount) *PreviousCount = Prev;
351 }
352 _SEH2_EXCEPT(ExSystemExceptionFilter())
353 {
354 /* Get the exception code */
355 Status = _SEH2_GetExceptionCode();
356 }
357 _SEH2_END;
358
359 /* Dereference it */
360 ObDereferenceObject(Mutant);
361 }
362
363 /* Return Status */
364 return Status;
365 }
366
367 /* EOF */