Synchronize with trunk's revision r57652.
[reactos.git] / ntoskrnl / ke / thrdobj.c
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 Set = ~NodePrcb->MultiThreadProcessorSet;
534 Mask = (ULONG)(Node->ProcessorMask & Process->Affinity);
535 Set &= Mask;
536 if (Set) Mask = Set;
537
538 /* Get the new thread seed */
539 IdealProcessor = KeFindNextRightSetAffinity(Process->ThreadSeed, Mask);
540 Process->ThreadSeed = IdealProcessor;
541
542 /* Sanity check */
543 ASSERT((Thread->UserAffinity & AFFINITY_MASK(IdealProcessor)));
544 #endif
545
546 /* Set the Ideal Processor */
547 Thread->IdealProcessor = IdealProcessor;
548 Thread->UserIdealProcessor = IdealProcessor;
549
550 /* Lock the Dispatcher Database */
551 KiAcquireDispatcherLockAtDpcLevel();
552
553 /* Insert the thread into the process list */
554 InsertTailList(&Process->ThreadListHead, &Thread->ThreadListEntry);
555
556 /* Increase the stack count */
557 ASSERT(Process->StackCount != MAXULONG_PTR);
558 Process->StackCount++;
559
560 /* Release locks and return */
561 KiReleaseDispatcherLockFromDpcLevel();
562 KiReleaseProcessLock(&LockHandle);
563 }
564
565 VOID
566 NTAPI
567 KiSuspendRundown(IN PKAPC Apc)
568 {
569 /* Does nothing */
570 UNREFERENCED_PARAMETER(Apc);
571 }
572
573 VOID
574 NTAPI
575 KiSuspendNop(IN PKAPC Apc,
576 IN PKNORMAL_ROUTINE *NormalRoutine,
577 IN PVOID *NormalContext,
578 IN PVOID *SystemArgument1,
579 IN PVOID *SystemArgument2)
580 {
581 /* Does nothing */
582 UNREFERENCED_PARAMETER(Apc);
583 UNREFERENCED_PARAMETER(NormalRoutine);
584 UNREFERENCED_PARAMETER(NormalContext);
585 UNREFERENCED_PARAMETER(SystemArgument1);
586 UNREFERENCED_PARAMETER(SystemArgument2);
587 }
588
589 VOID
590 NTAPI
591 KiSuspendThread(IN PVOID NormalContext,
592 IN PVOID SystemArgument1,
593 IN PVOID SystemArgument2)
594 {
595 /* Non-alertable kernel-mode suspended wait */
596 KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore,
597 Suspended,
598 KernelMode,
599 FALSE,
600 NULL);
601 }
602
603 ULONG
604 NTAPI
605 KeSuspendThread(PKTHREAD Thread)
606 {
607 KLOCK_QUEUE_HANDLE ApcLock;
608 ULONG PreviousCount;
609 ASSERT_THREAD(Thread);
610 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
611
612 /* Lock the APC Queue */
613 KiAcquireApcLock(Thread, &ApcLock);
614
615 /* Save the Old Count */
616 PreviousCount = Thread->SuspendCount;
617
618 /* Handle the maximum */
619 if (PreviousCount == MAXIMUM_SUSPEND_COUNT)
620 {
621 /* Raise an exception */
622 KiReleaseApcLock(&ApcLock);
623 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED);
624 }
625
626 /* Should we bother to queue at all? */
627 if (Thread->ApcQueueable)
628 {
629 /* Increment the suspend count */
630 Thread->SuspendCount++;
631
632 /* Check if we should suspend it */
633 if (!(PreviousCount) && !(Thread->FreezeCount))
634 {
635 /* Is the APC already inserted? */
636 if (!Thread->SuspendApc.Inserted)
637 {
638 /* Not inserted, insert it */
639 Thread->SuspendApc.Inserted = TRUE;
640 KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT);
641 }
642 else
643 {
644 /* Lock the dispatcher */
645 KiAcquireDispatcherLockAtDpcLevel();
646
647 /* Unsignal the semaphore, the APC was already inserted */
648 Thread->SuspendSemaphore.Header.SignalState--;
649
650 /* Release the dispatcher */
651 KiReleaseDispatcherLockFromDpcLevel();
652 }
653 }
654 }
655
656 /* Release Lock and return the Old State */
657 KiReleaseApcLockFromDpcLevel(&ApcLock);
658 KiExitDispatcher(ApcLock.OldIrql);
659 return PreviousCount;
660 }
661
662 VOID
663 NTAPI
664 KeThawAllThreads(VOID)
665 {
666 KLOCK_QUEUE_HANDLE LockHandle, ApcLock;
667 PKTHREAD Current, CurrentThread = KeGetCurrentThread();
668 PKPROCESS Process = CurrentThread->ApcState.Process;
669 PLIST_ENTRY ListHead, NextEntry;
670 LONG OldCount;
671 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
672
673 /* Lock the process */
674 KiAcquireProcessLock(Process, &LockHandle);
675
676 /* Loop the Process's Threads */
677 ListHead = &Process->ThreadListHead;
678 NextEntry = ListHead->Flink;
679 do
680 {
681 /* Get the current thread */
682 Current = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
683
684 /* Lock it */
685 KiAcquireApcLockAtDpcLevel(Current, &ApcLock);
686
687 /* Make sure we are frozen */
688 OldCount = Current->FreezeCount;
689 if (OldCount)
690 {
691 /* Decrease the freeze count */
692 Current->FreezeCount--;
693
694 /* Check if both counts are zero now */
695 if (!(Current->SuspendCount) && (!Current->FreezeCount))
696 {
697 /* Lock the dispatcher */
698 KiAcquireDispatcherLockAtDpcLevel();
699
700 /* Signal the suspend semaphore and wake it */
701 Current->SuspendSemaphore.Header.SignalState++;
702 KiWaitTest(&Current->SuspendSemaphore, 0);
703
704 /* Unlock the dispatcher */
705 KiReleaseDispatcherLockFromDpcLevel();
706 }
707 }
708
709 /* Release the APC lock */
710 KiReleaseApcLockFromDpcLevel(&ApcLock);
711
712 /* Go to the next one */
713 NextEntry = NextEntry->Flink;
714 } while (NextEntry != ListHead);
715
716 /* Release the process lock and exit the dispatcher */
717 KiReleaseProcessLockFromDpcLevel(&LockHandle);
718 KiExitDispatcher(LockHandle.OldIrql);
719
720 /* Leave the critical region */
721 KeLeaveCriticalRegion();
722 }
723
724 BOOLEAN
725 NTAPI
726 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
727 {
728 PKTHREAD Thread = KeGetCurrentThread();
729 BOOLEAN OldState;
730 KLOCK_QUEUE_HANDLE ApcLock;
731 ASSERT_THREAD(Thread);
732 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
733
734 /* Lock the Dispatcher Database and the APC Queue */
735 KiAcquireApcLock(Thread, &ApcLock);
736
737 /* Save the old State */
738 OldState = Thread->Alerted[AlertMode];
739
740 /* Check the Thread is alerted */
741 if (OldState)
742 {
743 /* Disable alert for this mode */
744 Thread->Alerted[AlertMode] = FALSE;
745 }
746 else if ((AlertMode != KernelMode) &&
747 (!IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])))
748 {
749 /* If the mode is User and the Queue isn't empty, set Pending */
750 Thread->ApcState.UserApcPending = TRUE;
751 }
752
753 /* Release Locks and return the Old State */
754 KiReleaseApcLock(&ApcLock);
755 return OldState;
756 }
757
758 NTSTATUS
759 NTAPI
760 KeInitThread(IN OUT PKTHREAD Thread,
761 IN PVOID KernelStack,
762 IN PKSYSTEM_ROUTINE SystemRoutine,
763 IN PKSTART_ROUTINE StartRoutine,
764 IN PVOID StartContext,
765 IN PCONTEXT Context,
766 IN PVOID Teb,
767 IN PKPROCESS Process)
768 {
769 BOOLEAN AllocatedStack = FALSE;
770 ULONG i;
771 PKWAIT_BLOCK TimerWaitBlock;
772 PKTIMER Timer;
773 NTSTATUS Status;
774
775 /* Initalize the Dispatcher Header */
776 Thread->Header.Type = ThreadObject;
777 Thread->Header.ThreadControlFlags = 0;
778 Thread->Header.DebugActive = FALSE;
779 Thread->Header.SignalState = 0;
780 InitializeListHead(&(Thread->Header.WaitListHead));
781
782 /* Initialize the Mutant List */
783 InitializeListHead(&Thread->MutantListHead);
784
785 /* Initialize the wait blocks */
786 for (i = 0; i< (THREAD_WAIT_OBJECTS + 1); i++)
787 {
788 /* Put our pointer */
789 Thread->WaitBlock[i].Thread = Thread;
790 }
791
792 /* Set swap settings */
793 Thread->EnableStackSwap = TRUE;
794 Thread->IdealProcessor = 1;
795 Thread->SwapBusy = FALSE;
796 Thread->KernelStackResident = TRUE;
797 Thread->AdjustReason = AdjustNone;
798
799 /* Initialize the lock */
800 KeInitializeSpinLock(&Thread->ThreadLock);
801
802 /* Setup the Service Descriptor Table for Native Calls */
803 Thread->ServiceTable = KeServiceDescriptorTable;
804
805 /* Setup APC Fields */
806 InitializeListHead(&Thread->ApcState.ApcListHead[0]);
807 InitializeListHead(&Thread->ApcState.ApcListHead[1]);
808 Thread->ApcState.Process = Process;
809 Thread->ApcStatePointer[OriginalApcEnvironment] = &Thread->ApcState;
810 Thread->ApcStatePointer[AttachedApcEnvironment] = &Thread->SavedApcState;
811 Thread->ApcStateIndex = OriginalApcEnvironment;
812 Thread->ApcQueueable = TRUE;
813 KeInitializeSpinLock(&Thread->ApcQueueLock);
814
815 /* Initialize the Suspend APC */
816 KeInitializeApc(&Thread->SuspendApc,
817 Thread,
818 OriginalApcEnvironment,
819 KiSuspendNop,
820 KiSuspendRundown,
821 KiSuspendThread,
822 KernelMode,
823 NULL);
824
825 /* Initialize the Suspend Semaphore */
826 KeInitializeSemaphore(&Thread->SuspendSemaphore, 0, 2);
827
828 /* Setup the timer */
829 Timer = &Thread->Timer;
830 KeInitializeTimer(Timer);
831 TimerWaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
832 TimerWaitBlock->Object = Timer;
833 TimerWaitBlock->WaitKey = STATUS_TIMEOUT;
834 TimerWaitBlock->WaitType = WaitAny;
835 TimerWaitBlock->NextWaitBlock = NULL;
836
837 /* Link the two wait lists together */
838 TimerWaitBlock->WaitListEntry.Flink = &Timer->Header.WaitListHead;
839 TimerWaitBlock->WaitListEntry.Blink = &Timer->Header.WaitListHead;
840
841 /* Set the TEB */
842 Thread->Teb = Teb;
843
844 /* Check if we have a kernel stack */
845 if (!KernelStack)
846 {
847 /* We don't, allocate one */
848 KernelStack = MmCreateKernelStack(FALSE, 0);
849 if (!KernelStack) return STATUS_INSUFFICIENT_RESOURCES;
850
851 /* Remember for later */
852 AllocatedStack = TRUE;
853 }
854
855 /* Set the Thread Stacks */
856 Thread->InitialStack = KernelStack;
857 Thread->StackBase = KernelStack;
858 Thread->StackLimit = (ULONG_PTR)KernelStack - KERNEL_STACK_SIZE;
859 Thread->KernelStackResident = TRUE;
860
861 /* Enter SEH to avoid crashes due to user mode */
862 Status = STATUS_SUCCESS;
863 _SEH2_TRY
864 {
865 /* Initalize the Thread Context */
866 KiInitializeContextThread(Thread,
867 SystemRoutine,
868 StartRoutine,
869 StartContext,
870 Context);
871 }
872 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
873 {
874 /* Set failure status */
875 Status = STATUS_UNSUCCESSFUL;
876
877 /* Check if a stack was allocated */
878 if (AllocatedStack)
879 {
880 /* Delete the stack */
881 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
882 Thread->InitialStack = NULL;
883 }
884 }
885 _SEH2_END;
886
887 /* Set the Thread to initalized */
888 Thread->State = Initialized;
889 return Status;
890 }
891
892 VOID
893 NTAPI
894 KeInitializeThread(IN PKPROCESS Process,
895 IN OUT PKTHREAD Thread,
896 IN PKSYSTEM_ROUTINE SystemRoutine,
897 IN PKSTART_ROUTINE StartRoutine,
898 IN PVOID StartContext,
899 IN PCONTEXT Context,
900 IN PVOID Teb,
901 IN PVOID KernelStack)
902 {
903 /* Initialize and start the thread on success */
904 if (NT_SUCCESS(KeInitThread(Thread,
905 KernelStack,
906 SystemRoutine,
907 StartRoutine,
908 StartContext,
909 Context,
910 Teb,
911 Process)))
912 {
913 /* Start it */
914 KeStartThread(Thread);
915 }
916 }
917
918 VOID
919 NTAPI
920 KeUninitThread(IN PKTHREAD Thread)
921 {
922 /* Delete the stack */
923 MmDeleteKernelStack((PVOID)Thread->StackBase, FALSE);
924 Thread->InitialStack = NULL;
925 }
926
927 /* PUBLIC FUNCTIONS **********************************************************/
928
929 /*
930 * @unimplemented
931 */
932 VOID
933 NTAPI
934 KeCapturePersistentThreadState(IN PVOID CurrentThread,
935 IN ULONG Setting1,
936 IN ULONG Setting2,
937 IN ULONG Setting3,
938 IN ULONG Setting4,
939 IN ULONG Setting5,
940 IN PVOID ThreadState)
941 {
942 UNIMPLEMENTED;
943 }
944
945 /*
946 * @implemented
947 */
948 #undef KeGetCurrentThread
949 PKTHREAD
950 NTAPI
951 KeGetCurrentThread(VOID)
952 {
953 /* Return the current thread on this PCR */
954 return _KeGetCurrentThread();
955 }
956
957 /*
958 * @implemented
959 */
960 #undef KeGetPreviousMode
961 UCHAR
962 NTAPI
963 KeGetPreviousMode(VOID)
964 {
965 /* Return the previous mode of this thread */
966 return _KeGetPreviousMode();
967 }
968
969 /*
970 * @implemented
971 */
972 ULONG
973 NTAPI
974 KeQueryRuntimeThread(IN PKTHREAD Thread,
975 OUT PULONG UserTime)
976 {
977 ASSERT_THREAD(Thread);
978
979 /* Return the User Time */
980 *UserTime = Thread->UserTime;
981
982 /* Return the Kernel Time */
983 return Thread->KernelTime;
984 }
985
986 /*
987 * @implemented
988 */
989 BOOLEAN
990 NTAPI
991 KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
992 {
993 BOOLEAN PreviousState;
994 PKTHREAD Thread = KeGetCurrentThread();
995
996 /* Save Old State */
997 PreviousState = Thread->EnableStackSwap;
998
999 /* Set New State */
1000 Thread->EnableStackSwap = Enable;
1001
1002 /* Return Old State */
1003 return PreviousState;
1004 }
1005
1006 /*
1007 * @implemented
1008 */
1009 KPRIORITY
1010 NTAPI
1011 KeQueryPriorityThread(IN PKTHREAD Thread)
1012 {
1013 ASSERT_THREAD(Thread);
1014
1015 /* Return the current priority */
1016 return Thread->Priority;
1017 }
1018
1019 /*
1020 * @implemented
1021 */
1022 VOID
1023 NTAPI
1024 KeRevertToUserAffinityThread(VOID)
1025 {
1026 KIRQL OldIrql;
1027 PKPRCB Prcb;
1028 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
1029 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1030 ASSERT(CurrentThread->SystemAffinityActive != FALSE);
1031
1032 /* Lock the Dispatcher Database */
1033 OldIrql = KiAcquireDispatcherLock();
1034
1035 /* Set the user affinity and processor and disable system affinity */
1036 CurrentThread->Affinity = CurrentThread->UserAffinity;
1037 CurrentThread->IdealProcessor = CurrentThread->UserIdealProcessor;
1038 CurrentThread->SystemAffinityActive = FALSE;
1039
1040 /* Get the current PRCB and check if it doesn't match this affinity */
1041 Prcb = KeGetCurrentPrcb();
1042 if (!(Prcb->SetMember & CurrentThread->Affinity))
1043 {
1044 /* Lock the PRCB */
1045 KiAcquirePrcbLock(Prcb);
1046
1047 /* Check if there's no next thread scheduled */
1048 if (!Prcb->NextThread)
1049 {
1050 /* Select a new thread and set it on standby */
1051 NextThread = KiSelectNextThread(Prcb);
1052 NextThread->State = Standby;
1053 Prcb->NextThread = NextThread;
1054 }
1055
1056 /* Release the PRCB lock */
1057 KiReleasePrcbLock(Prcb);
1058 }
1059
1060 /* Unlock dispatcher database */
1061 KiReleaseDispatcherLock(OldIrql);
1062 }
1063
1064 /*
1065 * @implemented
1066 */
1067 UCHAR
1068 NTAPI
1069 KeSetIdealProcessorThread(IN PKTHREAD Thread,
1070 IN UCHAR Processor)
1071 {
1072 CCHAR OldIdealProcessor;
1073 KIRQL OldIrql;
1074 ASSERT(Processor <= MAXIMUM_PROCESSORS);
1075
1076 /* Lock the Dispatcher Database */
1077 OldIrql = KiAcquireDispatcherLock();
1078
1079 /* Save Old Ideal Processor */
1080 OldIdealProcessor = Thread->UserIdealProcessor;
1081
1082 /* Make sure a valid CPU was given */
1083 if (Processor < KeNumberProcessors)
1084 {
1085 /* Check if the user ideal CPU is in the affinity */
1086 if (Thread->Affinity & AFFINITY_MASK(Processor))
1087 {
1088 /* Set the ideal processor */
1089 Thread->IdealProcessor = Processor;
1090
1091 /* Check if system affinity is used */
1092 if (!Thread->SystemAffinityActive)
1093 {
1094 /* It's not, so update the user CPU too */
1095 Thread->UserIdealProcessor = Processor;
1096 }
1097 }
1098 }
1099
1100 /* Release dispatcher lock and return the old ideal CPU */
1101 KiReleaseDispatcherLock(OldIrql);
1102 return OldIdealProcessor;
1103 }
1104
1105 /*
1106 * @implemented
1107 */
1108 VOID
1109 NTAPI
1110 KeSetSystemAffinityThread(IN KAFFINITY Affinity)
1111 {
1112 KIRQL OldIrql;
1113 PKPRCB Prcb;
1114 PKTHREAD NextThread, CurrentThread = KeGetCurrentThread();
1115 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1116 ASSERT((Affinity & KeActiveProcessors) != 0);
1117
1118 /* Lock the Dispatcher Database */
1119 OldIrql = KiAcquireDispatcherLock();
1120
1121 /* Restore the affinity and enable system affinity */
1122 CurrentThread->Affinity = Affinity;
1123 CurrentThread->SystemAffinityActive = TRUE;
1124
1125 /* Check if the ideal processor is part of the affinity */
1126 #ifdef CONFIG_SMP
1127 if (!(Affinity & AFFINITY_MASK(CurrentThread->IdealProcessor)))
1128 {
1129 ULONG AffinitySet, NodeMask;
1130
1131 /* It's not! Get the PRCB */
1132 Prcb = KiProcessorBlock[CurrentThread->IdealProcessor];
1133
1134 /* Calculate the affinity set */
1135 AffinitySet = KeActiveProcessors & Affinity;
1136 NodeMask = Prcb->ParentNode->ProcessorMask & AffinitySet;
1137 if (NodeMask)
1138 {
1139 /* Use the Node set instead */
1140 AffinitySet = NodeMask;
1141 }
1142
1143 /* Calculate the ideal CPU from the affinity set */
1144 BitScanReverse(&NodeMask, AffinitySet);
1145 CurrentThread->IdealProcessor = (UCHAR)NodeMask;
1146 }
1147 #endif
1148
1149 /* Get the current PRCB and check if it doesn't match this affinity */
1150 Prcb = KeGetCurrentPrcb();
1151 if (!(Prcb->SetMember & CurrentThread->Affinity))
1152 {
1153 /* Lock the PRCB */
1154 KiAcquirePrcbLock(Prcb);
1155
1156 /* Check if there's no next thread scheduled */
1157 if (!Prcb->NextThread)
1158 {
1159 /* Select a new thread and set it on standby */
1160 NextThread = KiSelectNextThread(Prcb);
1161 NextThread->State = Standby;
1162 Prcb->NextThread = NextThread;
1163 }
1164
1165 /* Release the PRCB lock */
1166 KiReleasePrcbLock(Prcb);
1167 }
1168
1169 /* Unlock dispatcher database */
1170 KiReleaseDispatcherLock(OldIrql);
1171 }
1172
1173 /*
1174 * @implemented
1175 */
1176 LONG
1177 NTAPI
1178 KeSetBasePriorityThread(IN PKTHREAD Thread,
1179 IN LONG Increment)
1180 {
1181 KIRQL OldIrql;
1182 KPRIORITY OldBasePriority, Priority, BasePriority;
1183 LONG OldIncrement;
1184 PKPROCESS Process;
1185 ASSERT_THREAD(Thread);
1186 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1187
1188 /* Get the process */
1189 Process = Thread->ApcState.Process;
1190
1191 /* Lock the Dispatcher Database */
1192 OldIrql = KiAcquireDispatcherLock();
1193
1194 /* Lock the thread */
1195 KiAcquireThreadLock(Thread);
1196
1197 /* Save the old base priority and increment */
1198 OldBasePriority = Thread->BasePriority;
1199 OldIncrement = OldBasePriority - Process->BasePriority;
1200
1201 /* If priority saturation happened, use the saturated increment */
1202 if (Thread->Saturation) OldIncrement = (HIGH_PRIORITY + 1) / 2 *
1203 Thread->Saturation;
1204
1205 /* Reset the saturation value */
1206 Thread->Saturation = 0;
1207
1208 /* Now check if saturation is being used for the new value */
1209 if (abs(Increment) >= ((HIGH_PRIORITY + 1) / 2))
1210 {
1211 /* Check if we need positive or negative saturation */
1212 Thread->Saturation = (Increment > 0) ? 1 : -1;
1213 }
1214
1215 /* Normalize the Base Priority */
1216 BasePriority = Process->BasePriority + Increment;
1217 if (Process->BasePriority >= LOW_REALTIME_PRIORITY)
1218 {
1219 /* Check if it's too low */
1220 if (BasePriority < LOW_REALTIME_PRIORITY)
1221 {
1222 /* Set it to the lowest real time level */
1223 BasePriority = LOW_REALTIME_PRIORITY;
1224 }
1225
1226 /* Check if it's too high */
1227 if (BasePriority > HIGH_PRIORITY) BasePriority = HIGH_PRIORITY;
1228
1229 /* We are at real time, so use the raw base priority */
1230 Priority = BasePriority;
1231 }
1232 else
1233 {
1234 /* Check if it's entering the real time range */
1235 if (BasePriority >= LOW_REALTIME_PRIORITY)
1236 {
1237 /* Set it to the highest dynamic level */
1238 BasePriority = LOW_REALTIME_PRIORITY - 1;
1239 }
1240
1241 /* Check if it's too low and normalize it */
1242 if (BasePriority <= LOW_PRIORITY) BasePriority = 1;
1243
1244 /* Check if Saturation is used */
1245 if (Thread->Saturation)
1246 {
1247 /* Use the raw base priority */
1248 Priority = BasePriority;
1249 }
1250 else
1251 {
1252 /* Otherwise, calculate the new priority */
1253 Priority = KiComputeNewPriority(Thread, 0);
1254 Priority += (BasePriority - OldBasePriority);
1255
1256 /* Check if it entered the real-time range */
1257 if (Priority >= LOW_REALTIME_PRIORITY)
1258 {
1259 /* Normalize it down to the highest dynamic priority */
1260 Priority = LOW_REALTIME_PRIORITY - 1;
1261 }
1262 else if (Priority <= LOW_PRIORITY)
1263 {
1264 /* It went too low, normalize it */
1265 Priority = 1;
1266 }
1267 }
1268 }
1269
1270 /* Finally set the new base priority */
1271 Thread->BasePriority = (SCHAR)BasePriority;
1272
1273 /* Reset the decrements */
1274 Thread->PriorityDecrement = 0;
1275
1276 /* Check if we're changing priority after all */
1277 if (Priority != Thread->Priority)
1278 {
1279 /* Reset the quantum and do the actual priority modification */
1280 Thread->Quantum = Thread->QuantumReset;
1281 KiSetPriorityThread(Thread, Priority);
1282 }
1283
1284 /* Release thread lock */
1285 KiReleaseThreadLock(Thread);
1286
1287 /* Release the dispatcher database and return old increment */
1288 KiReleaseDispatcherLock(OldIrql);
1289 return OldIncrement;
1290 }
1291
1292 /*
1293 * @implemented
1294 */
1295 KAFFINITY
1296 NTAPI
1297 KeSetAffinityThread(IN PKTHREAD Thread,
1298 IN KAFFINITY Affinity)
1299 {
1300 KIRQL OldIrql;
1301 KAFFINITY OldAffinity;
1302 ASSERT_THREAD(Thread);
1303 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1304
1305 /* Lock the dispatcher database */
1306 OldIrql = KiAcquireDispatcherLock();
1307
1308 /* Call the internal function */
1309 OldAffinity = KiSetAffinityThread(Thread, Affinity);
1310
1311 /* Release the dispatcher database and return old affinity */
1312 KiReleaseDispatcherLock(OldIrql);
1313 return OldAffinity;
1314 }
1315
1316 /*
1317 * @implemented
1318 */
1319 KPRIORITY
1320 NTAPI
1321 KeSetPriorityThread(IN PKTHREAD Thread,
1322 IN KPRIORITY Priority)
1323 {
1324 KIRQL OldIrql;
1325 KPRIORITY OldPriority;
1326 ASSERT_THREAD(Thread);
1327 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1328 ASSERT((Priority <= HIGH_PRIORITY) && (Priority >= LOW_PRIORITY));
1329 ASSERT(KeIsExecutingDpc() == FALSE);
1330
1331 /* Lock the Dispatcher Database */
1332 OldIrql = KiAcquireDispatcherLock();
1333
1334 /* Lock the thread */
1335 KiAcquireThreadLock(Thread);
1336
1337 /* Save the old Priority and reset decrement */
1338 OldPriority = Thread->Priority;
1339 Thread->PriorityDecrement = 0;
1340
1341 /* Make sure that an actual change is being done */
1342 if (Priority != Thread->Priority)
1343 {
1344 /* Reset the quantum */
1345 Thread->Quantum = Thread->QuantumReset;
1346
1347 /* Check if priority is being set too low and normalize if so */
1348 if ((Thread->BasePriority != 0) && !(Priority)) Priority = 1;
1349
1350 /* Set the new Priority */
1351 KiSetPriorityThread(Thread, Priority);
1352 }
1353
1354 /* Release thread lock */
1355 KiReleaseThreadLock(Thread);
1356
1357 /* Release the dispatcher database */
1358 KiReleaseDispatcherLock(OldIrql);
1359
1360 /* Return Old Priority */
1361 return OldPriority;
1362 }
1363
1364 /*
1365 * @implemented
1366 */
1367 VOID
1368 NTAPI
1369 KeTerminateThread(IN KPRIORITY Increment)
1370 {
1371 PLIST_ENTRY *ListHead;
1372 PETHREAD Entry, SavedEntry;
1373 PETHREAD *ThreadAddr;
1374 KLOCK_QUEUE_HANDLE LockHandle;
1375 PKTHREAD Thread = KeGetCurrentThread();
1376 PKPROCESS Process = Thread->ApcState.Process;
1377 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1378
1379 /* Lock the process */
1380 KiAcquireProcessLock(Process, &LockHandle);
1381
1382 /* Make sure we won't get Swapped */
1383 KiSetThreadSwapBusy(Thread);
1384
1385 /* Save the Kernel and User Times */
1386 Process->KernelTime += Thread->KernelTime;
1387 Process->UserTime += Thread->UserTime;
1388
1389 /* Get the current entry and our Port */
1390 Entry = (PETHREAD)PspReaperListHead.Flink;
1391 ThreadAddr = &((PETHREAD)Thread)->ReaperLink;
1392
1393 /* Add it to the reaper's list */
1394 do
1395 {
1396 /* Get the list head */
1397 ListHead = &PspReaperListHead.Flink;
1398
1399 /* Link ourselves */
1400 *ThreadAddr = Entry;
1401 SavedEntry = Entry;
1402
1403 /* Now try to do the exchange */
1404 Entry = InterlockedCompareExchangePointer((PVOID*)ListHead,
1405 ThreadAddr,
1406 Entry);
1407
1408 /* Break out if the change was succesful */
1409 } while (Entry != SavedEntry);
1410
1411 /* Acquire the dispatcher lock */
1412 KiAcquireDispatcherLockAtDpcLevel();
1413
1414 /* Check if the reaper wasn't active */
1415 if (!Entry)
1416 {
1417 /* Activate it as a work item, directly through its Queue */
1418 KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue,
1419 &PspReaperWorkItem.List,
1420 FALSE);
1421 }
1422
1423 /* Check the thread has an associated queue */
1424 if (Thread->Queue)
1425 {
1426 /* Remove it from the list, and handle the queue */
1427 RemoveEntryList(&Thread->QueueListEntry);
1428 KiActivateWaiterQueue(Thread->Queue);
1429 }
1430
1431 /* Signal the thread */
1432 Thread->Header.SignalState = TRUE;
1433 if (!IsListEmpty(&Thread->Header.WaitListHead))
1434 {
1435 /* Unwait the threads */
1436 KxUnwaitThread(&Thread->Header, Increment);
1437 }
1438
1439 /* Remove the thread from the list */
1440 RemoveEntryList(&Thread->ThreadListEntry);
1441
1442 /* Release the process lock */
1443 KiReleaseProcessLockFromDpcLevel(&LockHandle);
1444
1445 /* Set us as terminated, decrease the Process's stack count */
1446 Thread->State = Terminated;
1447
1448 /* Decrease stack count */
1449 ASSERT(Process->StackCount != 0);
1450 ASSERT(Process->State == ProcessInMemory);
1451 Process->StackCount--;
1452 if (!(Process->StackCount) && !(IsListEmpty(&Process->ThreadListHead)))
1453 {
1454 /* FIXME: Swap stacks */
1455 }
1456
1457 /* Rundown arch-specific parts */
1458 KiRundownThread(Thread);
1459
1460 /* Swap to a new thread */
1461 KiReleaseDispatcherLockFromDpcLevel();
1462 KiSwapThread(Thread, KeGetCurrentPrcb());
1463 }