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 KeRundownThread(VOID
)
395 PKTHREAD Thread
= KeGetCurrentThread();
396 PLIST_ENTRY CurrentEntry
;
399 DPRINT("KeRundownThread: %x\n", Thread
);
401 /* Lock the Dispatcher Database */
402 OldIrql
= KeAcquireDispatcherDatabaseLock();
404 while (!IsListEmpty(&Thread
->MutantListHead
)) {
407 CurrentEntry
= RemoveHeadList(&Thread
->MutantListHead
);
408 Mutant
= CONTAINING_RECORD(CurrentEntry
, KMUTANT
, MutantListEntry
);
409 ASSERT(Mutant
->ApcDisable
== 0);
411 /* Uncondtionally abandon it */
412 DPRINT("Abandonning the Mutant\n");
413 Mutant
->Header
.SignalState
= 1;
414 Mutant
->Abandoned
= TRUE
;
415 Mutant
->OwnerThread
= NULL
;
416 RemoveEntryList(&Mutant
->MutantListEntry
);
418 /* Check if the Wait List isn't empty */
419 DPRINT("Checking whether to wake the Mutant\n");
420 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
)) {
422 /* Wake the Mutant */
423 DPRINT("Waking the Mutant\n");
424 KiWaitTest(&Mutant
->Header
, MUTANT_INCREMENT
);
428 /* Release the Lock */
429 KeReleaseDispatcherDatabaseLock(OldIrql
);
434 KeResumeThread(PKTHREAD Thread
)
439 DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread
,
440 Thread
->SuspendCount
, Thread
->FreezeCount
);
442 /* Lock the Dispatcher */
443 OldIrql
= KeAcquireDispatcherDatabaseLock();
445 /* Save the Old Count */
446 PreviousCount
= Thread
->SuspendCount
;
448 /* Check if it existed */
451 Thread
->SuspendCount
--;
453 /* Decrease the current Suspend Count and Check Freeze Count */
454 if ((!Thread
->SuspendCount
) && (!Thread
->FreezeCount
)) {
456 /* Signal the Suspend Semaphore */
457 Thread
->SuspendSemaphore
.Header
.SignalState
++;
458 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
462 /* Release Lock and return the Old State */
463 KeReleaseDispatcherDatabaseLock(OldIrql
);
464 return PreviousCount
;
469 KiInsertQueueApc(PKAPC Apc
,
470 KPRIORITY PriorityBoost
);
473 * Used by the debugging code to freeze all the process's threads
474 * while the debugger is examining their state.
478 KeFreezeAllThreads(PKPROCESS Process
)
481 PLIST_ENTRY CurrentEntry
;
483 PKTHREAD CurrentThread
= KeGetCurrentThread();
486 OldIrql
= KeAcquireDispatcherDatabaseLock();
488 /* Loop the Process's Threads */
489 CurrentEntry
= Process
->ThreadListHead
.Flink
;
490 while (CurrentEntry
!= &Process
->ThreadListHead
)
493 Current
= CONTAINING_RECORD(CurrentEntry
, KTHREAD
, ThreadListEntry
);
495 /* Make sure it's not ours */
496 if (Current
== CurrentThread
) continue;
498 /* Make sure it wasn't already frozen, and that it's not suspended */
499 if (!(++Current
->FreezeCount
) && !(Current
->SuspendCount
))
502 if (!KiInsertQueueApc(&Current
->SuspendApc
, IO_NO_INCREMENT
))
504 /* Unsignal the Semaphore, the APC already got inserted */
505 Current
->SuspendSemaphore
.Header
.SignalState
--;
509 CurrentEntry
= CurrentEntry
->Flink
;
512 /* Release the lock */
513 KeReleaseDispatcherDatabaseLock(OldIrql
);
518 KeSuspendThread(PKTHREAD Thread
)
523 DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread
, Thread
->SuspendCount
, Thread
->FreezeCount
);
525 /* Lock the Dispatcher */
526 OldIrql
= KeAcquireDispatcherDatabaseLock();
528 /* Save the Old Count */
529 PreviousCount
= Thread
->SuspendCount
;
532 Thread
->SuspendCount
++;
534 /* Check if we should suspend it */
535 if (!PreviousCount
&& !Thread
->FreezeCount
) {
538 if (!KiInsertQueueApc(&Thread
->SuspendApc
, IO_NO_INCREMENT
)) {
540 /* Unsignal the Semaphore, the APC already got inserted */
541 Thread
->SuspendSemaphore
.Header
.SignalState
--;
545 /* Release Lock and return the Old State */
546 KeReleaseDispatcherDatabaseLock(OldIrql
);
547 return PreviousCount
;
552 KeForceResumeThread(IN PKTHREAD Thread
)
557 /* Lock the Dispatcher Database and the APC Queue */
558 OldIrql
= KeAcquireDispatcherDatabaseLock();
560 /* Save the old Suspend Count */
561 PreviousCount
= Thread
->SuspendCount
+ Thread
->FreezeCount
;
563 /* If the thread is suspended, wake it up!!! */
566 /* Unwait it completely */
567 Thread
->SuspendCount
= 0;
568 Thread
->FreezeCount
= 0;
570 /* Signal and satisfy */
571 Thread
->SuspendSemaphore
.Header
.SignalState
++;
572 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
575 /* Release Lock and return the Old State */
576 KeReleaseDispatcherDatabaseLock(OldIrql
);
577 return PreviousCount
;
582 KeAlertResumeThread(IN PKTHREAD Thread
)
587 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
589 /* Lock the Dispatcher Database and the APC Queue */
590 OldIrql
= KeAcquireDispatcherDatabaseLock();
591 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
593 /* Return if Thread is already alerted. */
594 if (Thread
->Alerted
[KernelMode
] == FALSE
) {
596 /* If it's Blocked, unblock if it we should */
597 if (Thread
->State
== Waiting
&& Thread
->Alertable
) {
599 DPRINT("Aborting Wait\n");
600 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
604 /* If not, simply Alert it */
605 Thread
->Alerted
[KernelMode
] = TRUE
;
609 /* Save the old Suspend Count */
610 PreviousCount
= Thread
->SuspendCount
;
612 /* If the thread is suspended, decrease one of the suspend counts */
615 /* Decrease count. If we are now zero, unwait it completely */
616 if (--Thread
->SuspendCount
) {
618 /* Signal and satisfy */
619 Thread
->SuspendSemaphore
.Header
.SignalState
++;
620 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
624 /* Release Locks and return the Old State */
625 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
626 KeReleaseDispatcherDatabaseLock(OldIrql
);
627 return PreviousCount
;
632 KeAlertThread(PKTHREAD Thread
,
633 KPROCESSOR_MODE AlertMode
)
636 BOOLEAN PreviousState
;
638 /* Acquire the Dispatcher Database Lock */
639 OldIrql
= KeAcquireDispatcherDatabaseLock();
641 /* Save the Previous State */
642 PreviousState
= Thread
->Alerted
[AlertMode
];
644 /* Return if Thread is already alerted. */
645 if (PreviousState
== FALSE
) {
647 /* If it's Blocked, unblock if it we should */
648 if (Thread
->State
== Waiting
&&
649 (AlertMode
== KernelMode
|| Thread
->WaitMode
== AlertMode
) &&
652 DPRINT("Aborting Wait\n");
653 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
657 /* If not, simply Alert it */
658 Thread
->Alerted
[AlertMode
] = TRUE
;
662 /* Release the Dispatcher Lock */
663 KeReleaseDispatcherDatabaseLock(OldIrql
);
665 /* Return the old state */
666 return PreviousState
;
674 KeCapturePersistentThreadState(IN PVOID CurrentThread
,
680 IN PVOID ThreadState
)
686 * FUNCTION: Initialize the microkernel state of the thread
690 KeInitializeThread(PKPROCESS Process
,
692 PKSYSTEM_ROUTINE SystemRoutine
,
693 PKSTART_ROUTINE StartRoutine
,
699 /* Initalize the Dispatcher Header */
700 DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread
, Process
);
701 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
706 DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
707 SystemRoutine
, StartRoutine
, StartContext
);
708 DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context
, Teb
);
710 /* Initialize the Mutant List */
711 InitializeListHead(&Thread
->MutantListHead
);
713 /* Setup the Service Descriptor Table for Native Calls */
714 Thread
->ServiceTable
= KeServiceDescriptorTable
;
716 /* Setup APC Fields */
717 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
718 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
719 Thread
->ApcState
.Process
= Process
;
720 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
721 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
722 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
723 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
725 /* Initialize the Suspend APC */
726 KeInitializeApc(&Thread
->SuspendApc
,
728 OriginalApcEnvironment
,
729 KiSuspendThreadKernelRoutine
,
731 KiSuspendThreadNormalRoutine
,
735 /* Initialize the Suspend Semaphore */
736 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
738 /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
740 Thread
->WaitBlock
[3].Object
= (PVOID
)&Thread
->Timer
;
741 Thread
->WaitBlock
[3].Thread
= Thread
;
742 Thread
->WaitBlock
[3].WaitKey
= STATUS_TIMEOUT
;
743 Thread
->WaitBlock
[3].WaitType
= WaitAny
;
744 Thread
->WaitBlock
[3].NextWaitBlock
= NULL
;
745 InsertTailList(&Thread
->Timer
.Header
.WaitListHead
,
746 &Thread
->WaitBlock
[3].WaitListEntry
);
748 KeInitializeTimer(&Thread
->Timer
);
753 /* Set the Thread Stacks */
754 Thread
->InitialStack
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
755 Thread
->StackBase
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
756 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
;
757 Thread
->KernelStackResident
= TRUE
;
760 * Establish the pde's for the new stack and the thread structure within the
761 * address space of the new process. They are accessed while taskswitching or
762 * while handling page faults. At this point it isn't possible to call the
763 * page fault handler for the missing pde's.
765 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
766 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
768 /* Initalize the Thread Context */
769 DPRINT("Initializing the Context for the thread: %x\n", Thread
);
770 KiArchInitThreadWithContext(Thread
,
776 /* Setup scheduler Fields based on Parent */
777 DPRINT("Thread context created, setting Scheduler Data\n");
778 Thread
->BasePriority
= Process
->BasePriority
;
779 Thread
->Quantum
= Process
->QuantumReset
;
780 Thread
->QuantumReset
= Process
->QuantumReset
;
781 Thread
->Affinity
= Process
->Affinity
;
782 Thread
->Priority
= Process
->BasePriority
;
783 Thread
->UserAffinity
= Process
->Affinity
;
784 Thread
->DisableBoost
= Process
->DisableBoost
;
785 Thread
->AutoAlignment
= Process
->AutoAlignment
;
786 Thread
->Iopl
= Process
->Iopl
;
788 /* Set the Thread to initalized */
789 Thread
->State
= Initialized
;
792 * Insert the Thread into the Process's Thread List
793 * Note, this is the KTHREAD Thread List. It is removed in
794 * ke/kthread.c!KeTerminateThread.
796 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
797 DPRINT("Thread initalized\n");
806 KeQueryPriorityThread (IN PKTHREAD Thread
)
808 return Thread
->Priority
;
816 KeQueryRuntimeThread(IN PKTHREAD Thread
,
819 /* Return the User Time */
820 *UserTime
= Thread
->UserTime
;
822 /* Return the Kernel Time */
823 return Thread
->KernelTime
;
831 KeSetKernelStackSwapEnable(IN BOOLEAN Enable
)
833 PKTHREAD Thread
= KeGetCurrentThread();
834 BOOLEAN PreviousState
;
837 /* Lock the Dispatcher Database */
838 OldIrql
= KeAcquireDispatcherDatabaseLock();
841 PreviousState
= Thread
->EnableStackSwap
;
844 Thread
->EnableStackSwap
= Enable
;
846 /* No, Release Lock */
847 KeReleaseDispatcherDatabaseLock(OldIrql
);
849 /* Return Old State */
850 return PreviousState
;
858 KeRevertToUserAffinityThread(VOID
)
860 PKTHREAD CurrentThread
= KeGetCurrentThread();
863 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
865 /* Lock the Dispatcher Database */
866 OldIrql
= KeAcquireDispatcherDatabaseLock();
868 /* Return to User Affinity */
869 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
871 /* Disable System Affinity */
872 CurrentThread
->SystemAffinityActive
= FALSE
;
874 /* Check if we need to Dispatch a New thread */
875 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber())) {
877 /* No, just release */
878 KeReleaseDispatcherDatabaseLock(OldIrql
);
882 /* We need to dispatch a new thread */
883 CurrentThread
->WaitIrql
= OldIrql
;
884 KiDispatchThreadNoLock(Ready
);
885 KeLowerIrql(OldIrql
);
894 KeSetIdealProcessorThread(IN PKTHREAD Thread
,
897 CCHAR PreviousIdealProcessor
;
900 /* Lock the Dispatcher Database */
901 OldIrql
= KeAcquireDispatcherDatabaseLock();
903 /* Save Old Ideal Processor */
904 PreviousIdealProcessor
= Thread
->IdealProcessor
;
906 /* Set New Ideal Processor */
907 Thread
->IdealProcessor
= Processor
;
910 KeReleaseDispatcherDatabaseLock(OldIrql
);
912 /* Return Old Ideal Processor */
913 return PreviousIdealProcessor
;
921 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
923 PKTHREAD CurrentThread
= KeGetCurrentThread();
926 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
928 /* Lock the Dispatcher Database */
929 OldIrql
= KeAcquireDispatcherDatabaseLock();
931 /* Set the System Affinity Specified */
932 CurrentThread
->Affinity
= Affinity
;
934 /* Enable System Affinity */
935 CurrentThread
->SystemAffinityActive
= TRUE
;
937 /* Check if we need to Dispatch a New thread */
938 if (Affinity
& (1 << KeGetCurrentProcessorNumber())) {
940 /* No, just release */
941 KeReleaseDispatcherDatabaseLock(OldIrql
);
945 /* We need to dispatch a new thread */
946 CurrentThread
->WaitIrql
= OldIrql
;
947 KiDispatchThreadNoLock(Ready
);
948 KeLowerIrql(OldIrql
);
956 KeSetBasePriorityThread (PKTHREAD Thread
,
959 * Sets thread's base priority relative to the process' base priority
960 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
968 else if (Increment
> 2)
972 Priority
= ((PETHREAD
)Thread
)->ThreadsProcess
->Pcb
.BasePriority
+ Increment
;
973 if (Priority
< LOW_PRIORITY
)
975 Priority
= LOW_PRIORITY
;
977 else if (Priority
>= MAXIMUM_PRIORITY
)
979 Thread
->BasePriority
= HIGH_PRIORITY
;
981 KeSetPriorityThread(Thread
, Priority
);
990 KeSetPriorityThread(PKTHREAD Thread
,
993 KPRIORITY OldPriority
;
995 PKTHREAD CurrentThread
;
1000 if (Priority
< LOW_PRIORITY
|| Priority
>= MAXIMUM_PRIORITY
) {
1005 OldIrql
= KeAcquireDispatcherDatabaseLock();
1007 OldPriority
= Thread
->Priority
;
1009 if (OldPriority
!= Priority
) {
1011 CurrentThread
= KeGetCurrentThread();
1013 if (Thread
->State
== Ready
) {
1015 KiRemoveFromThreadList(Thread
);
1016 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1017 KiInsertIntoThreadList(Priority
, Thread
);
1019 if (CurrentThread
->Priority
< Priority
) {
1021 KiDispatchThreadNoLock(Ready
);
1022 KeLowerIrql(OldIrql
);
1023 return (OldPriority
);
1026 } else if (Thread
->State
== Running
) {
1028 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1030 if (Priority
< OldPriority
) {
1032 /* Check for threads with a higher priority */
1033 Mask
= ~((1 << (Priority
+ 1)) - 1);
1034 if (PriorityListMask
& Mask
) {
1036 if (Thread
== CurrentThread
) {
1038 KiDispatchThreadNoLock(Ready
);
1039 KeLowerIrql(OldIrql
);
1040 return (OldPriority
);
1044 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1046 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1048 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1050 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1051 KiRequestReschedule(i
);
1052 KeLowerIrql(OldIrql
);
1053 return (OldPriority
);
1061 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1065 KeReleaseDispatcherDatabaseLock(OldIrql
);
1066 return(OldPriority
);
1072 * Sets thread's affinity
1076 KeSetAffinityThread(PKTHREAD Thread
,
1082 KAFFINITY ProcessorMask
;
1084 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread
, Affinity
);
1086 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
1088 OldIrql
= KeAcquireDispatcherDatabaseLock();
1090 Thread
->UserAffinity
= Affinity
;
1092 if (Thread
->SystemAffinityActive
== FALSE
) {
1094 Thread
->Affinity
= Affinity
;
1096 if (Thread
->State
== Running
) {
1098 ProcessorMask
= 1 << KeGetCurrentKPCR()->Number
;
1099 if (Thread
== KeGetCurrentThread()) {
1101 if (!(Affinity
& ProcessorMask
)) {
1103 KiDispatchThreadNoLock(Ready
);
1104 KeLowerIrql(OldIrql
);
1105 return STATUS_SUCCESS
;
1110 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1112 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1113 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1115 if (!(Affinity
& ProcessorMask
)) {
1117 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1118 KiRequestReschedule(i
);
1119 KeLowerIrql(OldIrql
);
1120 return STATUS_SUCCESS
;
1127 ASSERT (i
< KeNumberProcessors
);
1132 KeReleaseDispatcherDatabaseLock(OldIrql
);
1133 return STATUS_SUCCESS
;
1139 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1142 KeTerminateThread(IN KPRIORITY Increment
)
1145 PKTHREAD Thread
= KeGetCurrentThread();
1147 /* Lock the Dispatcher Database and the APC Queue */
1148 DPRINT("Terminating\n");
1149 OldIrql
= KeAcquireDispatcherDatabaseLock();
1151 /* Remove the thread from the list */
1152 RemoveEntryList(&Thread
->ThreadListEntry
);
1154 /* Insert into the Reaper List */
1155 DPRINT("List: %p\n", PspReaperList
);
1156 ((PETHREAD
)Thread
)->ReaperLink
= PspReaperList
;
1157 PspReaperList
= (PETHREAD
)Thread
;
1158 DPRINT("List: %p\n", PspReaperList
);
1160 /* Check if it's active */
1161 if (PspReaping
== FALSE
) {
1163 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1165 DPRINT("Terminating\n");
1166 KiInsertQueue(&ExWorkerQueue
[HyperCriticalWorkQueue
].WorkerQueue
,
1167 &PspReaperWorkItem
.List
,
1171 /* Handle Kernel Queues */
1172 if (Thread
->Queue
) {
1174 DPRINT("Waking Queue\n");
1175 RemoveEntryList(&Thread
->QueueListEntry
);
1176 KiWakeQueue(Thread
->Queue
);
1179 /* Signal the thread */
1180 Thread
->DispatcherHeader
.SignalState
= TRUE
;
1181 if (IsListEmpty(&Thread
->DispatcherHeader
.WaitListHead
) != TRUE
) {
1184 KiWaitTest((PVOID
)Thread
, Increment
);
1187 /* Find a new Thread */
1188 KiDispatchThreadNoLock(Terminated
);
1192 * FUNCTION: Tests whether there are any pending APCs for the current thread
1193 * and if so the APCs will be delivered on exit from kernel mode
1197 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode
)
1200 PKTHREAD Thread
= KeGetCurrentThread();
1203 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1205 /* Lock the Dispatcher Database and the APC Queue */
1206 OldIrql
= KeAcquireDispatcherDatabaseLock();
1207 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
1209 /* Save the old State */
1210 OldState
= Thread
->Alerted
[AlertMode
];
1212 /* If the Thread is Alerted, Clear it */
1215 Thread
->Alerted
[AlertMode
] = FALSE
;
1217 } else if ((AlertMode
== UserMode
) && (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
]))) {
1219 /* If the mode is User and the Queue isn't empty, set Pending */
1220 Thread
->ApcState
.UserApcPending
= TRUE
;
1223 /* Release Locks and return the Old State */
1224 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
1225 KeReleaseDispatcherDatabaseLock(OldIrql
);
1230 KiServiceCheck (VOID
)
1232 PKTHREAD Thread
= KeGetCurrentThread();
1234 /* Check if we need to inialize Win32 for this Thread */
1235 if (Thread
->ServiceTable
!= KeServiceDescriptorTableShadow
) {
1237 /* We do. Initialize it and save the new table */
1238 PsInitWin32Thread((PETHREAD
)Thread
);
1239 Thread
->ServiceTable
= KeServiceDescriptorTableShadow
;
1249 NtAlertResumeThread(IN HANDLE ThreadHandle
,
1250 OUT PULONG SuspendCount
)
1252 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1255 ULONG PreviousState
;
1257 /* Check if parameters are valid */
1258 if(PreviousMode
!= KernelMode
) {
1262 ProbeForWrite(SuspendCount
,
1268 Status
= _SEH_GetExceptionCode();
1273 /* Reference the Object */
1274 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1275 THREAD_SUSPEND_RESUME
,
1281 /* Check for Success */
1282 if (NT_SUCCESS(Status
)) {
1284 /* Call the Kernel Function */
1285 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
1287 /* Dereference Object */
1288 ObDereferenceObject(Thread
);
1294 *SuspendCount
= PreviousState
;
1298 Status
= _SEH_GetExceptionCode();
1315 NtAlertThread (IN HANDLE ThreadHandle
)
1317 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1321 /* Reference the Object */
1322 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1323 THREAD_SUSPEND_RESUME
,
1329 /* Check for Success */
1330 if (NT_SUCCESS(Status
)) {
1333 * Do an alert depending on the processor mode. If some kmode code wants to
1334 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1335 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1336 * use KeAlertThread() directly
1338 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
1340 /* Dereference Object */
1341 ObDereferenceObject(Thread
);
1350 NtDelayExecution(IN BOOLEAN Alertable
,
1351 IN PLARGE_INTEGER DelayInterval
)
1353 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1354 LARGE_INTEGER SafeInterval
;
1357 /* Check if parameters are valid */
1358 if(PreviousMode
!= KernelMode
) {
1362 ProbeForRead(DelayInterval
,
1363 sizeof(LARGE_INTEGER
),
1366 /* make a copy on the kernel stack and let DelayInterval point to it so
1367 we don't need to wrap KeDelayExecutionThread in SEH! */
1368 SafeInterval
= *DelayInterval
;
1372 Status
= _SEH_GetExceptionCode();
1376 /* Call the Kernel Function */
1377 Status
= KeDelayExecutionThread(PreviousMode
,