xref: /reactos/ntoskrnl/ex/mutant.c (revision cc7cf826)
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 INIT_FUNCTION
54 BOOLEAN
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     ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
73     Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExMutantObjectType);
74     if (!NT_SUCCESS(Status)) return FALSE;
75     return TRUE;
76 }
77 
78 /*
79  * @implemented
80  */
81 NTSTATUS
82 NTAPI
83 NtCreateMutant(OUT PHANDLE MutantHandle,
84                IN ACCESS_MASK DesiredAccess,
85                IN POBJECT_ATTRIBUTES ObjectAttributes  OPTIONAL,
86                IN BOOLEAN InitialOwner)
87 {
88     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
89     HANDLE hMutant;
90     PKMUTANT Mutant;
91     NTSTATUS Status;
92     PAGED_CODE();
93     DPRINT("NtCreateMutant(0x%p, 0x%x, 0x%p)\n",
94             MutantHandle, DesiredAccess, ObjectAttributes);
95 
96     /* Check if we were called from user-mode */
97     if (PreviousMode != KernelMode)
98     {
99         /* Enter SEH Block */
100         _SEH2_TRY
101         {
102             /* Check handle pointer */
103             ProbeForWriteHandle(MutantHandle);
104         }
105         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
106         {
107             /* Return the exception code */
108             _SEH2_YIELD(return _SEH2_GetExceptionCode());
109         }
110         _SEH2_END;
111     }
112 
113     /* Create the Mutant Object*/
114     Status = ObCreateObject(PreviousMode,
115                             ExMutantObjectType,
116                             ObjectAttributes,
117                             PreviousMode,
118                             NULL,
119                             sizeof(KMUTANT),
120                             0,
121                             0,
122                             (PVOID*)&Mutant);
123 
124     /* Check for success */
125     if(NT_SUCCESS(Status))
126     {
127         /* Initialize the Kernel Mutant */
128         DPRINT("Initializing the Mutant\n");
129         KeInitializeMutant(Mutant, InitialOwner);
130 
131         /* Insert the Object */
132         Status = ObInsertObject((PVOID)Mutant,
133                                 NULL,
134                                 DesiredAccess,
135                                 0,
136                                 NULL,
137                                 &hMutant);
138 
139         /* Check for success */
140         if (NT_SUCCESS(Status))
141         {
142             /* Enter SEH for return */
143             _SEH2_TRY
144             {
145                 /* Return the handle to the caller */
146                 *MutantHandle = hMutant;
147             }
148             _SEH2_EXCEPT(ExSystemExceptionFilter())
149             {
150                 /* Get the exception code */
151                 Status = _SEH2_GetExceptionCode();
152             }
153             _SEH2_END;
154         }
155     }
156 
157     /* Return Status */
158     return Status;
159 }
160 
161 /*
162  * @implemented
163  */
164 NTSTATUS
165 NTAPI
166 NtOpenMutant(OUT PHANDLE MutantHandle,
167              IN ACCESS_MASK DesiredAccess,
168              IN POBJECT_ATTRIBUTES ObjectAttributes)
169 {
170     HANDLE hMutant;
171     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
172     NTSTATUS Status;
173     PAGED_CODE();
174     DPRINT("NtOpenMutant(0x%p, 0x%x, 0x%p)\n",
175             MutantHandle, DesiredAccess, ObjectAttributes);
176 
177     /* Check if we were called from user-mode */
178     if (PreviousMode != KernelMode)
179     {
180         /* Enter SEH Block */
181         _SEH2_TRY
182         {
183             /* Check handle pointer */
184             ProbeForWriteHandle(MutantHandle);
185         }
186         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
187         {
188             /* Return the exception code */
189             _SEH2_YIELD(return _SEH2_GetExceptionCode());
190         }
191         _SEH2_END;
192     }
193 
194     /* Open the Object */
195     Status = ObOpenObjectByName(ObjectAttributes,
196                                 ExMutantObjectType,
197                                 PreviousMode,
198                                 NULL,
199                                 DesiredAccess,
200                                 NULL,
201                                 &hMutant);
202 
203     /* Check for success */
204     if(NT_SUCCESS(Status))
205     {
206         /* Enter SEH for return */
207         _SEH2_TRY
208         {
209             /* Return the handle to the caller */
210             *MutantHandle = hMutant;
211         }
212         _SEH2_EXCEPT(ExSystemExceptionFilter())
213         {
214             Status = _SEH2_GetExceptionCode();
215         }
216         _SEH2_END;
217     }
218 
219     /* Return Status */
220     return Status;
221 }
222 
223 /*
224  * @implemented
225  */
226 NTSTATUS
227 NTAPI
228 NtQueryMutant(IN HANDLE MutantHandle,
229               IN MUTANT_INFORMATION_CLASS MutantInformationClass,
230               OUT PVOID MutantInformation,
231               IN ULONG MutantInformationLength,
232               OUT PULONG ResultLength  OPTIONAL)
233 {
234     PKMUTANT Mutant;
235     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
236     NTSTATUS Status;
237     PMUTANT_BASIC_INFORMATION BasicInfo =
238         (PMUTANT_BASIC_INFORMATION)MutantInformation;
239     PAGED_CODE();
240 
241     /* Check buffers and parameters */
242     Status = DefaultQueryInfoBufferCheck(MutantInformationClass,
243                                          ExMutantInfoClass,
244                                          sizeof(ExMutantInfoClass) /
245                                          sizeof(ExMutantInfoClass[0]),
246                                          MutantInformation,
247                                          MutantInformationLength,
248                                          ResultLength,
249                                          NULL,
250                                          PreviousMode);
251     if(!NT_SUCCESS(Status))
252     {
253         DPRINT("NtQueryMutant() failed, Status: 0x%x\n", Status);
254         return Status;
255     }
256 
257     /* Open the Object */
258     Status = ObReferenceObjectByHandle(MutantHandle,
259                                        MUTANT_QUERY_STATE,
260                                        ExMutantObjectType,
261                                        PreviousMode,
262                                        (PVOID*)&Mutant,
263                                        NULL);
264     /* Check for Status */
265     if (NT_SUCCESS(Status))
266     {
267         /* Enter SEH Block for return */
268          _SEH2_TRY
269          {
270             /* Fill out the Basic Information Requested */
271             DPRINT("Returning Mutant Information\n");
272             BasicInfo->CurrentCount = KeReadStateMutant(Mutant);
273             BasicInfo->OwnedByCaller = (Mutant->OwnerThread ==
274                                         KeGetCurrentThread());
275             BasicInfo->AbandonedState = Mutant->Abandoned;
276 
277             /* Return the Result Length if requested */
278            if (ResultLength) *ResultLength = sizeof(MUTANT_BASIC_INFORMATION);
279         }
280         _SEH2_EXCEPT(ExSystemExceptionFilter())
281         {
282             Status = _SEH2_GetExceptionCode();
283         }
284         _SEH2_END;
285 
286         /* Release the Object */
287         ObDereferenceObject(Mutant);
288     }
289 
290     /* Return Status */
291     return Status;
292 }
293 
294 /*
295  * @implemented
296  */
297 NTSTATUS
298 NTAPI
299 NtReleaseMutant(IN HANDLE MutantHandle,
300                 IN PLONG PreviousCount OPTIONAL)
301 {
302     PKMUTANT Mutant;
303     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
304     NTSTATUS Status;
305     PAGED_CODE();
306     DPRINT("NtReleaseMutant(MutantHandle 0x%p PreviousCount 0x%p)\n",
307             MutantHandle,
308             PreviousCount);
309 
310      /* Check if we were called from user-mode */
311     if ((PreviousCount) && (PreviousMode != KernelMode))
312     {
313         /* Entry SEH Block */
314         _SEH2_TRY
315         {
316             /* Make sure the state pointer is valid */
317             ProbeForWriteLong(PreviousCount);
318         }
319         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
320         {
321             /* Return the exception code */
322             _SEH2_YIELD(return _SEH2_GetExceptionCode());
323         }
324         _SEH2_END;
325     }
326 
327     /* Open the Object */
328     Status = ObReferenceObjectByHandle(MutantHandle,
329                                        0, /* No access rights required */
330                                        ExMutantObjectType,
331                                        PreviousMode,
332                                        (PVOID*)&Mutant,
333                                        NULL);
334 
335     /* Check for Success and release if such */
336     if (NT_SUCCESS(Status))
337     {
338         /*
339          * Release the mutant. doing so might raise an exception which we're
340          * required to catch!
341          */
342         _SEH2_TRY
343         {
344             /* Release the mutant */
345             LONG Prev = KeReleaseMutant(Mutant,
346                                         MUTANT_INCREMENT,
347                                         FALSE,
348                                         FALSE);
349 
350             /* Return the previous count if requested */
351             if (PreviousCount) *PreviousCount = Prev;
352         }
353         _SEH2_EXCEPT(ExSystemExceptionFilter())
354         {
355             /* Get the exception code */
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 */
369