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