[CMAKE]
[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 | 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;
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 /* Initalize 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
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
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 MutantInformation,
243 MutantInformationLength,
244 ResultLength,
245 NULL,
246 PreviousMode);
247 if(!NT_SUCCESS(Status))
248 {
249 DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status);
250 return Status;
251 }
252
253 /* Open the Object */
254 Status = ObReferenceObjectByHandle(MutantHandle,
255 MUTANT_QUERY_STATE,
256 ExMutantObjectType,
257 PreviousMode,
258 (PVOID*)&Mutant,
259 NULL);
260 /* Check for Status */
261 if (NT_SUCCESS(Status))
262 {
263 /* Enter SEH Block for return */
264 _SEH2_TRY
265 {
266 /* Fill out the Basic Information Requested */
267 DPRINT("Returning Mutant Information\n");
268 BasicInfo->CurrentCount = KeReadStateMutant(Mutant);
269 BasicInfo->OwnedByCaller = (Mutant->OwnerThread ==
270 KeGetCurrentThread());
271 BasicInfo->AbandonedState = Mutant->Abandoned;
272
273 /* Return the Result Length if requested */
274 if (ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION);
275 }
276 _SEH2_EXCEPT(ExSystemExceptionFilter())
277 {
278 Status = _SEH2_GetExceptionCode();
279 }
280 _SEH2_END;
281
282 /* Release the Object */
283 ObDereferenceObject(Mutant);
284 }
285
286 /* Return Status */
287 return Status;
288 }
289
290 /*
291 * @implemented
292 */
293 NTSTATUS
294 NTAPI
295 NtReleaseMutant(IN HANDLE MutantHandle,
296 IN PLONG PreviousCount OPTIONAL)
297 {
298 PKMUTANT Mutant;
299 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
300 NTSTATUS Status;
301 PAGED_CODE();
302 DPRINT("NtReleaseMutant(MutantHandle 0x%p PreviousCount 0x%p)\n",
303 MutantHandle,
304 PreviousCount);
305
306 /* Check if we were called from user-mode */
307 if ((PreviousCount) && (PreviousMode != KernelMode))
308 {
309 /* Entry SEH Block */
310 _SEH2_TRY
311 {
312 /* Make sure the state pointer is valid */
313 ProbeForWriteLong(PreviousCount);
314 }
315 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
316 {
317 /* Return the exception code */
318 _SEH2_YIELD(return _SEH2_GetExceptionCode());
319 }
320 _SEH2_END;
321 }
322
323 /* Open the Object */
324 Status = ObReferenceObjectByHandle(MutantHandle,
325 MUTANT_QUERY_STATE,
326 ExMutantObjectType,
327 PreviousMode,
328 (PVOID*)&Mutant,
329 NULL);
330
331 /* Check for Success and release if such */
332 if (NT_SUCCESS(Status))
333 {
334 /*
335 * Release the mutant. doing so might raise an exception which we're
336 * required to catch!
337 */
338 _SEH2_TRY
339 {
340 /* Release the mutant */
341 LONG Prev = KeReleaseMutant(Mutant,
342 MUTANT_INCREMENT,
343 FALSE,
344 FALSE);
345
346 /* Return the previous count if requested */
347 if (PreviousCount) *PreviousCount = Prev;
348 }
349 _SEH2_EXCEPT(ExSystemExceptionFilter())
350 {
351 /* Get the exception code */
352 Status = _SEH2_GetExceptionCode();
353 }
354 _SEH2_END;
355
356 /* Dereference it */
357 ObDereferenceObject(Mutant);
358 }
359
360 /* Return Status */
361 return Status;
362 }
363
364 /* EOF */