xref: /reactos/ntoskrnl/ex/event.c (revision d0d86ab5)
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     IQS_SAME(EVENT_BASIC_INFORMATION, ULONG, ICIF_QUERY),
32 };
33 
34 /* FUNCTIONS *****************************************************************/
35 
36 CODE_SEG("INIT")
37 BOOLEAN
38 NTAPI
ExpInitializeEventImplementation(VOID)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
NtClearEvent(IN HANDLE EventHandle)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
NtCreateEvent(OUT PHANDLE EventHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN EVENT_TYPE EventType,IN BOOLEAN InitialState)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
NtOpenEvent(OUT PHANDLE EventHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes)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
NtPulseEvent(IN HANDLE EventHandle,OUT PLONG PreviousState OPTIONAL)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
NtQueryEvent(IN HANDLE EventHandle,IN EVENT_INFORMATION_CLASS EventInformationClass,OUT PVOID EventInformation,IN ULONG EventInformationLength,OUT PULONG ReturnLength OPTIONAL)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                                          ICIF_PROBE_READ_WRITE,
333                                          EventInformation,
334                                          EventInformationLength,
335                                          ReturnLength,
336                                          NULL,
337                                          PreviousMode);
338     if(!NT_SUCCESS(Status))
339     {
340         /* Invalid buffers */
341         DPRINT("NtQuerySemaphore() failed, Status: 0x%x\n", Status);
342         return Status;
343     }
344 
345     /* Get the Object */
346     Status = ObReferenceObjectByHandle(EventHandle,
347                                        EVENT_QUERY_STATE,
348                                        ExEventObjectType,
349                                        PreviousMode,
350                                        (PVOID*)&Event,
351                                        NULL);
352 
353     /* Check for success */
354     if(NT_SUCCESS(Status))
355     {
356         /* Entry SEH Block */
357         _SEH2_TRY
358         {
359             /* Return Event Type and State */
360             BasicInfo->EventType = Event->Header.Type;
361             BasicInfo->EventState = KeReadStateEvent(Event);
362 
363             /* Return length */
364             if(ReturnLength) *ReturnLength = sizeof(EVENT_BASIC_INFORMATION);
365         }
366         _SEH2_EXCEPT(ExSystemExceptionFilter())
367         {
368             /* Get the exception code */
369             Status = _SEH2_GetExceptionCode();
370         }
371         _SEH2_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
NtResetEvent(IN HANDLE EventHandle,OUT PLONG PreviousState OPTIONAL)386 NtResetEvent(IN HANDLE EventHandle,
387              OUT PLONG PreviousState OPTIONAL)
388 {
389     PKEVENT Event;
390     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
391     NTSTATUS Status;
392     PAGED_CODE();
393     DPRINT("NtResetEvent(EventHandle 0%p PreviousState 0%p)\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         _SEH2_TRY
401         {
402             /* Make sure the state pointer is valid */
403             ProbeForWriteLong(PreviousState);
404         }
405         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
406         {
407             /* Return the exception code */
408             _SEH2_YIELD(return _SEH2_GetExceptionCode());
409         }
410         _SEH2_END;
411     }
412 
413     /* Open the Object */
414     Status = ObReferenceObjectByHandle(EventHandle,
415                                        EVENT_MODIFY_STATE,
416                                        ExEventObjectType,
417                                        PreviousMode,
418                                        (PVOID*)&Event,
419                                        NULL);
420 
421     /* Check for success */
422     if(NT_SUCCESS(Status))
423     {
424         /* Reset the Event */
425         LONG Prev = KeResetEvent(Event);
426         ObDereferenceObject(Event);
427 
428         /* Check if caller wants the old state back */
429         if(PreviousState)
430         {
431             /* Entry SEH Block for return */
432             _SEH2_TRY
433             {
434                 /* Return previous state */
435                 *PreviousState = Prev;
436             }
437             _SEH2_EXCEPT(ExSystemExceptionFilter())
438             {
439                 /* Get the exception code */
440                 Status = _SEH2_GetExceptionCode();
441             }
442             _SEH2_END;
443         }
444    }
445 
446    /* Return Status */
447    return Status;
448 }
449 
450 /*
451  * @implemented
452  */
453 NTSTATUS
454 NTAPI
NtSetEvent(IN HANDLE EventHandle,OUT PLONG PreviousState OPTIONAL)455 NtSetEvent(IN HANDLE EventHandle,
456            OUT PLONG PreviousState  OPTIONAL)
457 {
458     PKEVENT Event;
459     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
460     NTSTATUS Status;
461     PAGED_CODE();
462     DPRINT("NtSetEvent(EventHandle 0%p PreviousState 0%p)\n",
463            EventHandle, PreviousState);
464 
465     /* Check if we were called from user-mode */
466     if ((PreviousState) && (PreviousMode != KernelMode))
467     {
468         /* Entry SEH Block */
469         _SEH2_TRY
470         {
471             /* Make sure the state pointer is valid */
472             ProbeForWriteLong(PreviousState);
473         }
474         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
475         {
476             /* Return the exception code */
477             _SEH2_YIELD(return _SEH2_GetExceptionCode());
478         }
479         _SEH2_END;
480     }
481 
482     /* Open the Object */
483     Status = ObReferenceObjectByHandle(EventHandle,
484                                        EVENT_MODIFY_STATE,
485                                        ExEventObjectType,
486                                        PreviousMode,
487                                        (PVOID*)&Event,
488                                        NULL);
489     if (NT_SUCCESS(Status))
490     {
491         /* Set the Event */
492         LONG Prev = KeSetEvent(Event, EVENT_INCREMENT, FALSE);
493         ObDereferenceObject(Event);
494 
495         /* Check if caller wants the old state back */
496         if (PreviousState)
497         {
498             /* Entry SEH Block for return */
499             _SEH2_TRY
500             {
501                 /* Return previous state */
502                 *PreviousState = Prev;
503             }
504             _SEH2_EXCEPT(ExSystemExceptionFilter())
505             {
506                 Status = _SEH2_GetExceptionCode();
507             }
508             _SEH2_END;
509         }
510     }
511 
512     /* Return Status */
513     return Status;
514 }
515 
516 /*
517  * @implemented
518  */
519 NTSTATUS
520 NTAPI
NtSetEventBoostPriority(IN HANDLE EventHandle)521 NtSetEventBoostPriority(IN HANDLE EventHandle)
522 {
523     PKEVENT Event;
524     NTSTATUS Status;
525     PAGED_CODE();
526 
527     /* Open the Object */
528     Status = ObReferenceObjectByHandle(EventHandle,
529                                        EVENT_MODIFY_STATE,
530                                        ExEventObjectType,
531                                        ExGetPreviousMode(),
532                                        (PVOID*)&Event,
533                                        NULL);
534     if (NT_SUCCESS(Status))
535     {
536         /* Set the Event */
537         KeSetEventBoostPriority(Event, NULL);
538         ObDereferenceObject(Event);
539     }
540 
541     /* Return Status */
542     return Status;
543 }
544 
545 /* EOF */
546