[NTOS:MM] Quick fix: use SIZE_T instead of ULONG, because ULONG is 32-bit and on...
[reactos.git] / 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 <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 ICI_SQ_SAME( sizeof(SEMAPHORE_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
36 };
37
38 /* FUNCTIONS *****************************************************************/
39
40 BOOLEAN
41 INIT_FUNCTION
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 SemaphoreInformation,
239 SemaphoreInformationLength,
240 ReturnLength,
241 NULL,
242 PreviousMode);
243 if (!NT_SUCCESS(Status))
244 {
245 /* Invalid buffers */
246 DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
247 return Status;
248 }
249
250 /* Get the Object */
251 Status = ObReferenceObjectByHandle(SemaphoreHandle,
252 SEMAPHORE_QUERY_STATE,
253 ExSemaphoreObjectType,
254 PreviousMode,
255 (PVOID*)&Semaphore,
256 NULL);
257
258 /* Check for success */
259 if (NT_SUCCESS(Status))
260 {
261 /* Entry SEH Block */
262 _SEH2_TRY
263 {
264 PSEMAPHORE_BASIC_INFORMATION BasicInfo =
265 (PSEMAPHORE_BASIC_INFORMATION)SemaphoreInformation;
266
267 /* Return the basic information */
268 BasicInfo->CurrentCount = KeReadStateSemaphore(Semaphore);
269 BasicInfo->MaximumCount = Semaphore->Limit;
270
271 /* Return the length */
272 if (ReturnLength) *ReturnLength = sizeof(*BasicInfo);
273 }
274 _SEH2_EXCEPT(ExSystemExceptionFilter())
275 {
276 /* Get the exception code */
277 Status = _SEH2_GetExceptionCode();
278 }
279 _SEH2_END;
280
281 /* Dereference the Object */
282 ObDereferenceObject(Semaphore);
283 }
284
285 /* Return status */
286 return Status;
287 }
288
289 /*
290 * @implemented
291 */
292 NTSTATUS
293 NTAPI
294 NtReleaseSemaphore(IN HANDLE SemaphoreHandle,
295 IN LONG ReleaseCount,
296 OUT PLONG PreviousCount OPTIONAL)
297 {
298 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
299 PKSEMAPHORE Semaphore;
300 NTSTATUS Status;
301 PAGED_CODE();
302
303 /* Check if we were called from user-mode */
304 if ((PreviousCount) && (PreviousMode != KernelMode))
305 {
306 /* Entry SEH Block */
307 _SEH2_TRY
308 {
309 /* Make sure the state pointer is valid */
310 ProbeForWriteLong(PreviousCount);
311 }
312 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
313 {
314 /* Return the exception code */
315 _SEH2_YIELD(return _SEH2_GetExceptionCode());
316 }
317 _SEH2_END;
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 _SEH2_TRY
340 {
341 /* Release the semaphore */
342 LONG PrevCount = KeReleaseSemaphore(Semaphore,
343 IO_NO_INCREMENT,
344 ReleaseCount,
345 FALSE);
346
347 /* Return the old count if requested */
348 if (PreviousCount) *PreviousCount = PrevCount;
349 }
350 _SEH2_EXCEPT(ExSystemExceptionFilter())
351 {
352 /* Get the exception code */
353 Status = _SEH2_GetExceptionCode();
354 }
355 _SEH2_END;
356
357 /* Dereference the Semaphore */
358 ObDereferenceObject(Semaphore);
359 }
360
361 /* Return Status */
362 return Status;
363 }
364
365 /* EOF */