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