xref: /reactos/ntoskrnl/ke/thrdobj.c (revision d6eebaa4)
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