xref: /reactos/ntoskrnl/ex/sem.c (revision b09b5584)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel
4  * FILE:            ntoskrnl/ex/sem.c
5  * PURPOSE:         Semaphore Implementation
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, ExpInitializeSemaphoreImplementation)
18 #endif
19 
20 /* GLOBALS ******************************************************************/
21 
22 POBJECT_TYPE ExSemaphoreObjectType;
23 
24 GENERIC_MAPPING ExSemaphoreMapping =
25 {
26     STANDARD_RIGHTS_READ | SEMAPHORE_QUERY_STATE,
27     STANDARD_RIGHTS_WRITE | SEMAPHORE_MODIFY_STATE,
28     STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
29     SEMAPHORE_ALL_ACCESS
30 };
31 
32 static const INFORMATION_CLASS_INFO ExSemaphoreInfoClass[] =
33 {
34      /* SemaphoreBasicInformation */
35     IQS_SAME(SEMAPHORE_BASIC_INFORMATION, ULONG, ICIF_QUERY),
36 };
37 
38 /* FUNCTIONS *****************************************************************/
39 
40 CODE_SEG("INIT")
41 BOOLEAN
42 NTAPI
43 ExpInitializeSemaphoreImplementation(VOID)
44 {
45     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
46     UNICODE_STRING Name;
47     NTSTATUS Status;
48     DPRINT("Creating Semaphore Object Type\n");
49 
50     /* Create the Event Pair Object Type */
51     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
52     RtlInitUnicodeString(&Name, L"Semaphore");
53     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
54     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KSEMAPHORE);
55     ObjectTypeInitializer.GenericMapping = ExSemaphoreMapping;
56     ObjectTypeInitializer.PoolType = NonPagedPool;
57     ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
58     ObjectTypeInitializer.ValidAccessMask = SEMAPHORE_ALL_ACCESS;
59     Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExSemaphoreObjectType);
60     if (!NT_SUCCESS(Status)) return FALSE;
61     return TRUE;
62 }
63 
64 /*
65  * @implemented
66  */
67 NTSTATUS
68 NTAPI
69 NtCreateSemaphore(OUT PHANDLE SemaphoreHandle,
70                   IN ACCESS_MASK DesiredAccess,
71                   IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
72                   IN LONG InitialCount,
73                   IN LONG MaximumCount)
74 {
75     PKSEMAPHORE Semaphore;
76     HANDLE hSemaphore;
77     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
78     NTSTATUS Status;
79     PAGED_CODE();
80 
81     /* Check if we were called from user-mode */
82     if (PreviousMode != KernelMode)
83     {
84         /* Enter SEH Block */
85         _SEH2_TRY
86         {
87             /* Check handle pointer */
88             ProbeForWriteHandle(SemaphoreHandle);
89         }
90         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
91         {
92             /* Return the exception code */
93             _SEH2_YIELD(return _SEH2_GetExceptionCode());
94         }
95         _SEH2_END;
96     }
97 
98     /* Make sure the counts make sense */
99     if ((MaximumCount <= 0) ||
100         (InitialCount < 0) ||
101         (InitialCount > MaximumCount))
102     {
103         DPRINT("Invalid Count Data!\n");
104         return STATUS_INVALID_PARAMETER;
105     }
106 
107     /* Create the Semaphore Object */
108     Status = ObCreateObject(PreviousMode,
109                             ExSemaphoreObjectType,
110                             ObjectAttributes,
111                             PreviousMode,
112                             NULL,
113                             sizeof(KSEMAPHORE),
114                             0,
115                             0,
116                             (PVOID*)&Semaphore);
117 
118     /* Check for Success */
119     if (NT_SUCCESS(Status))
120     {
121         /* Initialize it */
122         KeInitializeSemaphore(Semaphore,
123                               InitialCount,
124                               MaximumCount);
125 
126         /* Insert it into the Object Tree */
127         Status = ObInsertObject((PVOID)Semaphore,
128                                 NULL,
129                                 DesiredAccess,
130                                 0,
131                                 NULL,
132                                 &hSemaphore);
133 
134         /* Check for success */
135         if (NT_SUCCESS(Status))
136         {
137             /* Enter SEH Block for return */
138             _SEH2_TRY
139             {
140                 /* Return the handle */
141                 *SemaphoreHandle = hSemaphore;
142             }
143             _SEH2_EXCEPT(ExSystemExceptionFilter())
144             {
145                 /* Get the exception code */
146                 Status = _SEH2_GetExceptionCode();
147             }
148             _SEH2_END;
149         }
150     }
151 
152     /* Return Status */
153     return Status;
154 }
155 
156 /*
157  * @implemented
158  */
159 NTSTATUS
160 NTAPI
161 NtOpenSemaphore(OUT PHANDLE SemaphoreHandle,
162                 IN ACCESS_MASK DesiredAccess,
163                 IN POBJECT_ATTRIBUTES ObjectAttributes)
164 {
165     HANDLE hSemaphore;
166     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
167     NTSTATUS Status;
168     PAGED_CODE();
169 
170     /* Check if we were called from user-mode */
171     if (PreviousMode != KernelMode)
172     {
173         /* Enter SEH Block */
174         _SEH2_TRY
175         {
176             /* Check handle pointer */
177             ProbeForWriteHandle(SemaphoreHandle);
178         }
179         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
180         {
181             /* Return the exception code */
182             _SEH2_YIELD(return _SEH2_GetExceptionCode());
183         }
184         _SEH2_END;
185     }
186 
187     /* Open the Object */
188     Status = ObOpenObjectByName(ObjectAttributes,
189                                 ExSemaphoreObjectType,
190                                 PreviousMode,
191                                 NULL,
192                                 DesiredAccess,
193                                 NULL,
194                                 &hSemaphore);
195 
196     /* Check for success */
197     if (NT_SUCCESS(Status))
198     {
199         /* Enter SEH Block for return */
200         _SEH2_TRY
201         {
202             /* Return the handle */
203             *SemaphoreHandle = hSemaphore;
204         }
205         _SEH2_EXCEPT(ExSystemExceptionFilter())
206         {
207             /* Get the exception code */
208             Status = _SEH2_GetExceptionCode();
209         }
210         _SEH2_END;
211     }
212 
213     /* Return Status */
214     return Status;
215 }
216 
217 /*
218  * @implemented
219  */
220 NTSTATUS
221 NTAPI
222 NtQuerySemaphore(IN HANDLE SemaphoreHandle,
223                  IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,
224                  OUT PVOID SemaphoreInformation,
225                  IN ULONG SemaphoreInformationLength,
226                  OUT PULONG ReturnLength OPTIONAL)
227 {
228     PKSEMAPHORE Semaphore;
229     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
230     NTSTATUS Status;
231     PAGED_CODE();
232 
233     /* Check buffers and class validity */
234     Status = DefaultQueryInfoBufferCheck(SemaphoreInformationClass,
235                                          ExSemaphoreInfoClass,
236                                          sizeof(ExSemaphoreInfoClass) /
237                                          sizeof(ExSemaphoreInfoClass[0]),
238                                          ICIF_PROBE_READ_WRITE,
239                                          SemaphoreInformation,
240                                          SemaphoreInformationLength,
241                                          ReturnLength,
242                                          NULL,
243                                          PreviousMode);
244     if (!NT_SUCCESS(Status))
245     {
246         /* Invalid buffers */
247         DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
248         return Status;
249     }
250 
251     /* Get the Object */
252     Status = ObReferenceObjectByHandle(SemaphoreHandle,
253                                        SEMAPHORE_QUERY_STATE,
254                                        ExSemaphoreObjectType,
255                                        PreviousMode,
256                                        (PVOID*)&Semaphore,
257                                        NULL);
258 
259     /* Check for success */
260     if (NT_SUCCESS(Status))
261     {
262         /* Entry SEH Block */
263         _SEH2_TRY
264         {
265             PSEMAPHORE_BASIC_INFORMATION BasicInfo =
266                 (PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation;
267 
268             /* Return the basic information */
269             BasicInfo->CurrentCount = KeReadStateSemaphore(Semaphore);
270             BasicInfo->MaximumCount = Semaphore->Limit;
271 
272             /* Return the length */
273             if (ReturnLength) *ReturnLength = sizeof(*BasicInfo);
274         }
275         _SEH2_EXCEPT(ExSystemExceptionFilter())
276         {
277             /* Get the exception code */
278             Status = _SEH2_GetExceptionCode();
279         }
280         _SEH2_END;
281 
282         /* Dereference the Object */
283         ObDereferenceObject(Semaphore);
284    }
285 
286    /* Return status */
287    return Status;
288 }
289 
290 /*
291  * @implemented
292  */
293 NTSTATUS
294 NTAPI
295 NtReleaseSemaphore(IN HANDLE SemaphoreHandle,
296                    IN LONG ReleaseCount,
297                    OUT PLONG PreviousCount OPTIONAL)
298 {
299     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
300     PKSEMAPHORE Semaphore;
301     NTSTATUS Status;
302     PAGED_CODE();
303 
304     /* Check if we were called from user-mode */
305     if ((PreviousCount) && (PreviousMode != KernelMode))
306     {
307         /* Entry SEH Block */
308         _SEH2_TRY
309         {
310             /* Make sure the state pointer is valid */
311             ProbeForWriteLong(PreviousCount);
312          }
313         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
314         {
315             /* Return the exception code */
316             _SEH2_YIELD(return _SEH2_GetExceptionCode());
317         }
318         _SEH2_END;
319     }
320 
321     /* Make sure count makes sense */
322     if (ReleaseCount <= 0)
323     {
324         DPRINT("Invalid Release Count\n");
325         return STATUS_INVALID_PARAMETER;
326     }
327 
328     /* Get the Object */
329     Status = ObReferenceObjectByHandle(SemaphoreHandle,
330                                        SEMAPHORE_MODIFY_STATE,
331                                        ExSemaphoreObjectType,
332                                        PreviousMode,
333                                        (PVOID*)&Semaphore,
334                                        NULL);
335 
336     /* Check for success */
337     if (NT_SUCCESS(Status))
338     {
339         /* Enter SEH Block */
340         _SEH2_TRY
341         {
342             /* Release the semaphore */
343             LONG PrevCount = KeReleaseSemaphore(Semaphore,
344                                                 IO_NO_INCREMENT,
345                                                 ReleaseCount,
346                                                 FALSE);
347 
348             /* Return the old count if requested */
349             if (PreviousCount) *PreviousCount = PrevCount;
350         }
351         _SEH2_EXCEPT(ExSystemExceptionFilter())
352         {
353             /* Get the exception code */
354             Status = _SEH2_GetExceptionCode();
355         }
356         _SEH2_END;
357 
358         /* Dereference the Semaphore */
359         ObDereferenceObject(Semaphore);
360     }
361 
362     /* Return Status */
363     return Status;
364 }
365 
366 /* EOF */
367