1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/thrdobj.c 5 * PURPOSE: Implements routines to manage the Kernel Thread Object 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]; 16 extern LIST_ENTRY PspReaperListHead; 17 18 ULONG KiMask32Array[MAXIMUM_PRIORITY] = 19 { 20 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 21 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 22 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 23 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000, 24 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000, 25 0x40000000, 0x80000000 26 }; 27 28 /* FUNCTIONS *****************************************************************/ 29 30 UCHAR 31 NTAPI 32 KeFindNextRightSetAffinity(IN UCHAR Number, 33 IN ULONG Set) 34 { 35 ULONG Bit, Result; 36 ASSERT(Set != 0); 37 38 /* Calculate the mask */ 39 Bit = (AFFINITY_MASK(Number) - 1) & Set; 40 41 /* If it's 0, use the one we got */ 42 if (!Bit) Bit = Set; 43 44 /* Now find the right set and return it */ 45 BitScanReverse(&Result, Bit); 46 return (UCHAR)Result; 47 } 48 49 BOOLEAN 50 NTAPI 51 KeReadStateThread(IN PKTHREAD Thread) 52 { 53 ASSERT_THREAD(Thread); 54 55 /* Return signal state */ 56 return (BOOLEAN)Thread->Header.SignalState; 57 } 58 59 KPRIORITY 60 NTAPI 61 KeQueryBasePriorityThread(IN PKTHREAD Thread) 62 { 63 LONG BaseIncrement; 64 KIRQL OldIrql; 65 PKPROCESS Process; 66 ASSERT_THREAD(Thread); 67 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 68 69 /* Raise IRQL to synch level */ 70 OldIrql = KeRaiseIrqlToSynchLevel(); 71 72 /* Lock the thread */ 73 KiAcquireThreadLock(Thread); 74 75 /* Get the Process */ 76 Process = Thread->ApcStatePointer[0]->Process; 77 78 /* Calculate the base increment */ 79 BaseIncrement = Thread->BasePriority - Process->BasePriority; 80 81 /* If saturation occured, return the saturation increment instead */ 82 if (Thread->Saturation) BaseIncrement = (HIGH_PRIORITY + 1) / 2 * 83 Thread->Saturation; 84 85 /* Release thread lock */ 86 KiReleaseThreadLock(Thread); 87 88 /* Lower IRQl and return Increment */ 89 KeLowerIrql(OldIrql); 90 return BaseIncrement; 91 } 92 93 BOOLEAN 94 NTAPI 95 KeSetDisableBoostThread(IN OUT PKTHREAD Thread, 96 IN BOOLEAN Disable) 97 { 98 ASSERT_THREAD(Thread); 99 100 /* Check if we're enabling or disabling */ 101 if (Disable) 102 { 103 /* Set the bit */ 104 return InterlockedBitTestAndSet(&Thread->ThreadFlags, 1); 105 } 106 else 107 { 108 /* Remove the bit */ 109 return InterlockedBitTestAndReset(&Thread->ThreadFlags, 1); 110 } 111 } 112 113 VOID 114 NTAPI 115 KeReadyThread(IN PKTHREAD Thread) 116 { 117 KIRQL OldIrql; 118 ASSERT_THREAD(Thread); 119 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 120 121 /* Lock the Dispatcher Database */ 122 OldIrql = KiAcquireDispatcherLock(); 123 124 /* Make the thread ready */ 125 KiReadyThread(Thread); 126 127 /* Unlock dispatcher database */ 128 KiReleaseDispatcherLock(OldIrql); 129 } 130 131 ULONG 132 NTAPI 133 KeAlertResumeThread(IN PKTHREAD Thread) 134 { 135 ULONG PreviousCount; 136 KLOCK_QUEUE_HANDLE ApcLock; 137 ASSERT_THREAD(Thread); 138 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 139 140 /* Lock the Dispatcher Database and the APC Queue */ 141 KiAcquireApcLock(Thread, &ApcLock); 142 KiAcquireDispatcherLockAtDpcLevel(); 143 144 /* Return if Thread is already alerted. */ 145 if (!Thread->Alerted[KernelMode]) 146 { 147 /* If it's Blocked, unblock if it we should */ 148 if ((Thread->State == Waiting) && (Thread->Alertable)) 149 { 150 /* Abort the wait */ 151 KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); 152 } 153 else 154 { 155 /* If not, simply Alert it */ 156 Thread->Alerted[KernelMode] = TRUE; 157 } 158 } 159 160 /* Save the old Suspend Count */ 161 PreviousCount = Thread->SuspendCount; 162 163 /* If the thread is suspended, decrease one of the suspend counts */ 164 if (PreviousCount) 165 { 166 /* Decrease count. If we are now zero, unwait it completely */ 167 Thread->SuspendCount--; 168 if (!(Thread->SuspendCount) && !(Thread->FreezeCount)) 169 { 170 /* Signal and satisfy */ 171 Thread->SuspendSemaphore.Header.SignalState++; 172 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); 173 } 174 } 175 176 /* Release Locks and return the Old State */ 177 KiReleaseDispatcherLockFromDpcLevel(); 178 KiReleaseApcLockFromDpcLevel(&ApcLock); 179 KiExitDispatcher(ApcLock.OldIrql); 180 return PreviousCount; 181 } 182 183 BOOLEAN 184 NTAPI 185 KeAlertThread(IN PKTHREAD Thread, 186 IN KPROCESSOR_MODE AlertMode) 187 { 188 BOOLEAN PreviousState; 189 KLOCK_QUEUE_HANDLE ApcLock; 190 ASSERT_THREAD(Thread); 191 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 192 193 /* Lock the Dispatcher Database and the APC Queue */ 194 KiAcquireApcLock(Thread, &ApcLock); 195 KiAcquireDispatcherLockAtDpcLevel(); 196 197 /* Save the Previous State */ 198 PreviousState = Thread->Alerted[AlertMode]; 199 200 /* Check if it's already alerted */ 201 if (!PreviousState) 202 { 203 /* Check if the thread is alertable, and blocked in the given mode */ 204 if ((Thread->State == Waiting) && 205 (Thread->Alertable) && 206 (AlertMode <= Thread->WaitMode)) 207 { 208 /* Abort the wait to alert the thread */ 209 KiUnwaitThread(Thread, STATUS_ALERTED, THREAD_ALERT_INCREMENT); 210 } 211 else 212 { 213 /* Otherwise, merely set the alerted state */ 214 Thread->Alerted[AlertMode] = TRUE; 215 } 216 } 217 218 /* Release the Dispatcher Lock */ 219 KiReleaseDispatcherLockFromDpcLevel(); 220 KiReleaseApcLockFromDpcLevel(&ApcLock); 221 KiExitDispatcher(ApcLock.OldIrql); 222 223 /* Return the old state */ 224 return PreviousState; 225 } 226 227 VOID 228 NTAPI 229 KeBoostPriorityThread(IN PKTHREAD Thread, 230 IN KPRIORITY Increment) 231 { 232 KIRQL OldIrql; 233 KPRIORITY Priority; 234 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 235 236 /* Lock the Dispatcher Database */ 237 OldIrql = KiAcquireDispatcherLock(); 238 239 /* Only threads in the dynamic range get boosts */ 240 if (Thread->Priority < LOW_REALTIME_PRIORITY) 241 { 242 /* Lock the thread */ 243 KiAcquireThreadLock(Thread); 244 245 /* Check again, and make sure there's not already a boost */ 246 if ((Thread->Priority < LOW_REALTIME_PRIORITY) && 247 !(Thread->PriorityDecrement)) 248 { 249 /* Compute the new priority and see if it's higher */ 250 Priority = Thread->BasePriority + Increment; 251 if (Priority > Thread->Priority) 252 { 253 if (Priority >= LOW_REALTIME_PRIORITY) 254 { 255 Priority = LOW_REALTIME_PRIORITY - 1; 256 } 257 258 /* Reset the quantum */ 259 Thread->Quantum = Thread->QuantumReset; 260 261 /* Set the new Priority */ 262 KiSetPriorityThread(Thread, Priority); 263 } 264 } 265 266 /* Release thread lock */ 267 KiReleaseThreadLock(Thread); 268 } 269 270 /* Release the dispatcher lokc */ 271 KiReleaseDispatcherLock(OldIrql); 272 } 273 274 ULONG 275 NTAPI 276 KeForceResumeThread(IN PKTHREAD Thread) 277 { 278 KLOCK_QUEUE_HANDLE ApcLock; 279 ULONG PreviousCount; 280 ASSERT_THREAD(Thread); 281 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 282 283 /* Lock the APC Queue */ 284 KiAcquireApcLock(Thread, &ApcLock); 285 286 /* Save the old Suspend Count */ 287 PreviousCount = Thread->SuspendCount + Thread->FreezeCount; 288 289 /* If the thread is suspended, wake it up!!! */ 290 if (PreviousCount) 291 { 292 /* Unwait it completely */ 293 Thread->SuspendCount = 0; 294 Thread->FreezeCount = 0; 295 296 /* Lock the dispatcher */ 297 KiAcquireDispatcherLockAtDpcLevel(); 298 299 /* Signal and satisfy */ 300 Thread->SuspendSemaphore.Header.SignalState++; 301 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); 302 303 /* Release the dispatcher */ 304 KiReleaseDispatcherLockFromDpcLevel(); 305 } 306 307 /* Release Lock and return the Old State */ 308 KiReleaseApcLockFromDpcLevel(&ApcLock); 309 KiExitDispatcher(ApcLock.OldIrql); 310 return PreviousCount; 311 } 312 313 VOID 314 NTAPI 315 KeFreezeAllThreads(VOID) 316 { 317 KLOCK_QUEUE_HANDLE LockHandle, ApcLock; 318 PKTHREAD Current, CurrentThread = KeGetCurrentThread(); 319 PKPROCESS Process = CurrentThread->ApcState.Process; 320 PLIST_ENTRY ListHead, NextEntry; 321 LONG OldCount; 322 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 323 324 /* Lock the process */ 325 KiAcquireProcessLock(Process, &LockHandle); 326 327 /* If someone is already trying to free us, try again */ 328 while (CurrentThread->FreezeCount) 329 { 330 /* Release and re-acquire the process lock so the APC will go through */ 331 KiReleaseProcessLock(&LockHandle); 332 KiAcquireProcessLock(Process, &LockHandle); 333 } 334 335 /* Enter a critical region */ 336 KeEnterCriticalRegion(); 337 338 /* Loop the Process's Threads */ 339 ListHead = &Process->ThreadListHead; 340 NextEntry = ListHead->Flink; 341 do 342 { 343 /* Get the current thread */ 344 Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 345 346 /* Lock it */ 347 KiAcquireApcLockAtDpcLevel(Current, &ApcLock); 348 349 /* Make sure it's not ours, and check if APCs are enabled */ 350 if ((Current != CurrentThread) && (Current->ApcQueueable)) 351 { 352 /* Sanity check */ 353 OldCount = Current->SuspendCount; 354 ASSERT(OldCount != MAXIMUM_SUSPEND_COUNT); 355 356 /* Increase the freeze count */ 357 Current->FreezeCount++; 358 359 /* Make sure it wasn't already suspended */ 360 if (!(OldCount) && !(Current->SuspendCount)) 361 { 362 /* Did we already insert it? */ 363 if (!Current->SuspendApc.Inserted) 364 { 365 /* Insert the APC */ 366 Current->SuspendApc.Inserted = TRUE; 367 KiInsertQueueApc(&Current->SuspendApc, IO_NO_INCREMENT); 368 } 369 else 370 { 371 /* Lock the dispatcher */ 372 KiAcquireDispatcherLockAtDpcLevel(); 373 374 /* Unsignal the semaphore, the APC was already inserted */ 375 Current->SuspendSemaphore.Header.SignalState--; 376 377 /* Release the dispatcher */ 378 KiReleaseDispatcherLockFromDpcLevel(); 379 } 380 } 381 } 382 383 /* Release the APC lock */ 384 KiReleaseApcLockFromDpcLevel(&ApcLock); 385 386 /* Move to the next thread */ 387 NextEntry = NextEntry->Flink; 388 } while (NextEntry != ListHead); 389 390 /* Release the process lock and exit the dispatcher */ 391 KiReleaseProcessLockFromDpcLevel(&LockHandle); 392 KiExitDispatcher(LockHandle.OldIrql); 393 } 394 395 ULONG 396 NTAPI 397 KeResumeThread(IN PKTHREAD Thread) 398 { 399 KLOCK_QUEUE_HANDLE ApcLock; 400 ULONG PreviousCount; 401 ASSERT_THREAD(Thread); 402 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 403 404 /* Lock the APC Queue */ 405 KiAcquireApcLock(Thread, &ApcLock); 406 407 /* Save the Old Count */ 408 PreviousCount = Thread->SuspendCount; 409 410 /* Check if it existed */ 411 if (PreviousCount) 412 { 413 /* Decrease the suspend count */ 414 Thread->SuspendCount--; 415 416 /* Check if the thrad is still suspended or not */ 417 if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) 418 { 419 /* Acquire the dispatcher lock */ 420 KiAcquireDispatcherLockAtDpcLevel(); 421 422 /* Signal the Suspend Semaphore */ 423 Thread->SuspendSemaphore.Header.SignalState++; 424 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); 425 426 /* Release the dispatcher lock */ 427 KiReleaseDispatcherLockFromDpcLevel(); 428 } 429 } 430 431 /* Release APC Queue lock and return the Old State */ 432 KiReleaseApcLockFromDpcLevel(&ApcLock); 433 KiExitDispatcher(ApcLock.OldIrql); 434 return PreviousCount; 435 } 436 437 VOID 438 NTAPI 439 KeRundownThread(VOID) 440 { 441 KIRQL OldIrql; 442 PKTHREAD Thread = KeGetCurrentThread(); 443 PLIST_ENTRY NextEntry, ListHead; 444 PKMUTANT Mutant; 445 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 446 447 /* Optimized path if nothing is on the list at the moment */ 448 if (IsListEmpty(&Thread->MutantListHead)) return; 449 450 /* Lock the Dispatcher Database */ 451 OldIrql = KiAcquireDispatcherLock(); 452 453 /* Get the List Pointers */ 454 ListHead = &Thread->MutantListHead; 455 NextEntry = ListHead->Flink; 456 while (NextEntry != ListHead) 457 { 458 /* Get the Mutant */ 459 Mutant = CONTAINING_RECORD(NextEntry, KMUTANT, MutantListEntry); 460 ASSERT_MUTANT(Mutant); 461 462 /* Make sure it's not terminating with APCs off */ 463 if (Mutant->ApcDisable) 464 { 465 /* Bugcheck the system */ 466 KeBugCheckEx(THREAD_TERMINATE_HELD_MUTEX, 467 (ULONG_PTR)Thread, 468 (ULONG_PTR)Mutant, 469 0, 470 0); 471 } 472 473 /* Now we can remove it */ 474 RemoveEntryList(&Mutant->MutantListEntry); 475 476 /* Unconditionally abandon it */ 477 Mutant->Header.SignalState = 1; 478 Mutant->Abandoned = TRUE; 479 Mutant->OwnerThread = NULL; 480 481 /* Check if the Wait List isn't empty */ 482 if (!IsListEmpty(&Mutant->Header.WaitListHead)) 483 { 484 /* Wake the Mutant */ 485 KiWaitTest(&Mutant->Header, MUTANT_INCREMENT); 486 } 487 488 /* Move on */ 489 NextEntry = Thread->MutantListHead.Flink; 490 } 491 492 /* Release the Lock */ 493 KiReleaseDispatcherLock(OldIrql); 494 } 495 496 VOID 497 NTAPI 498 KeStartThread(IN OUT PKTHREAD Thread) 499 { 500 KLOCK_QUEUE_HANDLE LockHandle; 501 #ifdef CONFIG_SMP 502 PKNODE Node; 503 PKPRCB NodePrcb; 504 ULONG Set, Mask; 505 #endif 506 UCHAR IdealProcessor = 0; 507 PKPROCESS Process = Thread->ApcState.Process; 508 509 /* Setup static fields from parent */ 510 Thread->DisableBoost = Process->DisableBoost; 511 #if defined(_M_IX86) 512 Thread->Iopl = Process->Iopl; 513 #endif 514 Thread->Quantum = Process->QuantumReset; 515 Thread->QuantumReset = Process->QuantumReset; 516 Thread->SystemAffinityActive = FALSE; 517 518 /* Lock the process */ 519 KiAcquireProcessLock(Process, &LockHandle); 520 521 /* Setup volatile data */ 522 Thread->Priority = Process->BasePriority; 523 Thread->BasePriority = Process->BasePriority; 524 Thread->Affinity = Process->Affinity; 525 Thread->UserAffinity = Process->Affinity; 526 527 #ifdef CONFIG_SMP 528 /* Get the KNODE and its PRCB */ 529 Node = KeNodeBlock[Process->IdealNode]; 530 NodePrcb = KiProcessorBlock[Process->ThreadSeed]; 531 532 /* Calculate affinity mask */ 533 #ifdef _M_ARM 534 DbgBreakPoint(); 535 Set = 0; 536 #else 537 Set = ~NodePrcb->MultiThreadProcessorSet; 538 #endif 539 Mask = (ULONG)(Node->ProcessorMask & Process->Affinity); 540 Set &= Mask; 541 if (Set) Mask = Set; 542 543 /* Get the new thread seed */ 544 IdealProcessor = KeFindNextRightSetAffinity(Process->ThreadSeed, Mask); 545 Process->ThreadSeed = IdealProcessor; 546 547 /* Sanity check */ 548 ASSERT((Thread->UserAffinity & AFFINITY_MASK(IdealProcessor))); 549 #endif 550 551 /* Set the Ideal Processor */ 552 Thread->IdealProcessor = IdealProcessor; 553 Thread->UserIdealProcessor = IdealProcessor; 554 555 /* Lock the Dispatcher Database */ 556 KiAcquireDispatcherLockAtDpcLevel(); 557 558 /* Insert the thread into the process list */ 559 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry); 560 561 /* Increase the stack count */ 562 ASSERT(Process->StackCount != MAXULONG_PTR); 563 Process->StackCount++; 564 565 /* Release locks and return */ 566 KiReleaseDispatcherLockFromDpcLevel(); 567 KiReleaseProcessLock(&LockHandle); 568 } 569 570 VOID 571 NTAPI 572 KiSuspendRundown(IN PKAPC Apc) 573 { 574 /* Does nothing */ 575 UNREFERENCED_PARAMETER(Apc); 576 } 577 578 VOID 579 NTAPI 580 KiSuspendNop(IN PKAPC Apc, 581 IN PKNORMAL_ROUTINE *NormalRoutine, 582 IN PVOID *NormalContext, 583 IN PVOID *SystemArgument1, 584 IN PVOID *SystemArgument2) 585 { 586 /* Does nothing */ 587 UNREFERENCED_PARAMETER(Apc); 588 UNREFERENCED_PARAMETER(NormalRoutine); 589 UNREFERENCED_PARAMETER(NormalContext); 590 UNREFERENCED_PARAMETER(SystemArgument1); 591 UNREFERENCED_PARAMETER(SystemArgument2); 592 } 593 594 VOID 595 NTAPI 596 KiSuspendThread(IN PVOID NormalContext, 597 IN PVOID SystemArgument1, 598 IN PVOID SystemArgument2) 599 { 600 /* Non-alertable kernel-mode suspended wait */ 601 KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore, 602 Suspended, 603 KernelMode, 604 FALSE, 605 NULL); 606 } 607 608 ULONG 609 NTAPI 610 KeSuspendThread(PKTHREAD Thread) 611 { 612 KLOCK_QUEUE_HANDLE ApcLock; 613 ULONG PreviousCount; 614 ASSERT_THREAD(Thread); 615 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 616 617 /* Lock the APC Queue */ 618 KiAcquireApcLock(Thread, &ApcLock); 619 620 /* Save the Old Count */ 621 PreviousCount = Thread->SuspendCount; 622 623 /* Handle the maximum */ 624 if (PreviousCount == MAXIMUM_SUSPEND_COUNT) 625 { 626 /* Raise an exception */ 627 KiReleaseApcLock(&ApcLock); 628 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED); 629 } 630 631 /* Should we bother to queue at all? */ 632 if (Thread->ApcQueueable) 633 { 634 /* Increment the suspend count */ 635 Thread->SuspendCount++; 636 637 /* Check if we should suspend it */ 638 if (!(PreviousCount) && !(Thread->FreezeCount)) 639 { 640 /* Is the APC already inserted? */ 641 if (!Thread->SuspendApc.Inserted) 642 { 643 /* Not inserted, insert it */ 644 Thread->SuspendApc.Inserted = TRUE; 645 KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT); 646 } 647 else 648 { 649 /* Lock the dispatcher */ 650 KiAcquireDispatcherLockAtDpcLevel(); 651 652 /* Unsignal the semaphore, the APC was already inserted */ 653 Thread->SuspendSemaphore.Header.SignalState--; 654 655 /* Release the dispatcher */ 656 KiReleaseDispatcherLockFromDpcLevel(); 657 } 658 } 659 } 660 661 /* Release Lock and return the Old State */ 662 KiReleaseApcLockFromDpcLevel(&ApcLock); 663 KiExitDispatcher(ApcLock.OldIrql); 664 return PreviousCount; 665 } 666 667 VOID 668 NTAPI 669 KeThawAllThreads(VOID) 670 { 671 KLOCK_QUEUE_HANDLE LockHandle, ApcLock; 672 PKTHREAD Current, CurrentThread = KeGetCurrentThread(); 673 PKPROCESS Process = CurrentThread->ApcState.Process; 674 PLIST_ENTRY ListHead, NextEntry; 675 LONG OldCount; 676 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 677 678 /* Lock the process */ 679 KiAcquireProcessLock(Process, &LockHandle); 680 681 /* Loop the Process's Threads */ 682 ListHead = &Process->ThreadListHead; 683 NextEntry = ListHead->Flink; 684 do 685 { 686 /* Get the current thread */ 687 Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry); 688 689 /* Lock it */ 690 KiAcquireApcLockAtDpcLevel(Current, &ApcLock); 691 692 /* Make sure we are frozen */ 693 OldCount = Current->FreezeCount; 694 if (OldCount) 695 { 696 /* Decrease the freeze count */ 697 Current->FreezeCount--; 698 699 /* Check if both counts are zero now */ 700 if (!(Current->SuspendCount) && (!Current->FreezeCount)) 701 { 702 /* Lock the dispatcher */ 703 KiAcquireDispatcherLockAtDpcLevel(); 704 705 /* Signal the suspend semaphore and wake it */ 706 Current->SuspendSemaphore.Header.SignalState++; 707 KiWaitTest(&Current->SuspendSemaphore, 0); 708 709 /* Unlock the dispatcher */ 710 KiReleaseDispatcherLockFromDpcLevel(); 711 } 712 } 713 714 /* Release the APC lock */ 715 KiReleaseApcLockFromDpcLevel(&ApcLock); 716 717 /* Go to the next one */ 718 NextEntry = NextEntry->Flink; 719 } while (NextEntry != ListHead); 720 721 /* Release the process lock and exit the dispatcher */ 722 KiReleaseProcessLockFromDpcLevel(&LockHandle); 723 KiExitDispatcher(LockHandle.OldIrql); 724 725 /* Leave the critical region */ 726 KeLeaveCriticalRegion(); 727 } 728 729 BOOLEAN 730 NTAPI 731 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode) 732 { 733 PKTHREAD Thread = KeGetCurrentThread(); 734 BOOLEAN OldState; 735 KLOCK_QUEUE_HANDLE ApcLock; 736 ASSERT_THREAD(Thread); 737 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 738 739 /* Lock the Dispatcher Database and the APC Queue */ 740 KiAcquireApcLock(Thread, &ApcLock); 741 742 /* Save the old State */ 743 OldState = Thread->Alerted[AlertMode]; 744 745 /* Check the Thread is alerted */ 746 if (OldState) 747 { 748 /* Disable alert for this mode */ 749 Thread->Alerted[AlertMode] = FALSE; 750 } 751 else if ((AlertMode != KernelMode) && 752 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]))) 753 { 754 /* If the mode is User and the Queue isn't empty, set Pending */ 755 Thread->ApcState.UserApcPending = TRUE; 756 } 757 758 /* Release Locks and return the Old State */ 759 KiReleaseApcLock(&ApcLock); 760 return OldState; 761 } 762 763 NTSTATUS 764 NTAPI 765 KeInitThread(IN OUT PKTHREAD Thread, 766 IN PVOID KernelStack, 767 IN PKSYSTEM_ROUTINE SystemRoutine, 768 IN PKSTART_ROUTINE StartRoutine, 769 IN PVOID StartContext, 770 IN PCONTEXT Context, 771 IN PVOID Teb, 772 IN PKPROCESS Process) 773 { 774 BOOLEAN AllocatedStack = FALSE; 775 ULONG i; 776 PKWAIT_BLOCK TimerWaitBlock; 777 PKTIMER Timer; 778 NTSTATUS Status; 779 780 /* Initialize the Dispatcher Header */ 781 Thread->Header.Type = ThreadObject; 782 Thread->Header.ThreadControlFlags = 0; 783 Thread->Header.DebugActive = FALSE; 784 Thread->Header.SignalState = 0; 785 InitializeListHead(&(Thread->Header.WaitListHead)); 786 787 /* Initialize the Mutant List */ 788 InitializeListHead(&Thread->MutantListHead); 789 790 /* Initialize the wait blocks */ 791 for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++) 792 { 793 /* Put our pointer */ 794 Thread->WaitBlock[i].Thread = Thread; 795 } 796 797 /* Set swap settings */ 798 Thread->EnableStackSwap = TRUE; 799 Thread->IdealProcessor = 1; 800 Thread->SwapBusy = FALSE; 801 Thread->KernelStackResident = TRUE; 802 Thread->AdjustReason = AdjustNone; 803 804 /* Initialize the lock */ 805 KeInitializeSpinLock(&Thread->ThreadLock); 806 807 /* Setup the Service Descriptor Table for Native Calls */ 808 Thread->ServiceTable = KeServiceDescriptorTable; 809 810 /* Setup APC Fields */ 811 InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]); 812 InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]); 813 Thread->ApcState.Process = Process; 814 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState; 815 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState; 816 Thread->ApcStateIndex = OriginalApcEnvironment; 817 Thread->ApcQueueable = TRUE; 818 KeInitializeSpinLock(&Thread->ApcQueueLock); 819 820 /* Initialize the Suspend APC */ 821 KeInitializeApc(&Thread->SuspendApc, 822 Thread, 823 OriginalApcEnvironment, 824 KiSuspendNop, 825 KiSuspendRundown, 826 KiSuspendThread, 827 KernelMode, 828 NULL); 829 830 /* Initialize the Suspend Semaphore */ 831 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2); 832 833 /* Setup the timer */ 834 Timer = &Thread->Timer; 835 KeInitializeTimer(Timer); 836 TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK]; 837 TimerWaitBlock->Object = Timer; 838 TimerWaitBlock->WaitKey = STATUS_TIMEOUT; 839 TimerWaitBlock->WaitType = WaitAny; 840 TimerWaitBlock->NextWaitBlock = NULL; 841 842 /* Link the two wait lists together */ 843 TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead; 844 TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead; 845 846 /* Set the TEB and process */ 847 Thread->Teb = Teb; 848 Thread->Process = Process; 849 850 /* Check if we have a kernel stack */ 851 if (!KernelStack) 852 { 853 /* We don't, allocate one */ 854 KernelStack = MmCreateKernelStack(FALSE, 0); 855 if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES; 856 857 /* Remember for later */ 858 AllocatedStack = TRUE; 859 } 860 861 /* Set the Thread Stacks */ 862 Thread->InitialStack = KernelStack; 863 Thread->StackBase = KernelStack; 864 Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE; 865 Thread->KernelStackResident = TRUE; 866 867 /* Enter SEH to avoid crashes due to user mode */ 868 Status = STATUS_SUCCESS; 869 _SEH2_TRY 870 { 871 /* Initialize the Thread Context */ 872 KiInitializeContextThread(Thread, 873 SystemRoutine, 874 StartRoutine, 875 StartContext, 876 Context); 877 } 878 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 879 { 880 /* Set failure status */ 881 Status = STATUS_UNSUCCESSFUL; 882 883 /* Check if a stack was allocated */ 884 if (AllocatedStack) 885 { 886 /* Delete the stack */ 887 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE); 888 Thread->InitialStack = NULL; 889 } 890 } 891 _SEH2_END; 892 893 /* Set the Thread to initialized */ 894 Thread->State = Initialized; 895 return Status; 896 } 897 898 VOID 899 NTAPI 900 KeInitializeThread(IN PKPROCESS Process, 901 IN OUT PKTHREAD Thread, 902 IN PKSYSTEM_ROUTINE SystemRoutine, 903 IN PKSTART_ROUTINE StartRoutine, 904 IN PVOID StartContext, 905 IN PCONTEXT Context, 906 IN PVOID Teb, 907 IN PVOID KernelStack) 908 { 909 /* Initialize and start the thread on success */ 910 if (NT_SUCCESS(KeInitThread(Thread, 911 KernelStack, 912 SystemRoutine, 913 StartRoutine, 914 StartContext, 915 Context, 916 Teb, 917 Process))) 918 { 919 /* Start it */ 920 KeStartThread(Thread); 921 } 922 } 923 924 VOID 925 NTAPI 926 KeUninitThread(IN PKTHREAD Thread) 927 { 928 /* Delete the stack */ 929 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE); 930 Thread->InitialStack = NULL; 931 } 932 933 /* PUBLIC FUNCTIONS **********************************************************/ 934 935 /* 936 * @unimplemented 937 */ 938 VOID 939 NTAPI 940 KeCapturePersistentThreadState(IN PVOID CurrentThread, 941 IN ULONG Setting1, 942 IN ULONG Setting2, 943 IN ULONG Setting3, 944 IN ULONG Setting4, 945 IN ULONG Setting5, 946 IN PVOID ThreadState) 947 { 948 UNIMPLEMENTED; 949 } 950 951 /* 952 * @implemented 953 */ 954 #undef KeGetCurrentThread 955 PKTHREAD 956 NTAPI 957 KeGetCurrentThread(VOID) 958 { 959 /* Return the current thread on this PCR */ 960 return _KeGetCurrentThread(); 961 } 962 963 /* 964 * @implemented 965 */ 966 #undef KeGetPreviousMode 967 UCHAR 968 NTAPI 969 KeGetPreviousMode(VOID) 970 { 971 /* Return the previous mode of this thread */ 972 return _KeGetPreviousMode(); 973 } 974 975 /* 976 * @implemented 977 */ 978 ULONG 979 NTAPI 980 KeQueryRuntimeThread(IN PKTHREAD Thread, 981 OUT PULONG UserTime) 982 { 983 ASSERT_THREAD(Thread); 984 985 /* Return the User Time */ 986 *UserTime = Thread->UserTime; 987 988 /* Return the Kernel Time */ 989 return Thread->KernelTime; 990 } 991 992 /* 993 * @implemented 994 */ 995 BOOLEAN 996 NTAPI 997 KeSetKernelStackSwapEnable(IN BOOLEAN Enable) 998 { 999 BOOLEAN PreviousState; 1000 PKTHREAD Thread = KeGetCurrentThread(); 1001 1002 /* Save Old State */ 1003 PreviousState = Thread->EnableStackSwap; 1004 1005 /* Set New State */ 1006 Thread->EnableStackSwap = Enable; 1007 1008 /* Return Old State */ 1009 return PreviousState; 1010 } 1011 1012 /* 1013 * @implemented 1014 */ 1015 KPRIORITY 1016 NTAPI 1017 KeQueryPriorityThread(IN PKTHREAD Thread) 1018 { 1019 ASSERT_THREAD(Thread); 1020 1021 /* Return the current priority */ 1022 return Thread->Priority; 1023 } 1024 1025 /* 1026 * @implemented 1027 */ 1028 VOID 1029 NTAPI 1030 KeRevertToUserAffinityThread(VOID) 1031 { 1032 KIRQL OldIrql; 1033 PKPRCB Prcb; 1034 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread(); 1035 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1036 ASSERT(CurrentThread->SystemAffinityActive != FALSE); 1037 1038 /* Lock the Dispatcher Database */ 1039 OldIrql = KiAcquireDispatcherLock(); 1040 1041 /* Set the user affinity and processor and disable system affinity */ 1042 CurrentThread->Affinity = CurrentThread->UserAffinity; 1043 CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor; 1044 CurrentThread->SystemAffinityActive = FALSE; 1045 1046 /* Get the current PRCB and check if it doesn't match this affinity */ 1047 Prcb = KeGetCurrentPrcb(); 1048 if (!(Prcb->SetMember & CurrentThread->Affinity)) 1049 { 1050 /* Lock the PRCB */ 1051 KiAcquirePrcbLock(Prcb); 1052 1053 /* Check if there's no next thread scheduled */ 1054 if (!Prcb->NextThread) 1055 { 1056 /* Select a new thread and set it on standby */ 1057 NextThread = KiSelectNextThread(Prcb); 1058 NextThread->State = Standby; 1059 Prcb->NextThread = NextThread; 1060 } 1061 1062 /* Release the PRCB lock */ 1063 KiReleasePrcbLock(Prcb); 1064 } 1065 1066 /* Unlock dispatcher database */ 1067 KiReleaseDispatcherLock(OldIrql); 1068 } 1069 1070 /* 1071 * @implemented 1072 */ 1073 UCHAR 1074 NTAPI 1075 KeSetIdealProcessorThread(IN PKTHREAD Thread, 1076 IN UCHAR Processor) 1077 { 1078 CCHAR OldIdealProcessor; 1079 KIRQL OldIrql; 1080 ASSERT(Processor <= MAXIMUM_PROCESSORS); 1081 1082 /* Lock the Dispatcher Database */ 1083 OldIrql = KiAcquireDispatcherLock(); 1084 1085 /* Save Old Ideal Processor */ 1086 OldIdealProcessor = Thread->UserIdealProcessor; 1087 1088 /* Make sure a valid CPU was given */ 1089 if (Processor < KeNumberProcessors) 1090 { 1091 /* Check if the user ideal CPU is in the affinity */ 1092 if (Thread->Affinity & AFFINITY_MASK(Processor)) 1093 { 1094 /* Set the ideal processor */ 1095 Thread->IdealProcessor = Processor; 1096 1097 /* Check if system affinity is used */ 1098 if (!Thread->SystemAffinityActive) 1099 { 1100 /* It's not, so update the user CPU too */ 1101 Thread->UserIdealProcessor = Processor; 1102 } 1103 } 1104 } 1105 1106 /* Release dispatcher lock and return the old ideal CPU */ 1107 KiReleaseDispatcherLock(OldIrql); 1108 return OldIdealProcessor; 1109 } 1110 1111 /* 1112 * @implemented 1113 */ 1114 VOID 1115 NTAPI 1116 KeSetSystemAffinityThread(IN KAFFINITY Affinity) 1117 { 1118 KIRQL OldIrql; 1119 PKPRCB Prcb; 1120 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread(); 1121 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1122 ASSERT((Affinity & KeActiveProcessors) != 0); 1123 1124 /* Lock the Dispatcher Database */ 1125 OldIrql = KiAcquireDispatcherLock(); 1126 1127 /* Restore the affinity and enable system affinity */ 1128 CurrentThread->Affinity = Affinity; 1129 CurrentThread->SystemAffinityActive = TRUE; 1130 1131 /* Check if the ideal processor is part of the affinity */ 1132 #ifdef CONFIG_SMP 1133 if (!(Affinity & AFFINITY_MASK(CurrentThread->IdealProcessor))) 1134 { 1135 ULONG AffinitySet, NodeMask; 1136 1137 /* It's not! Get the PRCB */ 1138 Prcb = KiProcessorBlock[CurrentThread->IdealProcessor]; 1139 1140 /* Calculate the affinity set */ 1141 AffinitySet = KeActiveProcessors & Affinity; 1142 NodeMask = Prcb->ParentNode->ProcessorMask & AffinitySet; 1143 if (NodeMask) 1144 { 1145 /* Use the Node set instead */ 1146 AffinitySet = NodeMask; 1147 } 1148 1149 /* Calculate the ideal CPU from the affinity set */ 1150 BitScanReverse(&NodeMask, AffinitySet); 1151 CurrentThread->IdealProcessor = (UCHAR)NodeMask; 1152 } 1153 #endif 1154 1155 /* Get the current PRCB and check if it doesn't match this affinity */ 1156 Prcb = KeGetCurrentPrcb(); 1157 if (!(Prcb->SetMember & CurrentThread->Affinity)) 1158 { 1159 /* Lock the PRCB */ 1160 KiAcquirePrcbLock(Prcb); 1161 1162 /* Check if there's no next thread scheduled */ 1163 if (!Prcb->NextThread) 1164 { 1165 /* Select a new thread and set it on standby */ 1166 NextThread = KiSelectNextThread(Prcb); 1167 NextThread->State = Standby; 1168 Prcb->NextThread = NextThread; 1169 } 1170 1171 /* Release the PRCB lock */ 1172 KiReleasePrcbLock(Prcb); 1173 } 1174 1175 /* Unlock dispatcher database */ 1176 KiReleaseDispatcherLock(OldIrql); 1177 } 1178 1179 /* 1180 * @implemented 1181 */ 1182 LONG 1183 NTAPI 1184 KeSetBasePriorityThread(IN PKTHREAD Thread, 1185 IN LONG Increment) 1186 { 1187 KIRQL OldIrql; 1188 KPRIORITY OldBasePriority, Priority, BasePriority; 1189 LONG OldIncrement; 1190 PKPROCESS Process; 1191 ASSERT_THREAD(Thread); 1192 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1193 1194 /* Get the process */ 1195 Process = Thread->ApcState.Process; 1196 1197 /* Lock the Dispatcher Database */ 1198 OldIrql = KiAcquireDispatcherLock(); 1199 1200 /* Lock the thread */ 1201 KiAcquireThreadLock(Thread); 1202 1203 /* Save the old base priority and increment */ 1204 OldBasePriority = Thread->BasePriority; 1205 OldIncrement = OldBasePriority - Process->BasePriority; 1206 1207 /* If priority saturation happened, use the saturated increment */ 1208 if (Thread->Saturation) OldIncrement = (HIGH_PRIORITY + 1) / 2 * 1209 Thread->Saturation; 1210 1211 /* Reset the saturation value */ 1212 Thread->Saturation = 0; 1213 1214 /* Now check if saturation is being used for the new value */ 1215 if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2)) 1216 { 1217 /* Check if we need positive or negative saturation */ 1218 Thread->Saturation = (Increment > 0) ? 1 : -1; 1219 } 1220 1221 /* Normalize the Base Priority */ 1222 BasePriority = Process->BasePriority + Increment; 1223 if (Process->BasePriority >= LOW_REALTIME_PRIORITY) 1224 { 1225 /* Check if it's too low */ 1226 if (BasePriority < LOW_REALTIME_PRIORITY) 1227 { 1228 /* Set it to the lowest real time level */ 1229 BasePriority = LOW_REALTIME_PRIORITY; 1230 } 1231 1232 /* Check if it's too high */ 1233 if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY; 1234 1235 /* We are at real time, so use the raw base priority */ 1236 Priority = BasePriority; 1237 } 1238 else 1239 { 1240 /* Check if it's entering the real time range */ 1241 if (BasePriority >= LOW_REALTIME_PRIORITY) 1242 { 1243 /* Set it to the highest dynamic level */ 1244 BasePriority = LOW_REALTIME_PRIORITY - 1; 1245 } 1246 1247 /* Check if it's too low and normalize it */ 1248 if (BasePriority <= LOW_PRIORITY) BasePriority = 1; 1249 1250 /* Check if Saturation is used */ 1251 if (Thread->Saturation) 1252 { 1253 /* Use the raw base priority */ 1254 Priority = BasePriority; 1255 } 1256 else 1257 { 1258 /* Otherwise, calculate the new priority */ 1259 Priority = KiComputeNewPriority(Thread, 0); 1260 Priority += (BasePriority - OldBasePriority); 1261 1262 /* Check if it entered the real-time range */ 1263 if (Priority >= LOW_REALTIME_PRIORITY) 1264 { 1265 /* Normalize it down to the highest dynamic priority */ 1266 Priority = LOW_REALTIME_PRIORITY - 1; 1267 } 1268 else if (Priority <= LOW_PRIORITY) 1269 { 1270 /* It went too low, normalize it */ 1271 Priority = 1; 1272 } 1273 } 1274 } 1275 1276 /* Finally set the new base priority */ 1277 Thread->BasePriority = (SCHAR)BasePriority; 1278 1279 /* Reset the decrements */ 1280 Thread->PriorityDecrement = 0; 1281 1282 /* Check if we're changing priority after all */ 1283 if (Priority != Thread->Priority) 1284 { 1285 /* Reset the quantum and do the actual priority modification */ 1286 Thread->Quantum = Thread->QuantumReset; 1287 KiSetPriorityThread(Thread, Priority); 1288 } 1289 1290 /* Release thread lock */ 1291 KiReleaseThreadLock(Thread); 1292 1293 /* Release the dispatcher database and return old increment */ 1294 KiReleaseDispatcherLock(OldIrql); 1295 return OldIncrement; 1296 } 1297 1298 /* 1299 * @implemented 1300 */ 1301 KAFFINITY 1302 NTAPI 1303 KeSetAffinityThread(IN PKTHREAD Thread, 1304 IN KAFFINITY Affinity) 1305 { 1306 KIRQL OldIrql; 1307 KAFFINITY OldAffinity; 1308 ASSERT_THREAD(Thread); 1309 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1310 1311 /* Lock the dispatcher database */ 1312 OldIrql = KiAcquireDispatcherLock(); 1313 1314 /* Call the internal function */ 1315 OldAffinity = KiSetAffinityThread(Thread, Affinity); 1316 1317 /* Release the dispatcher database and return old affinity */ 1318 KiReleaseDispatcherLock(OldIrql); 1319 return OldAffinity; 1320 } 1321 1322 /* 1323 * @implemented 1324 */ 1325 KPRIORITY 1326 NTAPI 1327 KeSetPriorityThread(IN PKTHREAD Thread, 1328 IN KPRIORITY Priority) 1329 { 1330 KIRQL OldIrql; 1331 KPRIORITY OldPriority; 1332 ASSERT_THREAD(Thread); 1333 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1334 ASSERT((Priority <= HIGH_PRIORITY) && (Priority >= LOW_PRIORITY)); 1335 ASSERT(KeIsExecutingDpc() == FALSE); 1336 1337 /* Lock the Dispatcher Database */ 1338 OldIrql = KiAcquireDispatcherLock(); 1339 1340 /* Lock the thread */ 1341 KiAcquireThreadLock(Thread); 1342 1343 /* Save the old Priority and reset decrement */ 1344 OldPriority = Thread->Priority; 1345 Thread->PriorityDecrement = 0; 1346 1347 /* Make sure that an actual change is being done */ 1348 if (Priority != Thread->Priority) 1349 { 1350 /* Reset the quantum */ 1351 Thread->Quantum = Thread->QuantumReset; 1352 1353 /* Check if priority is being set too low and normalize if so */ 1354 if ((Thread->BasePriority != 0) && !(Priority)) Priority = 1; 1355 1356 /* Set the new Priority */ 1357 KiSetPriorityThread(Thread, Priority); 1358 } 1359 1360 /* Release thread lock */ 1361 KiReleaseThreadLock(Thread); 1362 1363 /* Release the dispatcher database */ 1364 KiReleaseDispatcherLock(OldIrql); 1365 1366 /* Return Old Priority */ 1367 return OldPriority; 1368 } 1369 1370 /* 1371 * @implemented 1372 */ 1373 VOID 1374 NTAPI 1375 KeTerminateThread(IN KPRIORITY Increment) 1376 { 1377 PLIST_ENTRY *ListHead; 1378 PETHREAD Entry, SavedEntry; 1379 PETHREAD *ThreadAddr; 1380 KLOCK_QUEUE_HANDLE LockHandle; 1381 PKTHREAD Thread = KeGetCurrentThread(); 1382 PKPROCESS Process = Thread->ApcState.Process; 1383 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1384 1385 /* Lock the process */ 1386 KiAcquireProcessLock(Process, &LockHandle); 1387 1388 /* Make sure we won't get Swapped */ 1389 KiSetThreadSwapBusy(Thread); 1390 1391 /* Save the Kernel and User Times */ 1392 Process->KernelTime += Thread->KernelTime; 1393 Process->UserTime += Thread->UserTime; 1394 1395 /* Get the current entry and our Port */ 1396 Entry = (PETHREAD)PspReaperListHead.Flink; 1397 ThreadAddr = &((PETHREAD)Thread)->ReaperLink; 1398 1399 /* Add it to the reaper's list */ 1400 do 1401 { 1402 /* Get the list head */ 1403 ListHead = &PspReaperListHead.Flink; 1404 1405 /* Link ourselves */ 1406 *ThreadAddr = Entry; 1407 SavedEntry = Entry; 1408 1409 /* Now try to do the exchange */ 1410 Entry = InterlockedCompareExchangePointer((PVOID*)ListHead, 1411 ThreadAddr, 1412 Entry); 1413 1414 /* Break out if the change was succesful */ 1415 } while (Entry != SavedEntry); 1416 1417 /* Acquire the dispatcher lock */ 1418 KiAcquireDispatcherLockAtDpcLevel(); 1419 1420 /* Check if the reaper wasn't active */ 1421 if (!Entry) 1422 { 1423 /* Activate it as a work item, directly through its Queue */ 1424 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue, 1425 &PspReaperWorkItem.List, 1426 FALSE); 1427 } 1428 1429 /* Check the thread has an associated queue */ 1430 if (Thread->Queue) 1431 { 1432 /* Remove it from the list, and handle the queue */ 1433 RemoveEntryList(&Thread->QueueListEntry); 1434 KiActivateWaiterQueue(Thread->Queue); 1435 } 1436 1437 /* Signal the thread */ 1438 Thread->Header.SignalState = TRUE; 1439 if (!IsListEmpty(&Thread->Header.WaitListHead)) 1440 { 1441 /* Unwait the threads */ 1442 KxUnwaitThread(&Thread->Header, Increment); 1443 } 1444 1445 /* Remove the thread from the list */ 1446 RemoveEntryList(&Thread->ThreadListEntry); 1447 1448 /* Release the process lock */ 1449 KiReleaseProcessLockFromDpcLevel(&LockHandle); 1450 1451 /* Set us as terminated, decrease the Process's stack count */ 1452 Thread->State = Terminated; 1453 1454 /* Decrease stack count */ 1455 ASSERT(Process->StackCount != 0); 1456 ASSERT(Process->State == ProcessInMemory); 1457 Process->StackCount--; 1458 if (!(Process->StackCount) && !(IsListEmpty(&Process->ThreadListHead))) 1459 { 1460 /* FIXME: Swap stacks */ 1461 } 1462 1463 /* Rundown arch-specific parts */ 1464 KiRundownThread(Thread); 1465 1466 /* Swap to a new thread */ 1467 KiReleaseDispatcherLockFromDpcLevel(); 1468 KiSwapThread(Thread, KeGetCurrentPrcb()); 1469 } 1470