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