1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/process.c 5 * PURPOSE: Kernel Process Management and System Call Tables 6 * PROGRAMMERS: Alex Ionescu 7 * Gregor Anich 8 */ 9 10 /* INCLUDES ******************************************************************/ 11 12 #include <ntoskrnl.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 /* GLOBALS *******************************************************************/ 17 18 LIST_ENTRY KiProcessListHead; 19 LIST_ENTRY KiProcessInSwapListHead, KiProcessOutSwapListHead; 20 LIST_ENTRY KiStackInSwapListHead; 21 KEVENT KiSwapEvent; 22 23 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable[SSDT_MAX_ENTRIES]; 24 KSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow[SSDT_MAX_ENTRIES]; 25 26 PVOID KeUserApcDispatcher; 27 PVOID KeUserCallbackDispatcher; 28 PVOID KeUserExceptionDispatcher; 29 PVOID KeRaiseUserExceptionDispatcher; 30 31 /* PRIVATE FUNCTIONS *********************************************************/ 32 33 VOID 34 NTAPI 35 KiAttachProcess(IN PKTHREAD Thread, 36 IN PKPROCESS Process, 37 IN PKLOCK_QUEUE_HANDLE ApcLock, 38 IN PRKAPC_STATE SavedApcState) 39 { 40 #if 0 41 PLIST_ENTRY ListHead, NextEntry; 42 PKTHREAD CurrentThread; 43 #endif 44 ASSERT(Process != Thread->ApcState.Process); 45 46 /* Increase Stack Count */ 47 ASSERT(Process->StackCount != MAXULONG_PTR); 48 Process->StackCount++; 49 50 /* Swap the APC Environment */ 51 KiMoveApcState(&Thread->ApcState, SavedApcState); 52 53 /* Reinitialize Apc State */ 54 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); 55 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); 56 Thread->ApcState.Process = Process; 57 Thread->ApcState.KernelApcInProgress = FALSE; 58 Thread->ApcState.KernelApcPending = FALSE; 59 Thread->ApcState.UserApcPending = FALSE; 60 61 /* Update Environment Pointers if needed*/ 62 if (SavedApcState == &Thread->SavedApcState) 63 { 64 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread-> 65 SavedApcState; 66 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->ApcState; 67 Thread->ApcStateIndex = AttachedApcEnvironment; 68 } 69 70 /* Check if the process is paged in */ 71 if (Process->State == ProcessInMemory) 72 { 73 /* Scan the ready list */ 74 #if 0 75 ListHead = &Process->ReadyListHead; 76 NextEntry = ListHead->Flink; 77 while (NextEntry != ListHead) 78 { 79 /* Get the thread */ 80 CurrentThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 81 82 /* Remove it */ 83 RemoveEntryList(NextEntry); 84 CurrentThread->ProcessReadyQueue = FALSE; 85 86 /* Mark it ready */ 87 KiReadyThread(CurrentThread); 88 89 /* Go to the next one */ 90 NextEntry = ListHead->Flink; 91 } 92 #endif 93 94 /* Release dispatcher lock */ 95 KiReleaseDispatcherLockFromDpcLevel(); 96 97 /* Release lock */ 98 KiReleaseApcLockFromDpcLevel(ApcLock); 99 100 /* Make sure that we are in the right page directory (ReactOS Mm Hack) */ 101 MiSyncForProcessAttach(Thread, (PEPROCESS)Process); 102 103 /* Swap Processes */ 104 KiSwapProcess(Process, SavedApcState->Process); 105 106 /* Exit the dispatcher */ 107 KiExitDispatcher(ApcLock->OldIrql); 108 } 109 else 110 { 111 DPRINT1("Errr. ReactOS doesn't support paging out processes yet...\n"); 112 ASSERT(FALSE); 113 } 114 } 115 116 VOID 117 NTAPI 118 KeInitializeProcess(IN OUT PKPROCESS Process, 119 IN KPRIORITY Priority, 120 IN KAFFINITY Affinity, 121 IN PULONG DirectoryTableBase, 122 IN BOOLEAN Enable) 123 { 124 #ifdef CONFIG_SMP 125 ULONG i = 0; 126 UCHAR IdealNode = 0; 127 PKNODE Node; 128 #endif 129 130 /* Initialize the Dispatcher Header */ 131 KeInitializeDispatcherHeader(&Process->Header, 132 ProcessObject, 133 sizeof(KPROCESS), 134 FALSE); 135 136 /* Initialize Scheduler Data, Alignment Faults and Set the PDE */ 137 Process->Affinity = Affinity; 138 Process->BasePriority = (CHAR)Priority; 139 Process->QuantumReset = 6; 140 Process->DirectoryTableBase[0] = DirectoryTableBase[0]; 141 Process->DirectoryTableBase[1] = DirectoryTableBase[1]; 142 Process->AutoAlignment = Enable; 143 #if defined(_M_IX86) 144 Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE); 145 #endif 146 147 /* Initialize the lists */ 148 InitializeListHead(&Process->ThreadListHead); 149 InitializeListHead(&Process->ProfileListHead); 150 InitializeListHead(&Process->ReadyListHead); 151 152 /* Initialize the current State */ 153 Process->State = ProcessInMemory; 154 155 /* Check how many Nodes there are on the system */ 156 #ifdef CONFIG_SMP 157 if (KeNumberNodes > 1) 158 { 159 /* Set the new seed */ 160 KeProcessNodeSeed = (KeProcessNodeSeed + 1) / KeNumberNodes; 161 IdealNode = KeProcessNodeSeed; 162 163 /* Loop every node */ 164 do 165 { 166 /* Check if the affinity matches */ 167 if (KeNodeBlock[IdealNode]->ProcessorMask != Affinity) break; 168 169 /* No match, try next Ideal Node and increase node loop index */ 170 IdealNode++; 171 i++; 172 173 /* Check if the Ideal Node is beyond the total number of nodes */ 174 if (IdealNode >= KeNumberNodes) 175 { 176 /* Normalize the Ideal Node */ 177 IdealNode -= KeNumberNodes; 178 } 179 } while (i < KeNumberNodes); 180 } 181 182 /* Set the ideal node and get the ideal node block */ 183 Process->IdealNode = IdealNode; 184 Node = KeNodeBlock[IdealNode]; 185 ASSERT(Node->ProcessorMask & Affinity); 186 187 /* Find the matching affinity set to calculate the thread seed */ 188 Affinity &= Node->ProcessorMask; 189 Process->ThreadSeed = KeFindNextRightSetAffinity(Node->Seed, 190 (ULONG)Affinity); 191 Node->Seed = Process->ThreadSeed; 192 #endif 193 } 194 195 ULONG 196 NTAPI 197 KeSetProcess(IN PKPROCESS Process, 198 IN KPRIORITY Increment, 199 IN BOOLEAN InWait) 200 { 201 KIRQL OldIrql; 202 ULONG OldState; 203 ASSERT_PROCESS(Process); 204 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 205 206 /* Lock Dispatcher */ 207 OldIrql = KiAcquireDispatcherLock(); 208 209 /* Get Old State */ 210 OldState = Process->Header.SignalState; 211 212 /* Signal the Process */ 213 Process->Header.SignalState = TRUE; 214 215 /* Check if was unsignaled and has waiters */ 216 if (!(OldState) && 217 !(IsListEmpty(&Process->Header.WaitListHead))) 218 { 219 /* Unwait the threads */ 220 KxUnwaitThread(&Process->Header, Increment); 221 } 222 223 /* Release Dispatcher Database */ 224 KiReleaseDispatcherLock(OldIrql); 225 226 /* Return the previous State */ 227 return OldState; 228 } 229 230 VOID 231 NTAPI 232 KeSetQuantumProcess(IN PKPROCESS Process, 233 IN UCHAR Quantum) 234 { 235 KLOCK_QUEUE_HANDLE ProcessLock; 236 PLIST_ENTRY NextEntry, ListHead; 237 PKTHREAD Thread; 238 ASSERT_PROCESS(Process); 239 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 240 241 /* Lock the process */ 242 KiAcquireProcessLock(Process, &ProcessLock); 243 244 /* Set new quantum */ 245 Process->QuantumReset = Quantum; 246 247 /* Loop all child threads */ 248 ListHead = &Process->ThreadListHead; 249 NextEntry = ListHead->Flink; 250 while (ListHead != NextEntry) 251 { 252 /* Get the thread */ 253 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 254 255 /* Set quantum */ 256 Thread->QuantumReset = Quantum; 257 258 /* Go to the next one */ 259 NextEntry = NextEntry->Flink; 260 } 261 262 /* Release lock */ 263 KiReleaseProcessLock(&ProcessLock); 264 } 265 266 KPRIORITY 267 NTAPI 268 KeSetPriorityAndQuantumProcess(IN PKPROCESS Process, 269 IN KPRIORITY Priority, 270 IN UCHAR Quantum OPTIONAL) 271 { 272 KLOCK_QUEUE_HANDLE ProcessLock; 273 KPRIORITY Delta; 274 PLIST_ENTRY NextEntry, ListHead; 275 KPRIORITY NewPriority, OldPriority; 276 PKTHREAD Thread; 277 ASSERT_PROCESS(Process); 278 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 279 280 /* Check if the process already has this priority */ 281 if (Process->BasePriority == Priority) return Process->BasePriority; 282 283 /* If the caller gave priority 0, normalize to 1 */ 284 if (!Priority) Priority = LOW_PRIORITY + 1; 285 286 /* Lock the process */ 287 KiAcquireProcessLock(Process, &ProcessLock); 288 289 /* Check if we are modifying the quantum too */ 290 if (Quantum) Process->QuantumReset = Quantum; 291 292 /* Save the current base priority and update it */ 293 OldPriority = Process->BasePriority; 294 Process->BasePriority = (SCHAR)Priority; 295 296 /* Calculate the priority delta */ 297 Delta = Priority - OldPriority; 298 299 /* Set the list head and list entry */ 300 ListHead = &Process->ThreadListHead; 301 NextEntry = ListHead->Flink; 302 303 /* Check if this is a real-time priority */ 304 if (Priority >= LOW_REALTIME_PRIORITY) 305 { 306 /* Loop the thread list */ 307 while (NextEntry != ListHead) 308 { 309 /* Get the thread */ 310 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 311 312 /* Update the quantum if we had one */ 313 if (Quantum) Thread->QuantumReset = Quantum; 314 315 /* Acquire the thread lock */ 316 KiAcquireThreadLock(Thread); 317 318 /* Calculate the new priority */ 319 NewPriority = Thread->BasePriority + Delta; 320 if (NewPriority < LOW_REALTIME_PRIORITY) 321 { 322 /* We're in real-time range, don't let it go below */ 323 NewPriority = LOW_REALTIME_PRIORITY; 324 } 325 else if (NewPriority > HIGH_PRIORITY) 326 { 327 /* We're going beyond the maximum priority, normalize */ 328 NewPriority = HIGH_PRIORITY; 329 } 330 331 /* 332 * If priority saturation occured or the old priority was still in 333 * the real-time range, don't do anything. 334 */ 335 if (!(Thread->Saturation) || (OldPriority < LOW_REALTIME_PRIORITY)) 336 { 337 /* Check if we had priority saturation */ 338 if (Thread->Saturation > 0) 339 { 340 /* Boost priority to maximum */ 341 NewPriority = HIGH_PRIORITY; 342 } 343 else if (Thread->Saturation < 0) 344 { 345 /* If we had negative saturation, set minimum priority */ 346 NewPriority = LOW_REALTIME_PRIORITY; 347 } 348 349 /* Update priority and quantum */ 350 Thread->BasePriority = (SCHAR)NewPriority; 351 Thread->Quantum = Thread->QuantumReset; 352 353 /* Disable decrements and update priority */ 354 Thread->PriorityDecrement = 0; 355 KiSetPriorityThread(Thread, NewPriority); 356 } 357 358 /* Release the thread lock */ 359 KiReleaseThreadLock(Thread); 360 361 /* Go to the next thread */ 362 NextEntry = NextEntry->Flink; 363 } 364 } 365 else 366 { 367 /* Loop the thread list */ 368 while (NextEntry != ListHead) 369 { 370 /* Get the thread */ 371 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 372 373 /* Update the quantum if we had one */ 374 if (Quantum) Thread->QuantumReset = Quantum; 375 376 /* Lock the thread */ 377 KiAcquireThreadLock(Thread); 378 379 /* Calculate the new priority */ 380 NewPriority = Thread->BasePriority + Delta; 381 if (NewPriority >= LOW_REALTIME_PRIORITY) 382 { 383 /* We're not real-time range, don't let it enter RT range */ 384 NewPriority = LOW_REALTIME_PRIORITY - 1; 385 } 386 else if (NewPriority <= LOW_PRIORITY) 387 { 388 /* We're going below the minimum priority, normalize */ 389 NewPriority = 1; 390 } 391 392 /* 393 * If priority saturation occured or the old priority was still in 394 * the real-time range, don't do anything. 395 */ 396 if (!(Thread->Saturation) || 397 (OldPriority >= LOW_REALTIME_PRIORITY)) 398 { 399 /* Check if we had priority saturation */ 400 if (Thread->Saturation > 0) 401 { 402 /* Boost priority to maximum */ 403 NewPriority = LOW_REALTIME_PRIORITY - 1; 404 } 405 else if (Thread->Saturation < 0) 406 { 407 /* If we had negative saturation, set minimum priority */ 408 NewPriority = 1; 409 } 410 411 /* Update priority and quantum */ 412 Thread->BasePriority = (SCHAR)NewPriority; 413 Thread->Quantum = Thread->QuantumReset; 414 415 /* Disable decrements and update priority */ 416 Thread->PriorityDecrement = 0; 417 KiSetPriorityThread(Thread, NewPriority); 418 } 419 420 /* Release the thread lock */ 421 KiReleaseThreadLock(Thread); 422 423 /* Go to the next thread */ 424 NextEntry = NextEntry->Flink; 425 } 426 } 427 428 /* Release Dispatcher Database */ 429 KiReleaseDispatcherLockFromDpcLevel(); 430 431 /* Release the process lock */ 432 KiReleaseProcessLockFromDpcLevel(&ProcessLock); 433 KiExitDispatcher(ProcessLock.OldIrql); 434 435 /* Return previous priority */ 436 return OldPriority; 437 } 438 439 /* PUBLIC FUNCTIONS **********************************************************/ 440 441 /* 442 * @implemented 443 */ 444 VOID 445 NTAPI 446 KeAttachProcess(IN PKPROCESS Process) 447 { 448 KLOCK_QUEUE_HANDLE ApcLock; 449 PKTHREAD Thread = KeGetCurrentThread(); 450 ASSERT_PROCESS(Process); 451 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 452 453 /* Make sure that we are in the right page directory (ReactOS Mm Hack) */ 454 MiSyncForProcessAttach(Thread, (PEPROCESS)Process); 455 456 /* Check if we're already in that process */ 457 if (Thread->ApcState.Process == Process) return; 458 459 /* Check if a DPC is executing or if we're already attached */ 460 if ((Thread->ApcStateIndex != OriginalApcEnvironment) || 461 (KeIsExecutingDpc())) 462 { 463 /* Invalid attempt */ 464 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 465 (ULONG_PTR)Process, 466 (ULONG_PTR)Thread->ApcState.Process, 467 Thread->ApcStateIndex, 468 KeIsExecutingDpc()); 469 } 470 else 471 { 472 /* Acquire APC Lock */ 473 KiAcquireApcLock(Thread, &ApcLock); 474 475 /* Acquire the dispatcher lock */ 476 KiAcquireDispatcherLockAtDpcLevel(); 477 478 /* Legit attach attempt: do it! */ 479 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 480 } 481 } 482 483 /* 484 * @implemented 485 */ 486 VOID 487 NTAPI 488 KeDetachProcess(VOID) 489 { 490 PKTHREAD Thread = KeGetCurrentThread(); 491 KLOCK_QUEUE_HANDLE ApcLock; 492 PKPROCESS Process; 493 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 494 495 /* Check if it's attached */ 496 if (Thread->ApcStateIndex == OriginalApcEnvironment) return; 497 498 /* Acquire APC Lock */ 499 KiAcquireApcLock(Thread, &ApcLock); 500 501 /* Check for invalid attach attempts */ 502 if ((Thread->ApcState.KernelApcInProgress) || 503 !(IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 504 !(IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 505 { 506 /* Crash the system */ 507 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 508 } 509 510 /* Get the process */ 511 Process = Thread->ApcState.Process; 512 513 /* Acquire dispatcher lock */ 514 KiAcquireDispatcherLockAtDpcLevel(); 515 516 /* Decrease the stack count */ 517 ASSERT(Process->StackCount != 0); 518 ASSERT(Process->State == ProcessInMemory); 519 Process->StackCount--; 520 521 /* Check if we can swap the process out */ 522 if (!Process->StackCount) 523 { 524 /* FIXME: Swap the process out */ 525 } 526 527 /* Release dispatcher lock */ 528 KiReleaseDispatcherLockFromDpcLevel(); 529 530 /* Restore the APC State */ 531 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 532 Thread->SavedApcState.Process = NULL; 533 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 534 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 535 Thread->ApcStateIndex = OriginalApcEnvironment; 536 537 /* Release lock */ 538 KiReleaseApcLockFromDpcLevel(&ApcLock); 539 540 /* Swap Processes */ 541 KiSwapProcess(Thread->ApcState.Process, Process); 542 543 /* Exit the dispatcher */ 544 KiExitDispatcher(ApcLock.OldIrql); 545 546 /* Check if we have pending APCs */ 547 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) 548 { 549 /* What do you know, we do! Request them to be delivered */ 550 Thread->ApcState.KernelApcPending = TRUE; 551 HalRequestSoftwareInterrupt(APC_LEVEL); 552 } 553 } 554 555 /* 556 * @implemented 557 */ 558 BOOLEAN 559 NTAPI 560 KeIsAttachedProcess(VOID) 561 { 562 /* Return the APC State */ 563 return KeGetCurrentThread()->ApcStateIndex; 564 } 565 566 /* 567 * @implemented 568 */ 569 VOID 570 NTAPI 571 KeStackAttachProcess(IN PKPROCESS Process, 572 OUT PRKAPC_STATE ApcState) 573 { 574 KLOCK_QUEUE_HANDLE ApcLock; 575 PKTHREAD Thread = KeGetCurrentThread(); 576 ASSERT_PROCESS(Process); 577 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 578 579 /* Crash system if DPC is being executed! */ 580 if (KeIsExecutingDpc()) 581 { 582 /* Executing a DPC, crash! */ 583 KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT, 584 (ULONG_PTR)Process, 585 (ULONG_PTR)Thread->ApcState.Process, 586 Thread->ApcStateIndex, 587 KeIsExecutingDpc()); 588 } 589 590 /* Check if we are already in the target process */ 591 if (Thread->ApcState.Process == Process) 592 { 593 /* Set magic value so we don't crash later when detaching */ 594 ApcState->Process = (PKPROCESS)1; 595 return; 596 } 597 598 /* Acquire APC Lock */ 599 KiAcquireApcLock(Thread, &ApcLock); 600 601 /* Acquire dispatcher lock */ 602 KiAcquireDispatcherLockAtDpcLevel(); 603 604 /* Check if the Current Thread is already attached */ 605 if (Thread->ApcStateIndex != OriginalApcEnvironment) 606 { 607 /* We're already attached, so save the APC State into what we got */ 608 KiAttachProcess(Thread, Process, &ApcLock, ApcState); 609 } 610 else 611 { 612 /* We're not attached, so save the APC State into SavedApcState */ 613 KiAttachProcess(Thread, Process, &ApcLock, &Thread->SavedApcState); 614 ApcState->Process = NULL; 615 } 616 } 617 618 /* 619 * @implemented 620 */ 621 VOID 622 NTAPI 623 KeUnstackDetachProcess(IN PRKAPC_STATE ApcState) 624 { 625 KLOCK_QUEUE_HANDLE ApcLock; 626 PKTHREAD Thread = KeGetCurrentThread(); 627 PKPROCESS Process; 628 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 629 630 /* Check for magic value meaning we were already in the same process */ 631 if (ApcState->Process == (PKPROCESS)1) return; 632 633 /* Loop to make sure no APCs are pending */ 634 for (;;) 635 { 636 /* Acquire APC Lock */ 637 KiAcquireApcLock(Thread, &ApcLock); 638 639 /* Check if a kernel APC is pending */ 640 if (Thread->ApcState.KernelApcPending) 641 { 642 /* Check if kernel APC should be delivered */ 643 if (!(Thread->KernelApcDisable) && (ApcLock.OldIrql <= APC_LEVEL)) 644 { 645 /* Release the APC lock so that the APC can be delivered */ 646 KiReleaseApcLock(&ApcLock); 647 continue; 648 } 649 } 650 651 /* Otherwise, break out */ 652 break; 653 } 654 655 /* 656 * Check if the process isn't attacked, or has a Kernel APC in progress 657 * or has pending APC of any kind. 658 */ 659 if ((Thread->ApcStateIndex == OriginalApcEnvironment) || 660 (Thread->ApcState.KernelApcInProgress) || 661 (!IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) || 662 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 663 { 664 /* Bugcheck the system */ 665 KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT); 666 } 667 668 /* Get the process */ 669 Process = Thread->ApcState.Process; 670 671 /* Acquire dispatcher lock */ 672 KiAcquireDispatcherLockAtDpcLevel(); 673 674 /* Decrease the stack count */ 675 ASSERT(Process->StackCount != 0); 676 ASSERT(Process->State == ProcessInMemory); 677 Process->StackCount--; 678 679 /* Check if we can swap the process out */ 680 if (!Process->StackCount) 681 { 682 /* FIXME: Swap the process out */ 683 } 684 685 /* Release dispatcher lock */ 686 KiReleaseDispatcherLockFromDpcLevel(); 687 688 /* Check if there's an APC state to restore */ 689 if (ApcState->Process) 690 { 691 /* Restore the APC State */ 692 KiMoveApcState(ApcState, &Thread->ApcState); 693 } 694 else 695 { 696 /* The ApcState parameter is useless, so use the saved data and reset it */ 697 KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState); 698 Thread->SavedApcState.Process = NULL; 699 Thread->ApcStateIndex = OriginalApcEnvironment; 700 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 701 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 702 } 703 704 /* Release lock */ 705 KiReleaseApcLockFromDpcLevel(&ApcLock); 706 707 /* Swap Processes */ 708 KiSwapProcess(Thread->ApcState.Process, Process); 709 710 /* Exit the dispatcher */ 711 KiExitDispatcher(ApcLock.OldIrql); 712 713 /* Check if we have pending APCs */ 714 if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode])) 715 { 716 /* What do you know, we do! Request them to be delivered */ 717 Thread->ApcState.KernelApcPending = TRUE; 718 HalRequestSoftwareInterrupt(APC_LEVEL); 719 } 720 } 721 722 /* 723 * @implemented 724 */ 725 ULONG 726 NTAPI 727 KeQueryRuntimeProcess(IN PKPROCESS Process, 728 OUT PULONG UserTime) 729 { 730 ULONG TotalUser, TotalKernel; 731 KLOCK_QUEUE_HANDLE ProcessLock; 732 PLIST_ENTRY NextEntry, ListHead; 733 PKTHREAD Thread; 734 735 ASSERT_PROCESS(Process); 736 737 /* Initialize user and kernel times */ 738 TotalUser = Process->UserTime; 739 TotalKernel = Process->KernelTime; 740 741 /* Lock the process */ 742 KiAcquireProcessLock(Process, &ProcessLock); 743 744 /* Loop all child threads and sum up their times */ 745 ListHead = &Process->ThreadListHead; 746 NextEntry = ListHead->Flink; 747 while (ListHead != NextEntry) 748 { 749 /* Get the thread */ 750 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 751 752 /* Sum up times */ 753 TotalKernel += Thread->KernelTime; 754 TotalUser += Thread->UserTime; 755 756 /* Go to the next one */ 757 NextEntry = NextEntry->Flink; 758 } 759 760 /* Release lock */ 761 KiReleaseProcessLock(&ProcessLock); 762 763 /* Return the user time */ 764 *UserTime = TotalUser; 765 766 /* Return the kernel time */ 767 return TotalKernel; 768 } 769 770 /* 771 * @implemented 772 */ 773 BOOLEAN 774 NTAPI 775 KeAddSystemServiceTable(IN PULONG_PTR Base, 776 IN PULONG Count OPTIONAL, 777 IN ULONG Limit, 778 IN PUCHAR Number, 779 IN ULONG Index) 780 { 781 PAGED_CODE(); 782 783 /* Check if descriptor table entry is free */ 784 if ((Index > SSDT_MAX_ENTRIES - 1) || 785 (KeServiceDescriptorTable[Index].Base) || 786 (KeServiceDescriptorTableShadow[Index].Base)) 787 { 788 /* It's not, fail */ 789 return FALSE; 790 } 791 792 /* Initialize the shadow service descriptor table */ 793 KeServiceDescriptorTableShadow[Index].Base = Base; 794 KeServiceDescriptorTableShadow[Index].Limit = Limit; 795 KeServiceDescriptorTableShadow[Index].Number = Number; 796 KeServiceDescriptorTableShadow[Index].Count = Count; 797 return TRUE; 798 } 799 800 /* 801 * @implemented 802 */ 803 BOOLEAN 804 NTAPI 805 KeRemoveSystemServiceTable(IN ULONG Index) 806 { 807 PAGED_CODE(); 808 809 /* Make sure the Index is valid */ 810 if (Index > (SSDT_MAX_ENTRIES - 1)) return FALSE; 811 812 /* Is there a Normal Descriptor Table? */ 813 if (!KeServiceDescriptorTable[Index].Base) 814 { 815 /* Not with the index, is there a shadow at least? */ 816 if (!KeServiceDescriptorTableShadow[Index].Base) return FALSE; 817 } 818 819 /* Now clear from the Shadow Table. */ 820 KeServiceDescriptorTableShadow[Index].Base = NULL; 821 KeServiceDescriptorTableShadow[Index].Number = NULL; 822 KeServiceDescriptorTableShadow[Index].Limit = 0; 823 KeServiceDescriptorTableShadow[Index].Count = NULL; 824 825 /* Check if we should clean from the Master one too */ 826 if (Index == 1) 827 { 828 KeServiceDescriptorTable[Index].Base = NULL; 829 KeServiceDescriptorTable[Index].Number = NULL; 830 KeServiceDescriptorTable[Index].Limit = 0; 831 KeServiceDescriptorTable[Index].Count = NULL; 832 } 833 834 /* Return success */ 835 return TRUE; 836 } 837 /* EOF */ 838