- Fix some small formatting issues.
[reactos.git] / reactos / ntoskrnl / ex / event.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/event.c
5 * PURPOSE: Event support
6 * PROGRAMMERS: Alex Ionescu(alex@relsoft.net)
7 * Thomas Weidenmueller
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, ExpInitializeEventImplementation)
18 #endif
19
20 /* GLOBALS *******************************************************************/
21
22 POBJECT_TYPE ExEventObjectType = NULL;
23
24 GENERIC_MAPPING ExpEventMapping =
25 {
26 STANDARD_RIGHTS_READ | SYNCHRONIZE | EVENT_QUERY_STATE,
27 STANDARD_RIGHTS_WRITE | SYNCHRONIZE | EVENT_MODIFY_STATE,
28 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | EVENT_QUERY_STATE,
29 EVENT_ALL_ACCESS};
30
31 static const INFORMATION_CLASS_INFO ExEventInfoClass[] =
32 {
33 /* EventBasicInformation */
34 ICI_SQ_SAME( sizeof(EVENT_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY),
35 };
36
37 /* FUNCTIONS *****************************************************************/
38
39 VOID
40 INIT_FUNCTION
41 NTAPI
42 ExpInitializeEventImplementation(VOID)
43 {
44 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
45 UNICODE_STRING Name;
46 DPRINT("Creating Event Object Type\n");
47
48 /* Create the Event Object Type */
49 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
50 RtlInitUnicodeString(&Name, L"Event");
51 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
52 ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KEVENT);
53 ObjectTypeInitializer.GenericMapping = ExpEventMapping;
54 ObjectTypeInitializer.PoolType = NonPagedPool;
55 ObjectTypeInitializer.ValidAccessMask = EVENT_ALL_ACCESS;
56 ObpCreateTypeObject(&ObjectTypeInitializer, &Name, &ExEventObjectType);
57 }
58
59 /*
60 * @implemented
61 */
62 NTSTATUS
63 NTAPI
64 NtClearEvent(IN HANDLE EventHandle)
65 {
66 PKEVENT Event;
67 NTSTATUS Status;
68 PAGED_CODE();
69
70 /* Reference the Object */
71 Status = ObReferenceObjectByHandle(EventHandle,
72 EVENT_MODIFY_STATE,
73 ExEventObjectType,
74 ExGetPreviousMode(),
75 (PVOID*)&Event,
76 NULL);
77
78 /* Check for Success */
79 if(NT_SUCCESS(Status))
80 {
81 /* Clear the Event and Dereference */
82 KeClearEvent(Event);
83 ObDereferenceObject(Event);
84 }
85
86 /* Return Status */
87 return Status;
88 }
89
90 /*
91 * @implemented
92 */
93 NTSTATUS
94 NTAPI
95 NtCreateEvent(OUT PHANDLE EventHandle,
96 IN ACCESS_MASK DesiredAccess,
97 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
98 IN EVENT_TYPE EventType,
99 IN BOOLEAN InitialState)
100 {
101 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
102 PKEVENT Event;
103 HANDLE hEvent;
104 NTSTATUS Status = STATUS_SUCCESS;
105 PAGED_CODE();
106 DPRINT("NtCreateEvent(0x%p, 0x%x, 0x%p)\n",
107 EventHandle, DesiredAccess, ObjectAttributes);
108
109 /* Check if we were called from user-mode */
110 if(PreviousMode != KernelMode)
111 {
112 /* Enter SEH Block */
113 _SEH_TRY
114 {
115 /* Check handle pointer */
116 ProbeForWriteHandle(EventHandle);
117 }
118 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
119 {
120 Status = _SEH_GetExceptionCode();
121 }
122 _SEH_END;
123
124 /* Bail out if pointer was invalid */
125 if(!NT_SUCCESS(Status)) return Status;
126 }
127
128 /* Create the Object */
129 Status = ObCreateObject(PreviousMode,
130 ExEventObjectType,
131 ObjectAttributes,
132 PreviousMode,
133 NULL,
134 sizeof(KEVENT),
135 0,
136 0,
137 (PVOID*)&Event);
138
139 /* Check for Success */
140 if(NT_SUCCESS(Status))
141 {
142 /* Initalize the Event */
143 KeInitializeEvent(Event,
144 EventType,
145 InitialState);
146
147 /* Insert it */
148 Status = ObInsertObject((PVOID)Event,
149 NULL,
150 DesiredAccess,
151 0,
152 NULL,
153 &hEvent);
154 ObDereferenceObject(Event);
155
156 /* Check for success */
157 if(NT_SUCCESS(Status))
158 {
159 /* Enter SEH for return */
160 _SEH_TRY
161 {
162 /* Return the handle to the caller */
163 *EventHandle = hEvent;
164 }
165 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
166 {
167 Status = _SEH_GetExceptionCode();
168 }
169 _SEH_END;
170 }
171 }
172
173 /* Return Status */
174 return Status;
175 }
176
177 /*
178 * @implemented
179 */
180 NTSTATUS
181 NTAPI
182 NtOpenEvent(OUT PHANDLE EventHandle,
183 IN ACCESS_MASK DesiredAccess,
184 IN POBJECT_ATTRIBUTES ObjectAttributes)
185 {
186 HANDLE hEvent;
187 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
188 NTSTATUS Status = STATUS_SUCCESS;
189 PAGED_CODE();
190 DPRINT("NtOpenEvent(0x%p, 0x%x, 0x%p)\n",
191 EventHandle, DesiredAccess, ObjectAttributes);
192
193 /* Check if we were called from user-mode */
194 if(PreviousMode != KernelMode)
195 {
196 /* Enter SEH Block */
197 _SEH_TRY
198 {
199 /* Check handle pointer */
200 ProbeForWriteHandle(EventHandle);
201 }
202 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
203 {
204 Status = _SEH_GetExceptionCode();
205 }
206 _SEH_END;
207
208 /* Bail out if pointer was invalid */
209 if(!NT_SUCCESS(Status)) return Status;
210 }
211
212 /* Open the Object */
213 Status = ObOpenObjectByName(ObjectAttributes,
214 ExEventObjectType,
215 NULL,
216 PreviousMode,
217 DesiredAccess,
218 NULL,
219 &hEvent);
220
221 /* Check for success */
222 if(NT_SUCCESS(Status))
223 {
224 /* Enter SEH for return */
225 _SEH_TRY
226 {
227 /* Return the handle to the caller */
228 *EventHandle = hEvent;
229 }
230 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
231 {
232 Status = _SEH_GetExceptionCode();
233 }
234 _SEH_END;
235 }
236
237 /* Return status */
238 return Status;
239 }
240
241 /*
242 * @implemented
243 */
244 NTSTATUS
245 NTAPI
246 NtPulseEvent(IN HANDLE EventHandle,
247 OUT PLONG PreviousState OPTIONAL)
248 {
249 PKEVENT Event;
250 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
251 NTSTATUS Status = STATUS_SUCCESS;
252 PAGED_CODE();
253 DPRINT("NtPulseEvent(EventHandle 0%x PreviousState 0%x)\n",
254 EventHandle, PreviousState);
255
256 /* Check if we were called from user-mode */
257 if((PreviousState) && (PreviousMode != KernelMode))
258 {
259 /* Entry SEH Block */
260 _SEH_TRY
261 {
262 /* Make sure the state pointer is valid */
263 ProbeForWriteLong(PreviousState);
264 }
265 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
266 {
267 Status = _SEH_GetExceptionCode();
268 }
269 _SEH_END;
270
271 /* Bail out if pointer was invalid */
272 if(!NT_SUCCESS(Status)) return Status;
273 }
274
275 /* Open the Object */
276 Status = ObReferenceObjectByHandle(EventHandle,
277 EVENT_MODIFY_STATE,
278 ExEventObjectType,
279 PreviousMode,
280 (PVOID*)&Event,
281 NULL);
282
283 /* Check for success */
284 if(NT_SUCCESS(Status))
285 {
286 /* Pulse the Event */
287 LONG Prev = KePulseEvent(Event, EVENT_INCREMENT, FALSE);
288 ObDereferenceObject(Event);
289
290 /* Check if caller wants the old state back */
291 if(PreviousState)
292 {
293 /* Entry SEH Block for return */
294 _SEH_TRY
295 {
296 /* Return previous state */
297 *PreviousState = Prev;
298 }
299 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
300 {
301 Status = _SEH_GetExceptionCode();
302 }
303 _SEH_END;
304 }
305 }
306
307 /* Return Status */
308 return Status;
309 }
310
311 /*
312 * @implemented
313 */
314 NTSTATUS
315 NTAPI
316 NtQueryEvent(IN HANDLE EventHandle,
317 IN EVENT_INFORMATION_CLASS EventInformationClass,
318 OUT PVOID EventInformation,
319 IN ULONG EventInformationLength,
320 OUT PULONG ReturnLength OPTIONAL)
321 {
322 PKEVENT Event;
323 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
324 NTSTATUS Status = STATUS_SUCCESS;
325 PEVENT_BASIC_INFORMATION BasicInfo =
326 (PEVENT_BASIC_INFORMATION)EventInformation;
327 PAGED_CODE();
328 DPRINT("NtQueryEvent(0x%p, 0x%x)\n", EventHandle, EventInformationClass);
329
330 /* Check buffers and class validity */
331 Status = DefaultQueryInfoBufferCheck(EventInformationClass,
332 ExEventInfoClass,
333 sizeof(ExEventInfoClass) /
334 sizeof(ExEventInfoClass[0]),
335 EventInformation,
336 EventInformationLength,
337 ReturnLength,
338 PreviousMode);
339 if(!NT_SUCCESS(Status))
340 {
341 /* Invalid buffers */
342 DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
343 return Status;
344 }
345
346 /* Get the Object */
347 Status = ObReferenceObjectByHandle(EventHandle,
348 EVENT_QUERY_STATE,
349 ExEventObjectType,
350 PreviousMode,
351 (PVOID*)&Event,
352 NULL);
353
354 /* Check for success */
355 if(NT_SUCCESS(Status))
356 {
357 /* Entry SEH Block */
358 _SEH_TRY
359 {
360 /* Return Event Type and State */
361 BasicInfo->EventType = Event->Header.Type;
362 BasicInfo->EventState = KeReadStateEvent(Event);
363
364 /* Return length */
365 if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
366 }
367 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
368 {
369 Status = _SEH_GetExceptionCode();
370 }
371 _SEH_END;
372
373 /* Dereference the Object */
374 ObDereferenceObject(Event);
375 }
376
377 /* Return status */
378 return Status;
379 }
380
381 /*
382 * @implemented
383 */
384 NTSTATUS
385 NTAPI
386 NtResetEvent(IN HANDLE EventHandle,
387 OUT PLONG PreviousState OPTIONAL)
388 {
389 PKEVENT Event;
390 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
391 NTSTATUS Status = STATUS_SUCCESS;
392 PAGED_CODE();
393 DPRINT("NtResetEvent(EventHandle 0%x PreviousState 0%x)\n",
394 EventHandle, PreviousState);
395
396 /* Check if we were called from user-mode */
397 if((PreviousState) && (PreviousMode != KernelMode))
398 {
399 /* Entry SEH Block */
400 _SEH_TRY
401 {
402 /* Make sure the state pointer is valid */
403 ProbeForWriteLong(PreviousState);
404 }
405 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
406 {
407 Status = _SEH_GetExceptionCode();
408 }
409 _SEH_END;
410
411 /* Bail out if pointer was invalid */
412 if(!NT_SUCCESS(Status)) return Status;
413 }
414
415 /* Open the Object */
416 Status = ObReferenceObjectByHandle(EventHandle,
417 EVENT_MODIFY_STATE,
418 ExEventObjectType,
419 PreviousMode,
420 (PVOID*)&Event,
421 NULL);
422
423 /* Check for success */
424 if(NT_SUCCESS(Status))
425 {
426 /* Reset the Event */
427 LONG Prev = KeResetEvent(Event);
428 ObDereferenceObject(Event);
429
430 /* Check if caller wants the old state back */
431 if(PreviousState)
432 {
433 /* Entry SEH Block for return */
434 _SEH_TRY
435 {
436 /* Return previous state */
437 *PreviousState = Prev;
438 }
439 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
440 {
441 Status = _SEH_GetExceptionCode();
442 }
443 _SEH_END;
444 }
445 }
446
447 /* Return Status */
448 return Status;
449 }
450
451 /*
452 * @implemented
453 */
454 NTSTATUS
455 NTAPI
456 NtSetEvent(IN HANDLE EventHandle,
457 OUT PLONG PreviousState OPTIONAL)
458 {
459 PKEVENT Event;
460 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
461 NTSTATUS Status = STATUS_SUCCESS;
462 PAGED_CODE();
463 DPRINT("NtSetEvent(EventHandle 0%x PreviousState 0%x)\n",
464 EventHandle, PreviousState);
465
466 /* Check if we were called from user-mode */
467 if((PreviousState) && (PreviousMode != KernelMode))
468 {
469 /* Entry SEH Block */
470 _SEH_TRY
471 {
472 /* Make sure the state pointer is valid */
473 ProbeForWriteLong(PreviousState);
474 }
475 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
476 {
477 Status = _SEH_GetExceptionCode();
478 }
479 _SEH_END;
480
481 /* Bail out if pointer was invalid */
482 if(!NT_SUCCESS(Status)) return Status;
483 }
484
485 /* Open the Object */
486 Status = ObReferenceObjectByHandle(EventHandle,
487 EVENT_MODIFY_STATE,
488 ExEventObjectType,
489 PreviousMode,
490 (PVOID*)&Event,
491 NULL);
492
493 /* Check for success */
494 if(NT_SUCCESS(Status))
495 {
496 /* Set the Event */
497 LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
498 ObDereferenceObject(Event);
499
500 /* Check if caller wants the old state back */
501 if(PreviousState)
502 {
503 /* Entry SEH Block for return */
504 _SEH_TRY
505 {
506 /* Return previous state */
507 *PreviousState = Prev;
508 }
509 _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
510 {
511 Status = _SEH_GetExceptionCode();
512 }
513 _SEH_END;
514 }
515 }
516
517 /* Return Status */
518 return Status;
519 }
520
521 /* EOF */