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