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