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