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