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