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