[SHELL32] Fix Control_RunDLLW (#5400)
[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 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 */