2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/kthread.c
5 * PURPOSE: Microkernel thread support
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@cwcom.net)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 #ifndef MUTANT_INCREMENT
18 #define MUTANT_INCREMENT 1
21 #define THREAD_ALERT_INCREMENT 2
23 extern EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
26 * PURPOSE: List of threads associated with each priority level
28 LIST_ENTRY PriorityListHead
[MAXIMUM_PRIORITY
];
29 static ULONG PriorityListMask
= 0;
30 ULONG IdleProcessorMask
= 0;
31 extern BOOLEAN DoneInitYet
;
32 extern PETHREAD PspReaperList
;
34 /* FUNCTIONS *****************************************************************/
38 KiRequestReschedule(CCHAR Processor
)
42 Pcr
= (PKPCR
)(KPCR_BASE
+ Processor
* PAGE_SIZE
);
43 Pcr
->Prcb
->QuantumEnd
= TRUE
;
44 KiIpiSendRequest(1 << Processor
, IPI_REQUEST_DPC
);
49 KiInsertIntoThreadList(KPRIORITY Priority
,
52 ASSERT(Ready
== Thread
->State
);
53 ASSERT(Thread
->Priority
== Priority
);
55 if (Priority
>= MAXIMUM_PRIORITY
|| Priority
< LOW_PRIORITY
) {
57 DPRINT1("Invalid thread priority (%d)\n", Priority
);
61 InsertTailList(&PriorityListHead
[Priority
], &Thread
->WaitListEntry
);
62 PriorityListMask
|= (1 << Priority
);
67 KiRemoveFromThreadList(PKTHREAD Thread
)
69 ASSERT(Ready
== Thread
->State
);
70 RemoveEntryList(&Thread
->WaitListEntry
);
71 if (IsListEmpty(&PriorityListHead
[(ULONG
)Thread
->Priority
])) {
73 PriorityListMask
&= ~(1 << Thread
->Priority
);
79 KiScanThreadList(KPRIORITY Priority
,
82 PLIST_ENTRY current_entry
;
86 Mask
= (1 << Priority
);
88 if (PriorityListMask
& Mask
) {
90 current_entry
= PriorityListHead
[Priority
].Flink
;
92 while (current_entry
!= &PriorityListHead
[Priority
]) {
94 current
= CONTAINING_RECORD(current_entry
, KTHREAD
, WaitListEntry
);
96 if (current
->State
!= Ready
) {
98 DPRINT1("%d/%d\n", ¤t
, current
->State
);
101 ASSERT(current
->State
== Ready
);
103 if (current
->Affinity
& Affinity
) {
105 KiRemoveFromThreadList(current
);
109 current_entry
= current_entry
->Flink
;
118 KiDispatchThreadNoLock(ULONG NewThreadStatus
)
120 KPRIORITY CurrentPriority
;
123 PKTHREAD CurrentThread
= KeGetCurrentThread();
125 DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
126 CurrentThread
, NewThreadStatus
, CurrentThread
->State
);
128 CurrentThread
->State
= (UCHAR
)NewThreadStatus
;
130 if (NewThreadStatus
== Ready
) {
132 KiInsertIntoThreadList(CurrentThread
->Priority
,
136 Affinity
= 1 << KeGetCurrentProcessorNumber();
138 for (CurrentPriority
= HIGH_PRIORITY
; CurrentPriority
>= LOW_PRIORITY
; CurrentPriority
--) {
140 Candidate
= KiScanThreadList(CurrentPriority
, Affinity
);
142 if (Candidate
== CurrentThread
) {
144 Candidate
->State
= Running
;
145 KeReleaseDispatcherDatabaseLockFromDpcLevel();
149 if (Candidate
!= NULL
) {
154 DPRINT("Scheduling %x(%d)\n",Candidate
, CurrentPriority
);
156 Candidate
->State
= Running
;
158 OldThread
= CurrentThread
;
159 CurrentThread
= Candidate
;
160 IdleThread
= KeGetCurrentPrcb()->IdleThread
;
162 if (OldThread
== IdleThread
) {
164 IdleProcessorMask
&= ~Affinity
;
166 } else if (CurrentThread
== IdleThread
) {
168 IdleProcessorMask
|= Affinity
;
171 MmUpdatePageDir(PsGetCurrentProcess(),((PETHREAD
)CurrentThread
)->ThreadsProcess
, sizeof(EPROCESS
));
173 /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
174 DPRINT("You are : %x, swapping to: %x\n", OldThread
, CurrentThread
);
175 KiArchContextSwitch(CurrentThread
);
176 DPRINT("You are : %x, swapped from: %x\n", OldThread
, CurrentThread
);
181 DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
187 KiBlockThread(PNTSTATUS Status
,
192 PKTHREAD Thread
= KeGetCurrentThread();
193 PKWAIT_BLOCK WaitBlock
;
195 if (Thread
->ApcState
.KernelApcPending
) {
197 DPRINT("Dispatching Thread as ready (APC!)\n");
200 WaitBlock
= Thread
->WaitBlockList
;
202 RemoveEntryList (&WaitBlock
->WaitListEntry
);
203 WaitBlock
= WaitBlock
->NextWaitBlock
;
204 } while (WaitBlock
!= Thread
->WaitBlockList
);
205 Thread
->WaitBlockList
= NULL
;
207 /* Dispatch it and return status */
208 KiDispatchThreadNoLock (Ready
);
209 if (Status
!= NULL
) *Status
= STATUS_KERNEL_APC
;
213 /* Set the Thread Data as Requested */
214 DPRINT("Dispatching Thread as blocked: %d\n", Thread
->WaitStatus
);
215 Thread
->Alertable
= Alertable
;
216 Thread
->WaitMode
= (UCHAR
)WaitMode
;
217 Thread
->WaitReason
= WaitReason
;
219 /* Dispatch it and return status */
220 KiDispatchThreadNoLock(Waiting
);
221 DPRINT("Dispatching Thread as blocked: %d\n", Thread
->WaitStatus
);
222 if (Status
!= NULL
) *Status
= Thread
->WaitStatus
;
225 DPRINT("Releasing Dispatcher Lock\n");
226 KfLowerIrql(Thread
->WaitIrql
);
231 KiDispatchThread(ULONG NewThreadStatus
)
235 if (!DoneInitYet
|| KeGetCurrentPrcb()->IdleThread
== NULL
) {
239 OldIrql
= KeAcquireDispatcherDatabaseLock();
240 KiDispatchThreadNoLock(NewThreadStatus
);
241 KeLowerIrql(OldIrql
);
246 KiUnblockThread(PKTHREAD Thread
,
247 PNTSTATUS WaitStatus
,
250 if (Terminated
== Thread
->State
) {
252 DPRINT("Can't unblock thread 0x%x because it's terminating\n",
255 } else if (Ready
== Thread
->State
||
256 Running
== Thread
->State
) {
258 DPRINT("Can't unblock thread 0x%x because it's %s\n",
259 Thread
, (Thread
->State
== Ready
? "ready" : "running"));
266 /* FIXME: This propably isn't the right way to do it... */
267 /* No it's not... i'll fix it later-- Alex */
268 if (Thread
->Priority
< LOW_REALTIME_PRIORITY
&&
269 Thread
->BasePriority
< LOW_REALTIME_PRIORITY
- 2) {
271 if (!Thread
->PriorityDecrement
&& !Thread
->DisableBoost
) {
273 Thread
->Priority
= Thread
->BasePriority
+ Increment
;
274 Thread
->PriorityDecrement
= Increment
;
279 Thread
->Quantum
= Thread
->QuantumReset
;
282 if (WaitStatus
!= NULL
) {
284 Thread
->WaitStatus
= *WaitStatus
;
287 Thread
->State
= Ready
;
288 KiInsertIntoThreadList(Thread
->Priority
, Thread
);
289 Processor
= KeGetCurrentProcessorNumber();
290 Affinity
= Thread
->Affinity
;
292 if (!(IdleProcessorMask
& (1 << Processor
) & Affinity
) &&
293 (IdleProcessorMask
& ~(1 << Processor
) & Affinity
)) {
297 for (i
= 0; i
< KeNumberProcessors
- 1; i
++) {
301 if (Processor
>= KeNumberProcessors
) {
306 if (IdleProcessorMask
& (1 << Processor
) & Affinity
) {
309 * Reschedule the threads on an other processor
311 KeReleaseDispatcherDatabaseLockFromDpcLevel();
312 KiRequestReschedule(Processor
);
313 KeAcquireDispatcherDatabaseLockAtDpcLevel();
324 KiSuspendThreadKernelRoutine(PKAPC Apc
,
325 PKNORMAL_ROUTINE
* NormalRoutine
,
326 PVOID
* NormalContext
,
327 PVOID
* SystemArgument1
,
328 PVOID
* SystemArguemnt2
)
334 KiSuspendThreadNormalRoutine(PVOID NormalContext
,
335 PVOID SystemArgument1
,
336 PVOID SystemArgument2
)
338 PKTHREAD CurrentThread
= KeGetCurrentThread();
340 /* Non-alertable kernel-mode suspended wait */
341 DPRINT("Waiting...\n");
342 KeWaitForSingleObject(&CurrentThread
->SuspendSemaphore
,
347 DPRINT("Done Waiting\n");
350 #ifdef KeGetCurrentThread
351 #undef KeGetCurrentThread
358 KeGetCurrentThread(VOID
)
363 Ke386SaveFlags(Flags
);
364 Ke386DisableInterrupts();
365 Thread
= KeGetCurrentPrcb()->CurrentThread
;
366 Ke386RestoreFlags(Flags
);
369 return(KeGetCurrentPrcb()->CurrentThread
);
375 KeSetPreviousMode(ULONG Mode
)
377 PsGetCurrentThread()->Tcb
.PreviousMode
= (UCHAR
)Mode
;
385 KeGetPreviousMode(VOID
)
387 return (ULONG
)PsGetCurrentThread()->Tcb
.PreviousMode
;
392 KeDisableThreadApcQueueing(IN PKTHREAD Thread
)
395 BOOLEAN PreviousState
;
397 /* Lock the Dispatcher Database */
398 OldIrql
= KeAcquireDispatcherDatabaseLock();
401 PreviousState
= Thread
->ApcQueueable
;
404 Thread
->ApcQueueable
= FALSE
;
406 /* Release the Lock */
407 KeReleaseDispatcherDatabaseLock(OldIrql
);
409 /* Return old state */
410 return PreviousState
;
415 KeRundownThread(VOID
)
418 PKTHREAD Thread
= KeGetCurrentThread();
419 PLIST_ENTRY CurrentEntry
;
422 DPRINT("KeRundownThread: %x\n", Thread
);
424 /* Lock the Dispatcher Database */
425 OldIrql
= KeAcquireDispatcherDatabaseLock();
427 while (!IsListEmpty(&Thread
->MutantListHead
)) {
430 CurrentEntry
= RemoveHeadList(&Thread
->MutantListHead
);
431 Mutant
= CONTAINING_RECORD(CurrentEntry
, KMUTANT
, MutantListEntry
);
432 ASSERT(Mutant
->ApcDisable
== 0);
434 /* Uncondtionally abandon it */
435 DPRINT("Abandonning the Mutant\n");
436 Mutant
->Header
.SignalState
= 1;
437 Mutant
->Abandoned
= TRUE
;
438 Mutant
->OwnerThread
= NULL
;
439 RemoveEntryList(&Mutant
->MutantListEntry
);
441 /* Check if the Wait List isn't empty */
442 DPRINT("Checking whether to wake the Mutant\n");
443 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
)) {
445 /* Wake the Mutant */
446 DPRINT("Waking the Mutant\n");
447 KiWaitTest(&Mutant
->Header
, MUTANT_INCREMENT
);
451 /* Release the Lock */
452 KeReleaseDispatcherDatabaseLock(OldIrql
);
457 KeResumeThread(PKTHREAD Thread
)
462 DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread
,
463 Thread
->SuspendCount
, Thread
->FreezeCount
);
465 /* Lock the Dispatcher */
466 OldIrql
= KeAcquireDispatcherDatabaseLock();
468 /* Save the Old Count */
469 PreviousCount
= Thread
->SuspendCount
;
471 /* Check if it existed */
474 Thread
->SuspendCount
--;
476 /* Decrease the current Suspend Count and Check Freeze Count */
477 if ((!Thread
->SuspendCount
) && (!Thread
->FreezeCount
)) {
479 /* Signal the Suspend Semaphore */
480 Thread
->SuspendSemaphore
.Header
.SignalState
++;
481 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
485 /* Release Lock and return the Old State */
486 KeReleaseDispatcherDatabaseLock(OldIrql
);
487 return PreviousCount
;
492 KiInsertQueueApc(PKAPC Apc
,
493 KPRIORITY PriorityBoost
);
496 * Used by the debugging code to freeze all the process's threads
497 * while the debugger is examining their state.
501 KeFreezeAllThreads(PKPROCESS Process
)
504 PLIST_ENTRY CurrentEntry
;
506 PKTHREAD CurrentThread
= KeGetCurrentThread();
509 OldIrql
= KeAcquireDispatcherDatabaseLock();
511 /* Loop the Process's Threads */
512 CurrentEntry
= Process
->ThreadListHead
.Flink
;
513 while (CurrentEntry
!= &Process
->ThreadListHead
)
516 Current
= CONTAINING_RECORD(CurrentEntry
, KTHREAD
, ThreadListEntry
);
518 /* Make sure it's not ours */
519 if (Current
== CurrentThread
) continue;
521 /* Make sure it wasn't already frozen, and that it's not suspended */
522 if (!(++Current
->FreezeCount
) && !(Current
->SuspendCount
))
525 if (!KiInsertQueueApc(&Current
->SuspendApc
, IO_NO_INCREMENT
))
527 /* Unsignal the Semaphore, the APC already got inserted */
528 Current
->SuspendSemaphore
.Header
.SignalState
--;
532 CurrentEntry
= CurrentEntry
->Flink
;
535 /* Release the lock */
536 KeReleaseDispatcherDatabaseLock(OldIrql
);
541 KeSuspendThread(PKTHREAD Thread
)
546 DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread
, Thread
->SuspendCount
, Thread
->FreezeCount
);
548 /* Lock the Dispatcher */
549 OldIrql
= KeAcquireDispatcherDatabaseLock();
551 /* Save the Old Count */
552 PreviousCount
= Thread
->SuspendCount
;
555 Thread
->SuspendCount
++;
557 /* Check if we should suspend it */
558 if (!PreviousCount
&& !Thread
->FreezeCount
) {
561 if (!KiInsertQueueApc(&Thread
->SuspendApc
, IO_NO_INCREMENT
)) {
563 /* Unsignal the Semaphore, the APC already got inserted */
564 Thread
->SuspendSemaphore
.Header
.SignalState
--;
568 /* Release Lock and return the Old State */
569 KeReleaseDispatcherDatabaseLock(OldIrql
);
570 return PreviousCount
;
575 KeForceResumeThread(IN PKTHREAD Thread
)
580 /* Lock the Dispatcher Database and the APC Queue */
581 OldIrql
= KeAcquireDispatcherDatabaseLock();
583 /* Save the old Suspend Count */
584 PreviousCount
= Thread
->SuspendCount
+ Thread
->FreezeCount
;
586 /* If the thread is suspended, wake it up!!! */
589 /* Unwait it completely */
590 Thread
->SuspendCount
= 0;
591 Thread
->FreezeCount
= 0;
593 /* Signal and satisfy */
594 Thread
->SuspendSemaphore
.Header
.SignalState
++;
595 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
598 /* Release Lock and return the Old State */
599 KeReleaseDispatcherDatabaseLock(OldIrql
);
600 return PreviousCount
;
605 KeAlertResumeThread(IN PKTHREAD Thread
)
610 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
612 /* Lock the Dispatcher Database and the APC Queue */
613 OldIrql
= KeAcquireDispatcherDatabaseLock();
614 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
616 /* Return if Thread is already alerted. */
617 if (Thread
->Alerted
[KernelMode
] == FALSE
) {
619 /* If it's Blocked, unblock if it we should */
620 if (Thread
->State
== Waiting
&& Thread
->Alertable
) {
622 DPRINT("Aborting Wait\n");
623 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
627 /* If not, simply Alert it */
628 Thread
->Alerted
[KernelMode
] = TRUE
;
632 /* Save the old Suspend Count */
633 PreviousCount
= Thread
->SuspendCount
;
635 /* If the thread is suspended, decrease one of the suspend counts */
638 /* Decrease count. If we are now zero, unwait it completely */
639 if (--Thread
->SuspendCount
) {
641 /* Signal and satisfy */
642 Thread
->SuspendSemaphore
.Header
.SignalState
++;
643 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
647 /* Release Locks and return the Old State */
648 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
649 KeReleaseDispatcherDatabaseLock(OldIrql
);
650 return PreviousCount
;
655 KeAlertThread(PKTHREAD Thread
,
656 KPROCESSOR_MODE AlertMode
)
659 BOOLEAN PreviousState
;
661 /* Acquire the Dispatcher Database Lock */
662 OldIrql
= KeAcquireDispatcherDatabaseLock();
664 /* Save the Previous State */
665 PreviousState
= Thread
->Alerted
[AlertMode
];
667 /* Return if Thread is already alerted. */
668 if (PreviousState
== FALSE
) {
670 /* If it's Blocked, unblock if it we should */
671 if (Thread
->State
== Waiting
&&
672 (AlertMode
== KernelMode
|| Thread
->WaitMode
== AlertMode
) &&
675 DPRINT("Aborting Wait\n");
676 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
680 /* If not, simply Alert it */
681 Thread
->Alerted
[AlertMode
] = TRUE
;
685 /* Release the Dispatcher Lock */
686 KeReleaseDispatcherDatabaseLock(OldIrql
);
688 /* Return the old state */
689 return PreviousState
;
697 KeCapturePersistentThreadState(IN PVOID CurrentThread
,
703 IN PVOID ThreadState
)
709 * FUNCTION: Initialize the microkernel state of the thread
713 KeInitializeThread(PKPROCESS Process
,
715 PKSYSTEM_ROUTINE SystemRoutine
,
716 PKSTART_ROUTINE StartRoutine
,
722 /* Initalize the Dispatcher Header */
723 DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread
, Process
);
724 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
729 DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
730 SystemRoutine
, StartRoutine
, StartContext
);
731 DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context
, Teb
);
733 /* Initialize the Mutant List */
734 InitializeListHead(&Thread
->MutantListHead
);
736 /* Setup the Service Descriptor Table for Native Calls */
737 Thread
->ServiceTable
= KeServiceDescriptorTable
;
739 /* Setup APC Fields */
740 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
741 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
742 Thread
->ApcState
.Process
= Process
;
743 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
744 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
745 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
746 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
748 /* Initialize the Suspend APC */
749 KeInitializeApc(&Thread
->SuspendApc
,
751 OriginalApcEnvironment
,
752 KiSuspendThreadKernelRoutine
,
754 KiSuspendThreadNormalRoutine
,
758 /* Initialize the Suspend Semaphore */
759 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
761 /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
763 Thread
->WaitBlock
[3].Object
= (PVOID
)&Thread
->Timer
;
764 Thread
->WaitBlock
[3].Thread
= Thread
;
765 Thread
->WaitBlock
[3].WaitKey
= STATUS_TIMEOUT
;
766 Thread
->WaitBlock
[3].WaitType
= WaitAny
;
767 Thread
->WaitBlock
[3].NextWaitBlock
= NULL
;
768 InsertTailList(&Thread
->Timer
.Header
.WaitListHead
,
769 &Thread
->WaitBlock
[3].WaitListEntry
);
771 KeInitializeTimer(&Thread
->Timer
);
776 /* Set the Thread Stacks */
777 Thread
->InitialStack
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
778 Thread
->StackBase
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
779 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
;
780 Thread
->KernelStackResident
= TRUE
;
783 * Establish the pde's for the new stack and the thread structure within the
784 * address space of the new process. They are accessed while taskswitching or
785 * while handling page faults. At this point it isn't possible to call the
786 * page fault handler for the missing pde's.
788 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
789 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
791 /* Initalize the Thread Context */
792 DPRINT("Initializing the Context for the thread: %x\n", Thread
);
793 KiArchInitThreadWithContext(Thread
,
799 /* Setup scheduler Fields based on Parent */
800 DPRINT("Thread context created, setting Scheduler Data\n");
801 Thread
->BasePriority
= Process
->BasePriority
;
802 Thread
->Quantum
= Process
->QuantumReset
;
803 Thread
->QuantumReset
= Process
->QuantumReset
;
804 Thread
->Affinity
= Process
->Affinity
;
805 Thread
->Priority
= Process
->BasePriority
;
806 Thread
->UserAffinity
= Process
->Affinity
;
807 Thread
->DisableBoost
= Process
->DisableBoost
;
808 Thread
->AutoAlignment
= Process
->AutoAlignment
;
809 Thread
->Iopl
= Process
->Iopl
;
811 /* Set the Thread to initalized */
812 Thread
->State
= Initialized
;
815 * Insert the Thread into the Process's Thread List
816 * Note, this is the KTHREAD Thread List. It is removed in
817 * ke/kthread.c!KeTerminateThread.
819 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
820 DPRINT("Thread initalized\n");
829 KeQueryPriorityThread (IN PKTHREAD Thread
)
831 return Thread
->Priority
;
839 KeQueryRuntimeThread(IN PKTHREAD Thread
,
842 /* Return the User Time */
843 *UserTime
= Thread
->UserTime
;
845 /* Return the Kernel Time */
846 return Thread
->KernelTime
;
854 KeSetKernelStackSwapEnable(IN BOOLEAN Enable
)
856 PKTHREAD Thread
= KeGetCurrentThread();
857 BOOLEAN PreviousState
;
860 /* Lock the Dispatcher Database */
861 OldIrql
= KeAcquireDispatcherDatabaseLock();
864 PreviousState
= Thread
->EnableStackSwap
;
867 Thread
->EnableStackSwap
= Enable
;
869 /* No, Release Lock */
870 KeReleaseDispatcherDatabaseLock(OldIrql
);
872 /* Return Old State */
873 return PreviousState
;
881 KeRevertToUserAffinityThread(VOID
)
883 PKTHREAD CurrentThread
= KeGetCurrentThread();
886 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
888 /* Lock the Dispatcher Database */
889 OldIrql
= KeAcquireDispatcherDatabaseLock();
891 /* Return to User Affinity */
892 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
894 /* Disable System Affinity */
895 CurrentThread
->SystemAffinityActive
= FALSE
;
897 /* Check if we need to Dispatch a New thread */
898 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber())) {
900 /* No, just release */
901 KeReleaseDispatcherDatabaseLock(OldIrql
);
905 /* We need to dispatch a new thread */
906 CurrentThread
->WaitIrql
= OldIrql
;
907 KiDispatchThreadNoLock(Ready
);
908 KeLowerIrql(OldIrql
);
917 KeSetIdealProcessorThread(IN PKTHREAD Thread
,
920 CCHAR PreviousIdealProcessor
;
923 /* Lock the Dispatcher Database */
924 OldIrql
= KeAcquireDispatcherDatabaseLock();
926 /* Save Old Ideal Processor */
927 PreviousIdealProcessor
= Thread
->IdealProcessor
;
929 /* Set New Ideal Processor */
930 Thread
->IdealProcessor
= Processor
;
933 KeReleaseDispatcherDatabaseLock(OldIrql
);
935 /* Return Old Ideal Processor */
936 return PreviousIdealProcessor
;
944 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
946 PKTHREAD CurrentThread
= KeGetCurrentThread();
949 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
951 /* Lock the Dispatcher Database */
952 OldIrql
= KeAcquireDispatcherDatabaseLock();
954 /* Set the System Affinity Specified */
955 CurrentThread
->Affinity
= Affinity
;
957 /* Enable System Affinity */
958 CurrentThread
->SystemAffinityActive
= TRUE
;
960 /* Check if we need to Dispatch a New thread */
961 if (Affinity
& (1 << KeGetCurrentProcessorNumber())) {
963 /* No, just release */
964 KeReleaseDispatcherDatabaseLock(OldIrql
);
968 /* We need to dispatch a new thread */
969 CurrentThread
->WaitIrql
= OldIrql
;
970 KiDispatchThreadNoLock(Ready
);
971 KeLowerIrql(OldIrql
);
979 KeSetBasePriorityThread (PKTHREAD Thread
,
982 * Sets thread's base priority relative to the process' base priority
983 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
991 else if (Increment
> 2)
995 Priority
= ((PETHREAD
)Thread
)->ThreadsProcess
->Pcb
.BasePriority
+ Increment
;
996 if (Priority
< LOW_PRIORITY
)
998 Priority
= LOW_PRIORITY
;
1000 else if (Priority
>= MAXIMUM_PRIORITY
)
1002 Thread
->BasePriority
= HIGH_PRIORITY
;
1004 KeSetPriorityThread(Thread
, Priority
);
1013 KeSetPriorityThread(PKTHREAD Thread
,
1016 KPRIORITY OldPriority
;
1018 PKTHREAD CurrentThread
;
1023 if (Priority
< LOW_PRIORITY
|| Priority
>= MAXIMUM_PRIORITY
) {
1028 OldIrql
= KeAcquireDispatcherDatabaseLock();
1030 OldPriority
= Thread
->Priority
;
1032 if (OldPriority
!= Priority
) {
1034 CurrentThread
= KeGetCurrentThread();
1036 if (Thread
->State
== Ready
) {
1038 KiRemoveFromThreadList(Thread
);
1039 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1040 KiInsertIntoThreadList(Priority
, Thread
);
1042 if (CurrentThread
->Priority
< Priority
) {
1044 KiDispatchThreadNoLock(Ready
);
1045 KeLowerIrql(OldIrql
);
1046 return (OldPriority
);
1049 } else if (Thread
->State
== Running
) {
1051 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1053 if (Priority
< OldPriority
) {
1055 /* Check for threads with a higher priority */
1056 Mask
= ~((1 << (Priority
+ 1)) - 1);
1057 if (PriorityListMask
& Mask
) {
1059 if (Thread
== CurrentThread
) {
1061 KiDispatchThreadNoLock(Ready
);
1062 KeLowerIrql(OldIrql
);
1063 return (OldPriority
);
1067 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1069 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1071 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1073 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1074 KiRequestReschedule(i
);
1075 KeLowerIrql(OldIrql
);
1076 return (OldPriority
);
1084 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1088 KeReleaseDispatcherDatabaseLock(OldIrql
);
1089 return(OldPriority
);
1095 * Sets thread's affinity
1099 KeSetAffinityThread(PKTHREAD Thread
,
1105 KAFFINITY ProcessorMask
;
1107 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread
, Affinity
);
1109 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
1111 OldIrql
= KeAcquireDispatcherDatabaseLock();
1113 Thread
->UserAffinity
= Affinity
;
1115 if (Thread
->SystemAffinityActive
== FALSE
) {
1117 Thread
->Affinity
= Affinity
;
1119 if (Thread
->State
== Running
) {
1121 ProcessorMask
= 1 << KeGetCurrentKPCR()->Number
;
1122 if (Thread
== KeGetCurrentThread()) {
1124 if (!(Affinity
& ProcessorMask
)) {
1126 KiDispatchThreadNoLock(Ready
);
1127 KeLowerIrql(OldIrql
);
1128 return STATUS_SUCCESS
;
1133 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1135 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1136 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1138 if (!(Affinity
& ProcessorMask
)) {
1140 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1141 KiRequestReschedule(i
);
1142 KeLowerIrql(OldIrql
);
1143 return STATUS_SUCCESS
;
1150 ASSERT (i
< KeNumberProcessors
);
1155 KeReleaseDispatcherDatabaseLock(OldIrql
);
1156 return STATUS_SUCCESS
;
1162 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1165 KeTerminateThread(IN KPRIORITY Increment
)
1168 PKTHREAD Thread
= KeGetCurrentThread();
1170 /* Lock the Dispatcher Database and the APC Queue */
1171 DPRINT("Terminating\n");
1172 OldIrql
= KeAcquireDispatcherDatabaseLock();
1174 /* Remove the thread from the list */
1175 RemoveEntryList(&Thread
->ThreadListEntry
);
1177 /* Insert into the Reaper List */
1178 DPRINT("List: %p\n", PspReaperList
);
1179 ((PETHREAD
)Thread
)->ReaperLink
= PspReaperList
;
1180 PspReaperList
= (PETHREAD
)Thread
;
1181 DPRINT("List: %p\n", PspReaperList
);
1183 /* Check if it's active */
1184 if (PspReaping
== FALSE
) {
1186 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1188 DPRINT("Terminating\n");
1189 KiInsertQueue(&ExWorkerQueue
[HyperCriticalWorkQueue
].WorkerQueue
,
1190 &PspReaperWorkItem
.List
,
1194 /* Handle Kernel Queues */
1195 if (Thread
->Queue
) {
1197 DPRINT("Waking Queue\n");
1198 RemoveEntryList(&Thread
->QueueListEntry
);
1199 KiWakeQueue(Thread
->Queue
);
1202 /* Signal the thread */
1203 Thread
->DispatcherHeader
.SignalState
= TRUE
;
1204 if (IsListEmpty(&Thread
->DispatcherHeader
.WaitListHead
) != TRUE
) {
1207 KiWaitTest((PVOID
)Thread
, Increment
);
1210 /* Find a new Thread */
1211 KiDispatchThreadNoLock(Terminated
);
1215 * FUNCTION: Tests whether there are any pending APCs for the current thread
1216 * and if so the APCs will be delivered on exit from kernel mode
1220 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode
)
1223 PKTHREAD Thread
= KeGetCurrentThread();
1226 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1228 /* Lock the Dispatcher Database and the APC Queue */
1229 OldIrql
= KeAcquireDispatcherDatabaseLock();
1230 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
1232 /* Save the old State */
1233 OldState
= Thread
->Alerted
[AlertMode
];
1235 /* If the Thread is Alerted, Clear it */
1238 Thread
->Alerted
[AlertMode
] = FALSE
;
1240 } else if ((AlertMode
== UserMode
) && (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
]))) {
1242 /* If the mode is User and the Queue isn't empty, set Pending */
1243 Thread
->ApcState
.UserApcPending
= TRUE
;
1246 /* Release Locks and return the Old State */
1247 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
1248 KeReleaseDispatcherDatabaseLock(OldIrql
);
1253 KiServiceCheck (VOID
)
1255 PKTHREAD Thread
= KeGetCurrentThread();
1257 /* Check if we need to inialize Win32 for this Thread */
1258 if (Thread
->ServiceTable
!= KeServiceDescriptorTableShadow
) {
1260 /* We do. Initialize it and save the new table */
1261 PsInitWin32Thread((PETHREAD
)Thread
);
1262 Thread
->ServiceTable
= KeServiceDescriptorTableShadow
;
1272 NtAlertResumeThread(IN HANDLE ThreadHandle
,
1273 OUT PULONG SuspendCount
)
1275 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1278 ULONG PreviousState
;
1280 /* Check if parameters are valid */
1281 if(PreviousMode
!= KernelMode
) {
1285 ProbeForWrite(SuspendCount
,
1291 Status
= _SEH_GetExceptionCode();
1296 /* Reference the Object */
1297 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1298 THREAD_SUSPEND_RESUME
,
1304 /* Check for Success */
1305 if (NT_SUCCESS(Status
)) {
1307 /* Call the Kernel Function */
1308 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
1310 /* Dereference Object */
1311 ObDereferenceObject(Thread
);
1317 *SuspendCount
= PreviousState
;
1321 Status
= _SEH_GetExceptionCode();
1338 NtAlertThread (IN HANDLE ThreadHandle
)
1340 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1344 /* Reference the Object */
1345 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1346 THREAD_SUSPEND_RESUME
,
1352 /* Check for Success */
1353 if (NT_SUCCESS(Status
)) {
1356 * Do an alert depending on the processor mode. If some kmode code wants to
1357 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1358 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1359 * use KeAlertThread() directly
1361 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
1363 /* Dereference Object */
1364 ObDereferenceObject(Thread
);
1373 NtDelayExecution(IN BOOLEAN Alertable
,
1374 IN PLARGE_INTEGER DelayInterval
)
1376 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1377 LARGE_INTEGER SafeInterval
;
1380 /* Check if parameters are valid */
1381 if(PreviousMode
!= KernelMode
) {
1385 ProbeForRead(DelayInterval
,
1386 sizeof(LARGE_INTEGER
),
1389 /* make a copy on the kernel stack and let DelayInterval point to it so
1390 we don't need to wrap KeDelayExecutionThread in SEH! */
1391 SafeInterval
= *DelayInterval
;
1395 Status
= _SEH_GetExceptionCode();
1399 /* Call the Kernel Function */
1400 Status
= KeDelayExecutionThread(PreviousMode
,