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 #define THREAD_ALERT_INCREMENT 2
19 extern EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
22 * PURPOSE: List of threads associated with each priority level
24 LIST_ENTRY PriorityListHead
[MAXIMUM_PRIORITY
];
25 static ULONG PriorityListMask
= 0;
26 ULONG IdleProcessorMask
= 0;
27 extern BOOLEAN DoneInitYet
;
28 extern PETHREAD PspReaperList
;
30 /* FUNCTIONS *****************************************************************/
34 KiRequestReschedule(CCHAR Processor
)
38 Pcr
= (PKPCR
)(KPCR_BASE
+ Processor
* PAGE_SIZE
);
39 Pcr
->Prcb
->QuantumEnd
= TRUE
;
40 KiIpiSendRequest(1 << Processor
, IPI_REQUEST_DPC
);
45 KiInsertIntoThreadList(KPRIORITY Priority
,
48 ASSERT(Ready
== Thread
->State
);
49 ASSERT(Thread
->Priority
== Priority
);
51 if (Priority
>= MAXIMUM_PRIORITY
|| Priority
< LOW_PRIORITY
) {
53 DPRINT1("Invalid thread priority (%d)\n", Priority
);
57 InsertTailList(&PriorityListHead
[Priority
], &Thread
->WaitListEntry
);
58 PriorityListMask
|= (1 << Priority
);
63 KiRemoveFromThreadList(PKTHREAD Thread
)
65 ASSERT(Ready
== Thread
->State
);
66 RemoveEntryList(&Thread
->WaitListEntry
);
67 if (IsListEmpty(&PriorityListHead
[(ULONG
)Thread
->Priority
])) {
69 PriorityListMask
&= ~(1 << Thread
->Priority
);
75 KiScanThreadList(KPRIORITY Priority
,
78 PLIST_ENTRY current_entry
;
82 Mask
= (1 << Priority
);
84 if (PriorityListMask
& Mask
) {
86 current_entry
= PriorityListHead
[Priority
].Flink
;
88 while (current_entry
!= &PriorityListHead
[Priority
]) {
90 current
= CONTAINING_RECORD(current_entry
, KTHREAD
, WaitListEntry
);
92 if (current
->State
!= Ready
) {
94 DPRINT1("%d/%d\n", ¤t
, current
->State
);
97 ASSERT(current
->State
== Ready
);
99 if (current
->Affinity
& Affinity
) {
101 KiRemoveFromThreadList(current
);
105 current_entry
= current_entry
->Flink
;
114 KiDispatchThreadNoLock(ULONG NewThreadStatus
)
116 KPRIORITY CurrentPriority
;
119 PKTHREAD CurrentThread
= KeGetCurrentThread();
121 DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
122 CurrentThread
, NewThreadStatus
, CurrentThread
->State
);
124 CurrentThread
->State
= (UCHAR
)NewThreadStatus
;
126 if (NewThreadStatus
== Ready
) {
128 KiInsertIntoThreadList(CurrentThread
->Priority
,
132 Affinity
= 1 << KeGetCurrentProcessorNumber();
134 for (CurrentPriority
= HIGH_PRIORITY
; CurrentPriority
>= LOW_PRIORITY
; CurrentPriority
--) {
136 Candidate
= KiScanThreadList(CurrentPriority
, Affinity
);
138 if (Candidate
== CurrentThread
) {
140 Candidate
->State
= Running
;
141 KeReleaseDispatcherDatabaseLockFromDpcLevel();
145 if (Candidate
!= NULL
) {
150 DPRINT("Scheduling %x(%d)\n",Candidate
, CurrentPriority
);
152 Candidate
->State
= Running
;
154 OldThread
= CurrentThread
;
155 CurrentThread
= Candidate
;
156 IdleThread
= KeGetCurrentPrcb()->IdleThread
;
158 if (OldThread
== IdleThread
) {
160 IdleProcessorMask
&= ~Affinity
;
162 } else if (CurrentThread
== IdleThread
) {
164 IdleProcessorMask
|= Affinity
;
167 MmUpdatePageDir(PsGetCurrentProcess(),((PETHREAD
)CurrentThread
)->ThreadsProcess
, sizeof(EPROCESS
));
169 /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
170 DPRINT("You are : %x, swapping to: %x\n", OldThread
, CurrentThread
);
171 KiArchContextSwitch(CurrentThread
);
172 DPRINT("You are : %x, swapped from: %x\n", OldThread
, CurrentThread
);
177 DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
183 KiBlockThread(PNTSTATUS Status
,
188 PKTHREAD Thread
= KeGetCurrentThread();
189 PKWAIT_BLOCK WaitBlock
;
191 if (Thread
->ApcState
.KernelApcPending
) {
193 DPRINT("Dispatching Thread as ready (APC!)\n");
196 WaitBlock
= Thread
->WaitBlockList
;
198 RemoveEntryList (&WaitBlock
->WaitListEntry
);
199 WaitBlock
= WaitBlock
->NextWaitBlock
;
200 } while (WaitBlock
!= Thread
->WaitBlockList
);
201 Thread
->WaitBlockList
= NULL
;
203 /* Dispatch it and return status */
204 KiDispatchThreadNoLock (Ready
);
205 if (Status
!= NULL
) *Status
= STATUS_KERNEL_APC
;
209 /* Set the Thread Data as Requested */
210 DPRINT("Dispatching Thread as blocked: %d\n", Thread
->WaitStatus
);
211 Thread
->Alertable
= Alertable
;
212 Thread
->WaitMode
= (UCHAR
)WaitMode
;
213 Thread
->WaitReason
= WaitReason
;
215 /* Dispatch it and return status */
216 KiDispatchThreadNoLock(Waiting
);
217 DPRINT("Dispatching Thread as blocked: %d\n", Thread
->WaitStatus
);
218 if (Status
!= NULL
) *Status
= Thread
->WaitStatus
;
221 DPRINT("Releasing Dispatcher Lock\n");
222 KfLowerIrql(Thread
->WaitIrql
);
227 KiDispatchThread(ULONG NewThreadStatus
)
231 if (!DoneInitYet
|| KeGetCurrentPrcb()->IdleThread
== NULL
) {
235 OldIrql
= KeAcquireDispatcherDatabaseLock();
236 KiDispatchThreadNoLock(NewThreadStatus
);
237 KeLowerIrql(OldIrql
);
242 KiUnblockThread(PKTHREAD Thread
,
243 PNTSTATUS WaitStatus
,
246 if (Terminated
== Thread
->State
) {
248 DPRINT("Can't unblock thread 0x%x because it's terminating\n",
251 } else if (Ready
== Thread
->State
||
252 Running
== Thread
->State
) {
254 DPRINT("Can't unblock thread 0x%x because it's %s\n",
255 Thread
, (Thread
->State
== Ready
? "ready" : "running"));
262 /* FIXME: This propably isn't the right way to do it... */
263 /* No it's not... i'll fix it later-- Alex */
264 if (Thread
->Priority
< LOW_REALTIME_PRIORITY
&&
265 Thread
->BasePriority
< LOW_REALTIME_PRIORITY
- 2) {
267 if (!Thread
->PriorityDecrement
&& !Thread
->DisableBoost
) {
269 Thread
->Priority
= Thread
->BasePriority
+ Increment
;
270 Thread
->PriorityDecrement
= Increment
;
275 Thread
->Quantum
= Thread
->ApcState
.Process
->ThreadQuantum
;
278 if (WaitStatus
!= NULL
) {
280 Thread
->WaitStatus
= *WaitStatus
;
283 Thread
->State
= Ready
;
284 KiInsertIntoThreadList(Thread
->Priority
, Thread
);
285 Processor
= KeGetCurrentProcessorNumber();
286 Affinity
= Thread
->Affinity
;
288 if (!(IdleProcessorMask
& (1 << Processor
) & Affinity
) &&
289 (IdleProcessorMask
& ~(1 << Processor
) & Affinity
)) {
293 for (i
= 0; i
< KeNumberProcessors
- 1; i
++) {
297 if (Processor
>= KeNumberProcessors
) {
302 if (IdleProcessorMask
& (1 << Processor
) & Affinity
) {
305 * Reschedule the threads on an other processor
307 KeReleaseDispatcherDatabaseLockFromDpcLevel();
308 KiRequestReschedule(Processor
);
309 KeAcquireDispatcherDatabaseLockAtDpcLevel();
320 KiSuspendThreadKernelRoutine(PKAPC Apc
,
321 PKNORMAL_ROUTINE
* NormalRoutine
,
322 PVOID
* NormalContext
,
323 PVOID
* SystemArgument1
,
324 PVOID
* SystemArguemnt2
)
330 KiSuspendThreadNormalRoutine(PVOID NormalContext
,
331 PVOID SystemArgument1
,
332 PVOID SystemArgument2
)
334 PKTHREAD CurrentThread
= KeGetCurrentThread();
336 /* Non-alertable kernel-mode suspended wait */
337 DPRINT("Waiting...\n");
338 KeWaitForSingleObject(&CurrentThread
->SuspendSemaphore
,
343 DPRINT("Done Waiting\n");
346 #ifdef KeGetCurrentThread
347 #undef KeGetCurrentThread
354 KeGetCurrentThread(VOID
)
359 Ke386SaveFlags(Flags
);
360 Ke386DisableInterrupts();
361 Thread
= KeGetCurrentPrcb()->CurrentThread
;
362 Ke386RestoreFlags(Flags
);
365 return(KeGetCurrentPrcb()->CurrentThread
);
371 KeSetPreviousMode(ULONG Mode
)
373 PsGetCurrentThread()->Tcb
.PreviousMode
= (UCHAR
)Mode
;
381 KeGetPreviousMode(VOID
)
383 return (ULONG
)PsGetCurrentThread()->Tcb
.PreviousMode
;
388 KeRundownThread(VOID
)
391 PKTHREAD Thread
= KeGetCurrentThread();
392 PLIST_ENTRY CurrentEntry
;
395 DPRINT("KeRundownThread: %x\n", Thread
);
397 /* Lock the Dispatcher Database */
398 OldIrql
= KeAcquireDispatcherDatabaseLock();
400 while (!IsListEmpty(&Thread
->MutantListHead
)) {
403 CurrentEntry
= RemoveHeadList(&Thread
->MutantListHead
);
404 Mutant
= CONTAINING_RECORD(CurrentEntry
, KMUTANT
, MutantListEntry
);
405 ASSERT(Mutant
->ApcDisable
== 0);
407 /* Uncondtionally abandon it */
408 DPRINT("Abandonning the Mutant\n");
409 Mutant
->Header
.SignalState
= 1;
410 Mutant
->Abandoned
= TRUE
;
411 Mutant
->OwnerThread
= NULL
;
412 RemoveEntryList(&Mutant
->MutantListEntry
);
414 /* Check if the Wait List isn't empty */
415 DPRINT("Checking whether to wake the Mutant\n");
416 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
)) {
418 /* Wake the Mutant */
419 DPRINT("Waking the Mutant\n");
420 KiWaitTest(&Mutant
->Header
, MUTANT_INCREMENT
);
424 /* Release the Lock */
425 KeReleaseDispatcherDatabaseLock(OldIrql
);
430 KeResumeThread(PKTHREAD Thread
)
435 DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread
, Thread
->SuspendCount
, Thread
->FreezeCount
);
437 /* Lock the Dispatcher */
438 OldIrql
= KeAcquireDispatcherDatabaseLock();
440 /* Save the Old Count */
441 PreviousCount
= Thread
->SuspendCount
;
443 /* Check if it existed */
446 Thread
->SuspendCount
--;
448 /* Decrease the current Suspend Count and Check Freeze Count */
449 if ((!Thread
->SuspendCount
) && (!Thread
->FreezeCount
)) {
451 /* Signal the Suspend Semaphore */
452 Thread
->SuspendSemaphore
.Header
.SignalState
++;
453 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
457 /* Release Lock and return the Old State */
458 KeReleaseDispatcherDatabaseLock(OldIrql
);
459 return PreviousCount
;
464 KiInsertQueueApc(PKAPC Apc
,
465 KPRIORITY PriorityBoost
);
468 * Used by the debugging code to freeze all the process's threads
469 * while the debugger is examining their state.
473 KeFreezeAllThreads(PKPROCESS Process
)
476 PLIST_ENTRY CurrentEntry
;
478 PKTHREAD CurrentThread
= KeGetCurrentThread();
481 OldIrql
= KeAcquireDispatcherDatabaseLock();
483 /* Loop the Process's Threads */
484 CurrentEntry
= Process
->ThreadListHead
.Flink
;
485 while (CurrentEntry
!= &Process
->ThreadListHead
)
488 Current
= CONTAINING_RECORD(CurrentEntry
, KTHREAD
, ThreadListEntry
);
490 /* Make sure it's not ours */
491 if (Current
== CurrentThread
) continue;
493 /* Make sure it wasn't already frozen, and that it's not suspended */
494 if (!(++Current
->FreezeCount
) && !(Current
->SuspendCount
))
497 if (!KiInsertQueueApc(&Current
->SuspendApc
, IO_NO_INCREMENT
))
499 /* Unsignal the Semaphore, the APC already got inserted */
500 Current
->SuspendSemaphore
.Header
.SignalState
--;
504 CurrentEntry
= CurrentEntry
->Flink
;
507 /* Release the lock */
508 KeReleaseDispatcherDatabaseLock(OldIrql
);
513 KeSuspendThread(PKTHREAD Thread
)
518 DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread
, Thread
->SuspendCount
, Thread
->FreezeCount
);
520 /* Lock the Dispatcher */
521 OldIrql
= KeAcquireDispatcherDatabaseLock();
523 /* Save the Old Count */
524 PreviousCount
= Thread
->SuspendCount
;
527 Thread
->SuspendCount
++;
529 /* Check if we should suspend it */
530 if (!PreviousCount
&& !Thread
->FreezeCount
) {
533 if (!KiInsertQueueApc(&Thread
->SuspendApc
, IO_NO_INCREMENT
)) {
535 /* Unsignal the Semaphore, the APC already got inserted */
536 Thread
->SuspendSemaphore
.Header
.SignalState
--;
540 /* Release Lock and return the Old State */
541 KeReleaseDispatcherDatabaseLock(OldIrql
);
542 return PreviousCount
;
547 KeForceResumeThread(IN PKTHREAD Thread
)
552 /* Lock the Dispatcher Database and the APC Queue */
553 OldIrql
= KeAcquireDispatcherDatabaseLock();
555 /* Save the old Suspend Count */
556 PreviousCount
= Thread
->SuspendCount
+ Thread
->FreezeCount
;
558 /* If the thread is suspended, wake it up!!! */
561 /* Unwait it completely */
562 Thread
->SuspendCount
= 0;
563 Thread
->FreezeCount
= 0;
565 /* Signal and satisfy */
566 Thread
->SuspendSemaphore
.Header
.SignalState
++;
567 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
570 /* Release Lock and return the Old State */
571 KeReleaseDispatcherDatabaseLock(OldIrql
);
572 return PreviousCount
;
577 KeAlertResumeThread(IN PKTHREAD Thread
)
582 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
584 /* Lock the Dispatcher Database and the APC Queue */
585 OldIrql
= KeAcquireDispatcherDatabaseLock();
586 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
588 /* Return if Thread is already alerted. */
589 if (Thread
->Alerted
[KernelMode
] == FALSE
) {
591 /* If it's Blocked, unblock if it we should */
592 if (Thread
->State
== Waiting
&& Thread
->Alertable
) {
594 DPRINT("Aborting Wait\n");
595 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
599 /* If not, simply Alert it */
600 Thread
->Alerted
[KernelMode
] = TRUE
;
604 /* Save the old Suspend Count */
605 PreviousCount
= Thread
->SuspendCount
;
607 /* If the thread is suspended, decrease one of the suspend counts */
610 /* Decrease count. If we are now zero, unwait it completely */
611 if (--Thread
->SuspendCount
) {
613 /* Signal and satisfy */
614 Thread
->SuspendSemaphore
.Header
.SignalState
++;
615 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
619 /* Release Locks and return the Old State */
620 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
621 KeReleaseDispatcherDatabaseLock(OldIrql
);
622 return PreviousCount
;
627 KeAlertThread(PKTHREAD Thread
,
628 KPROCESSOR_MODE AlertMode
)
631 BOOLEAN PreviousState
;
633 /* Acquire the Dispatcher Database Lock */
634 OldIrql
= KeAcquireDispatcherDatabaseLock();
636 /* Save the Previous State */
637 PreviousState
= Thread
->Alerted
[AlertMode
];
639 /* Return if Thread is already alerted. */
640 if (PreviousState
== FALSE
) {
642 /* If it's Blocked, unblock if it we should */
643 if (Thread
->State
== Waiting
&&
644 (AlertMode
== KernelMode
|| Thread
->WaitMode
== AlertMode
) &&
647 DPRINT("Aborting Wait\n");
648 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
652 /* If not, simply Alert it */
653 Thread
->Alerted
[AlertMode
] = TRUE
;
657 /* Release the Dispatcher Lock */
658 KeReleaseDispatcherDatabaseLock(OldIrql
);
660 /* Return the old state */
661 return PreviousState
;
669 KeCapturePersistentThreadState(IN PVOID CurrentThread
,
675 IN PVOID ThreadState
)
681 * FUNCTION: Initialize the microkernel state of the thread
685 KeInitializeThread(PKPROCESS Process
,
687 PKSYSTEM_ROUTINE SystemRoutine
,
688 PKSTART_ROUTINE StartRoutine
,
694 /* Initalize the Dispatcher Header */
695 DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread
, Process
);
696 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
701 DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
702 SystemRoutine
, StartRoutine
, StartContext
);
703 DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context
, Teb
);
705 /* Initialize the Mutant List */
706 InitializeListHead(&Thread
->MutantListHead
);
708 /* Setup the Service Descriptor Table for Native Calls */
709 Thread
->ServiceTable
= KeServiceDescriptorTable
;
711 /* Setup APC Fields */
712 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
713 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
714 Thread
->ApcState
.Process
= Process
;
715 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
716 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
717 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
718 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
720 /* Initialize the Suspend APC */
721 KeInitializeApc(&Thread
->SuspendApc
,
723 OriginalApcEnvironment
,
724 KiSuspendThreadKernelRoutine
,
726 KiSuspendThreadNormalRoutine
,
730 /* Initialize the Suspend Semaphore */
731 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
733 /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
735 Thread
->WaitBlock
[3].Object
= (PVOID
)&Thread
->Timer
;
736 Thread
->WaitBlock
[3].Thread
= Thread
;
737 Thread
->WaitBlock
[3].WaitKey
= STATUS_TIMEOUT
;
738 Thread
->WaitBlock
[3].WaitType
= WaitAny
;
739 Thread
->WaitBlock
[3].NextWaitBlock
= NULL
;
740 InsertTailList(&Thread
->Timer
.Header
.WaitListHead
,
741 &Thread
->WaitBlock
[3].WaitListEntry
);
743 KeInitializeTimer(&Thread
->Timer
);
748 /* Set the Thread Stacks */
749 Thread
->InitialStack
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
750 Thread
->StackBase
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
751 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
;
752 Thread
->KernelStackResident
= TRUE
;
755 * Establish the pde's for the new stack and the thread structure within the
756 * address space of the new process. They are accessed while taskswitching or
757 * while handling page faults. At this point it isn't possible to call the
758 * page fault handler for the missing pde's.
760 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
761 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
763 /* Initalize the Thread Context */
764 DPRINT("Initializing the Context for the thread: %x\n", Thread
);
765 KiArchInitThreadWithContext(Thread
,
771 /* Setup scheduler Fields based on Parent */
772 DPRINT("Thread context created, setting Scheduler Data\n");
773 Thread
->BasePriority
= Process
->BasePriority
;
774 Thread
->Quantum
= Process
->ThreadQuantum
;
775 Thread
->Affinity
= Process
->Affinity
;
776 Thread
->Priority
= Process
->BasePriority
;
777 Thread
->UserAffinity
= Process
->Affinity
;
778 Thread
->DisableBoost
= Process
->DisableBoost
;
779 Thread
->AutoAlignment
= Process
->AutoAlignment
;
780 Thread
->Iopl
= Process
->Iopl
;
782 /* Set the Thread to initalized */
783 Thread
->State
= Initialized
;
786 * Insert the Thread into the Process's Thread List
787 * Note, this is the KTHREAD Thread List. It is removed in
788 * ke/kthread.c!KeTerminateThread.
790 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
791 DPRINT("Thread initalized\n");
800 KeQueryPriorityThread (IN PKTHREAD Thread
)
802 return Thread
->Priority
;
810 KeQueryRuntimeThread(IN PKTHREAD Thread
,
813 /* Return the User Time */
814 *UserTime
= Thread
->UserTime
;
816 /* Return the Kernel Time */
817 return Thread
->KernelTime
;
825 KeSetKernelStackSwapEnable(IN BOOLEAN Enable
)
827 PKTHREAD Thread
= KeGetCurrentThread();
828 BOOLEAN PreviousState
;
831 /* Lock the Dispatcher Database */
832 OldIrql
= KeAcquireDispatcherDatabaseLock();
835 PreviousState
= Thread
->EnableStackSwap
;
838 Thread
->EnableStackSwap
= Enable
;
840 /* No, Release Lock */
841 KeReleaseDispatcherDatabaseLock(OldIrql
);
843 /* Return Old State */
844 return PreviousState
;
852 KeRevertToUserAffinityThread(VOID
)
854 PKTHREAD CurrentThread
= KeGetCurrentThread();
857 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
859 /* Lock the Dispatcher Database */
860 OldIrql
= KeAcquireDispatcherDatabaseLock();
862 /* Return to User Affinity */
863 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
865 /* Disable System Affinity */
866 CurrentThread
->SystemAffinityActive
= FALSE
;
868 /* Check if we need to Dispatch a New thread */
869 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber())) {
871 /* No, just release */
872 KeReleaseDispatcherDatabaseLock(OldIrql
);
876 /* We need to dispatch a new thread */
877 CurrentThread
->WaitIrql
= OldIrql
;
878 KiDispatchThreadNoLock(Ready
);
879 KeLowerIrql(OldIrql
);
888 KeSetIdealProcessorThread(IN PKTHREAD Thread
,
891 CCHAR PreviousIdealProcessor
;
894 /* Lock the Dispatcher Database */
895 OldIrql
= KeAcquireDispatcherDatabaseLock();
897 /* Save Old Ideal Processor */
898 PreviousIdealProcessor
= Thread
->IdealProcessor
;
900 /* Set New Ideal Processor */
901 Thread
->IdealProcessor
= Processor
;
904 KeReleaseDispatcherDatabaseLock(OldIrql
);
906 /* Return Old Ideal Processor */
907 return PreviousIdealProcessor
;
915 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
917 PKTHREAD CurrentThread
= KeGetCurrentThread();
920 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
922 /* Lock the Dispatcher Database */
923 OldIrql
= KeAcquireDispatcherDatabaseLock();
925 /* Set the System Affinity Specified */
926 CurrentThread
->Affinity
= Affinity
;
928 /* Enable System Affinity */
929 CurrentThread
->SystemAffinityActive
= TRUE
;
931 /* Check if we need to Dispatch a New thread */
932 if (Affinity
& (1 << KeGetCurrentProcessorNumber())) {
934 /* No, just release */
935 KeReleaseDispatcherDatabaseLock(OldIrql
);
939 /* We need to dispatch a new thread */
940 CurrentThread
->WaitIrql
= OldIrql
;
941 KiDispatchThreadNoLock(Ready
);
942 KeLowerIrql(OldIrql
);
950 KeSetBasePriorityThread (PKTHREAD Thread
,
953 * Sets thread's base priority relative to the process' base priority
954 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
962 else if (Increment
> 2)
966 Priority
= ((PETHREAD
)Thread
)->ThreadsProcess
->Pcb
.BasePriority
+ Increment
;
967 if (Priority
< LOW_PRIORITY
)
969 Priority
= LOW_PRIORITY
;
971 else if (Priority
>= MAXIMUM_PRIORITY
)
973 Thread
->BasePriority
= HIGH_PRIORITY
;
975 KeSetPriorityThread(Thread
, Priority
);
984 KeSetPriorityThread(PKTHREAD Thread
,
987 KPRIORITY OldPriority
;
989 PKTHREAD CurrentThread
;
994 if (Priority
< LOW_PRIORITY
|| Priority
>= MAXIMUM_PRIORITY
) {
999 OldIrql
= KeAcquireDispatcherDatabaseLock();
1001 OldPriority
= Thread
->Priority
;
1003 if (OldPriority
!= Priority
) {
1005 CurrentThread
= KeGetCurrentThread();
1007 if (Thread
->State
== Ready
) {
1009 KiRemoveFromThreadList(Thread
);
1010 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1011 KiInsertIntoThreadList(Priority
, Thread
);
1013 if (CurrentThread
->Priority
< Priority
) {
1015 KiDispatchThreadNoLock(Ready
);
1016 KeLowerIrql(OldIrql
);
1017 return (OldPriority
);
1020 } else if (Thread
->State
== Running
) {
1022 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1024 if (Priority
< OldPriority
) {
1026 /* Check for threads with a higher priority */
1027 Mask
= ~((1 << (Priority
+ 1)) - 1);
1028 if (PriorityListMask
& Mask
) {
1030 if (Thread
== CurrentThread
) {
1032 KiDispatchThreadNoLock(Ready
);
1033 KeLowerIrql(OldIrql
);
1034 return (OldPriority
);
1038 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1040 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1042 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1044 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1045 KiRequestReschedule(i
);
1046 KeLowerIrql(OldIrql
);
1047 return (OldPriority
);
1055 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1059 KeReleaseDispatcherDatabaseLock(OldIrql
);
1060 return(OldPriority
);
1066 * Sets thread's affinity
1070 KeSetAffinityThread(PKTHREAD Thread
,
1076 KAFFINITY ProcessorMask
;
1078 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread
, Affinity
);
1080 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
1082 OldIrql
= KeAcquireDispatcherDatabaseLock();
1084 Thread
->UserAffinity
= Affinity
;
1086 if (Thread
->SystemAffinityActive
== FALSE
) {
1088 Thread
->Affinity
= Affinity
;
1090 if (Thread
->State
== Running
) {
1092 ProcessorMask
= 1 << KeGetCurrentKPCR()->ProcessorNumber
;
1093 if (Thread
== KeGetCurrentThread()) {
1095 if (!(Affinity
& ProcessorMask
)) {
1097 KiDispatchThreadNoLock(Ready
);
1098 KeLowerIrql(OldIrql
);
1099 return STATUS_SUCCESS
;
1104 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1106 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1107 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1109 if (!(Affinity
& ProcessorMask
)) {
1111 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1112 KiRequestReschedule(i
);
1113 KeLowerIrql(OldIrql
);
1114 return STATUS_SUCCESS
;
1121 ASSERT (i
< KeNumberProcessors
);
1126 KeReleaseDispatcherDatabaseLock(OldIrql
);
1127 return STATUS_SUCCESS
;
1133 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1136 KeTerminateThread(IN KPRIORITY Increment
)
1139 PKTHREAD Thread
= KeGetCurrentThread();
1141 /* Lock the Dispatcher Database and the APC Queue */
1142 DPRINT("Terminating\n");
1143 OldIrql
= KeAcquireDispatcherDatabaseLock();
1145 /* Remove the thread from the list */
1146 RemoveEntryList(&Thread
->ThreadListEntry
);
1148 /* Insert into the Reaper List */
1149 DPRINT("List: %p\n", PspReaperList
);
1150 ((PETHREAD
)Thread
)->ReaperLink
= PspReaperList
;
1151 PspReaperList
= (PETHREAD
)Thread
;
1152 DPRINT("List: %p\n", PspReaperList
);
1154 /* Check if it's active */
1155 if (PspReaping
== FALSE
) {
1157 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1159 DPRINT("Terminating\n");
1160 KiInsertQueue(&ExWorkerQueue
[HyperCriticalWorkQueue
].WorkerQueue
,
1161 &PspReaperWorkItem
.List
,
1165 /* Handle Kernel Queues */
1166 if (Thread
->Queue
) {
1168 DPRINT("Waking Queue\n");
1169 RemoveEntryList(&Thread
->QueueListEntry
);
1170 KiWakeQueue(Thread
->Queue
);
1173 /* Signal the thread */
1174 Thread
->DispatcherHeader
.SignalState
= TRUE
;
1175 if (IsListEmpty(&Thread
->DispatcherHeader
.WaitListHead
) != TRUE
) {
1178 KiWaitTest((PVOID
)Thread
, Increment
);
1181 /* Find a new Thread */
1182 KiDispatchThreadNoLock(Terminated
);
1186 * FUNCTION: Tests whether there are any pending APCs for the current thread
1187 * and if so the APCs will be delivered on exit from kernel mode
1191 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode
)
1194 PKTHREAD Thread
= KeGetCurrentThread();
1197 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1199 /* Lock the Dispatcher Database and the APC Queue */
1200 OldIrql
= KeAcquireDispatcherDatabaseLock();
1201 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
1203 /* Save the old State */
1204 OldState
= Thread
->Alerted
[AlertMode
];
1206 /* If the Thread is Alerted, Clear it */
1209 Thread
->Alerted
[AlertMode
] = FALSE
;
1211 } else if ((AlertMode
== UserMode
) && (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
]))) {
1213 /* If the mode is User and the Queue isn't empty, set Pending */
1214 Thread
->ApcState
.UserApcPending
= TRUE
;
1217 /* Release Locks and return the Old State */
1218 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
1219 KeReleaseDispatcherDatabaseLock(OldIrql
);
1224 KiServiceCheck (VOID
)
1226 PKTHREAD Thread
= KeGetCurrentThread();
1228 /* Check if we need to inialize Win32 for this Thread */
1229 if (Thread
->ServiceTable
!= KeServiceDescriptorTableShadow
) {
1231 /* We do. Initialize it and save the new table */
1232 PsInitWin32Thread((PETHREAD
)Thread
);
1233 Thread
->ServiceTable
= KeServiceDescriptorTableShadow
;
1243 NtAlertResumeThread(IN HANDLE ThreadHandle
,
1244 OUT PULONG SuspendCount
)
1246 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1249 ULONG PreviousState
;
1251 /* Check if parameters are valid */
1252 if(PreviousMode
!= KernelMode
) {
1256 ProbeForWrite(SuspendCount
,
1262 Status
= _SEH_GetExceptionCode();
1267 /* Reference the Object */
1268 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1269 THREAD_SUSPEND_RESUME
,
1275 /* Check for Success */
1276 if (NT_SUCCESS(Status
)) {
1278 /* Call the Kernel Function */
1279 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
1281 /* Dereference Object */
1282 ObDereferenceObject(Thread
);
1288 *SuspendCount
= PreviousState
;
1292 Status
= _SEH_GetExceptionCode();
1309 NtAlertThread (IN HANDLE ThreadHandle
)
1311 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1315 /* Reference the Object */
1316 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1317 THREAD_SUSPEND_RESUME
,
1323 /* Check for Success */
1324 if (NT_SUCCESS(Status
)) {
1327 * Do an alert depending on the processor mode. If some kmode code wants to
1328 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1329 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1330 * use KeAlertThread() directly
1332 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
1334 /* Dereference Object */
1335 ObDereferenceObject(Thread
);
1344 NtDelayExecution(IN BOOLEAN Alertable
,
1345 IN PLARGE_INTEGER DelayInterval
)
1347 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1348 LARGE_INTEGER SafeInterval
;
1351 /* Check if parameters are valid */
1352 if(PreviousMode
!= KernelMode
) {
1356 ProbeForRead(DelayInterval
,
1357 sizeof(LARGE_INTEGER
),
1360 /* make a copy on the kernel stack and let DelayInterval point to it so
1361 we don't need to wrap KeDelayExecutionThread in SEH! */
1362 SafeInterval
= *DelayInterval
;
1366 Status
= _SEH_GetExceptionCode();
1370 /* Call the Kernel Function */
1371 Status
= KeDelayExecutionThread(PreviousMode
,