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