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