[NTOS:KE] Rename some locking functions to reflect the IRQL level changes
[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 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
142 KiAcquireDispatcherLockAtSynchLevel();
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 KiReleaseDispatcherLockFromSynchLevel();
178 KiReleaseApcLockFromSynchLevel(&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 KiAcquireApcLockRaiseToSynch(Thread, &ApcLock);
195 KiAcquireDispatcherLockAtSynchLevel();
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 KiReleaseDispatcherLockFromSynchLevel();
220 KiReleaseApcLockFromSynchLevel(&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 KiAcquireApcLockRaiseToSynch(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 KiAcquireDispatcherLockAtSynchLevel();
298
299 /* Signal and satisfy */
300 Thread->SuspendSemaphore.Header.SignalState++;
301 KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT);
302
303 /* Release the dispatcher */
304 KiReleaseDispatcherLockFromSynchLevel();
305 }
306
307 /* Release Lock and return the Old State */
308 KiReleaseApcLockFromSynchLevel(&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 KiAcquireProcessLockRaiseToSynch(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 KiAcquireProcessLockRaiseToSynch(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 KiAcquireApcLockAtSynchLevel(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 KiAcquireDispatcherLockAtSynchLevel();
373
374 /* Unsignal the semaphore, the APC was already inserted */
375 Current->SuspendSemaphore.Header.SignalState--;
376
377 /* Release the dispatcher */
378 KiReleaseDispatcherLockFromSynchLevel();
379 }
380 }
381 }
382
383 /* Release the APC lock */
384 KiReleaseApcLockFromSynchLevel(&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 KiReleaseProcessLockFromSynchLevel(&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 KiAcquireApcLockRaiseToSynch(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 KiAcquireDispatcherLockAtSynchLevel();
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 KiReleaseDispatcherLockFromSynchLevel();
428 }
429 }
430
431 /* Release APC Queue lock and return the Old State */
432 KiReleaseApcLockFromSynchLevel(&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 KiAcquireProcessLockRaiseToSynch(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 KiAcquireDispatcherLockAtSynchLevel();
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 KiReleaseDispatcherLockFromSynchLevel();
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 KiAcquireApcLockRaiseToSynch(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 KiAcquireDispatcherLockAtSynchLevel();
651
652 /* Unsignal the semaphore, the APC was already inserted */
653 Thread->SuspendSemaphore.Header.SignalState--;
654
655 /* Release the dispatcher */
656 KiReleaseDispatcherLockFromSynchLevel();
657 }
658 }
659 }
660
661 /* Release Lock and return the Old State */
662 KiReleaseApcLockFromSynchLevel(&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 KiAcquireProcessLockRaiseToSynch(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 KiAcquireApcLockAtSynchLevel(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 KiAcquireDispatcherLockAtSynchLevel();
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 KiReleaseDispatcherLockFromSynchLevel();
711 }
712 }
713
714 /* Release the APC lock */
715 KiReleaseApcLockFromSynchLevel(&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 KiReleaseProcessLockFromSynchLevel(&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 KiAcquireApcLockRaiseToSynch(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 KiAcquireProcessLockRaiseToSynch(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 KiAcquireDispatcherLockAtSynchLevel();
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 KiReleaseProcessLockFromSynchLevel(&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 KiReleaseDispatcherLockFromSynchLevel();
1468 KiSwapThread(Thread, KeGetCurrentPrcb());
1469 }