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