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