xref: /reactos/ntoskrnl/ex/event.c (revision cdf90707)
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
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                                           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
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
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
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