merge trunk head (37902)
[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 <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 ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &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 _SEH2_TRY
83 {
84 /* Check handle pointer */
85 ProbeForWriteHandle(SemaphoreHandle);
86 }
87 _SEH2_EXCEPT(ExSystemExceptionFilter())
88 {
89 Status = _SEH2_GetExceptionCode();
90 }
91 _SEH2_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
133 /* Check for success */
134 if(NT_SUCCESS(Status))
135 {
136 /* Enter SEH Block for return */
137 _SEH2_TRY
138 {
139 /* Return the handle */
140 *SemaphoreHandle = hSemaphore;
141 }
142 _SEH2_EXCEPT(ExSystemExceptionFilter())
143 {
144 Status = _SEH2_GetExceptionCode();
145 }
146 _SEH2_END;
147 }
148 }
149
150 /* Return Status */
151 return Status;
152 }
153
154 /*
155 * @implemented
156 */
157 NTSTATUS
158 NTAPI
159 NtOpenSemaphore(OUT PHANDLE SemaphoreHandle,
160 IN ACCESS_MASK DesiredAccess,
161 IN POBJECT_ATTRIBUTES ObjectAttributes)
162 {
163 HANDLE hSemaphore;
164 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
165 NTSTATUS Status = STATUS_SUCCESS;
166 PAGED_CODE();
167
168 /* Check if we were called from user-mode */
169 if(PreviousMode != KernelMode)
170 {
171 /* Enter SEH Block */
172 _SEH2_TRY
173 {
174 /* Check handle pointer */
175 ProbeForWriteHandle(SemaphoreHandle);
176 }
177 _SEH2_EXCEPT(ExSystemExceptionFilter())
178 {
179 Status = _SEH2_GetExceptionCode();
180 }
181 _SEH2_END;
182
183 /* Bail out if pointer was invalid */
184 if(!NT_SUCCESS(Status)) return Status;
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 Status = _SEH2_GetExceptionCode();
208 }
209 _SEH2_END;
210 }
211
212 /* Return Status */
213 return Status;
214 }
215
216 /*
217 * @implemented
218 */
219 NTSTATUS
220 NTAPI
221 NtQuerySemaphore(IN HANDLE SemaphoreHandle,
222 IN SEMAPHORE_INFORMATION_CLASS SemaphoreInformationClass,
223 OUT PVOID SemaphoreInformation,
224 IN ULONG SemaphoreInformationLength,
225 OUT PULONG ReturnLength OPTIONAL)
226 {
227 PKSEMAPHORE Semaphore;
228 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
229 NTSTATUS Status = STATUS_SUCCESS;
230 PAGED_CODE();
231
232 /* Check buffers and class validity */
233 Status = DefaultQueryInfoBufferCheck(SemaphoreInformationClass,
234 ExSemaphoreInfoClass,
235 sizeof(ExSemaphoreInfoClass) /
236 sizeof(ExSemaphoreInfoClass[0]),
237 SemaphoreInformation,
238 SemaphoreInformationLength,
239 ReturnLength,
240 NULL,
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 _SEH2_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 _SEH2_EXCEPT(ExSystemExceptionFilter())
274 {
275 Status = _SEH2_GetExceptionCode();
276 }
277 _SEH2_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 _SEH2_TRY
306 {
307 /* Make sure the state pointer is valid */
308 ProbeForWriteLong(PreviousCount);
309 }
310 _SEH2_EXCEPT(ExSystemExceptionFilter())
311 {
312 Status = _SEH2_GetExceptionCode();
313 }
314 _SEH2_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 _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 Status = _SEH2_GetExceptionCode();
353 }
354 _SEH2_END;
355
356 ObDereferenceObject(Semaphore);
357 }
358
359 /* Return Status */
360 return Status;
361 }
362
363 /* EOF */