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