xref: /reactos/ntoskrnl/ex/mutant.c (revision 003b19dc)
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     ICI_SQ_SAME( sizeof(MUTANT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
32 };
33 
34 /* FUNCTIONS *****************************************************************/
35 
36 VOID
37 NTAPI
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
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
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
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                                        0, /* No access rights required */
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 */
365