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>
18 #define MAXIMUM_SUSPEND_COUNT 0x7F
19 #define THREAD_ALERT_INCREMENT 2
21 extern EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
24 * PURPOSE: List of threads associated with each priority level
26 LIST_ENTRY PriorityListHead
[MAXIMUM_PRIORITY
];
27 static ULONG PriorityListMask
= 0;
28 ULONG IdleProcessorMask
= 0;
29 extern PETHREAD PspReaperList
;
31 /* FUNCTIONS *****************************************************************/
35 KiRequestReschedule(CCHAR Processor
)
39 Pcr
= (PKPCR
)(KPCR_BASE
+ Processor
* PAGE_SIZE
);
40 Pcr
->Prcb
->QuantumEnd
= TRUE
;
41 KiIpiSendRequest(1 << Processor
, IPI_REQUEST_DPC
);
46 KiInsertIntoThreadList(KPRIORITY Priority
,
49 ASSERT(Ready
== Thread
->State
);
50 ASSERT(Thread
->Priority
== Priority
);
52 if (Priority
>= MAXIMUM_PRIORITY
|| Priority
< LOW_PRIORITY
) {
54 DPRINT1("Invalid thread priority (%d)\n", Priority
);
58 InsertTailList(&PriorityListHead
[Priority
], &Thread
->WaitListEntry
);
59 PriorityListMask
|= (1 << Priority
);
64 KiRemoveFromThreadList(PKTHREAD Thread
)
66 ASSERT(Ready
== Thread
->State
);
67 RemoveEntryList(&Thread
->WaitListEntry
);
68 if (IsListEmpty(&PriorityListHead
[(ULONG
)Thread
->Priority
])) {
70 PriorityListMask
&= ~(1 << Thread
->Priority
);
76 KiScanThreadList(KPRIORITY Priority
,
79 PLIST_ENTRY current_entry
;
83 Mask
= (1 << Priority
);
85 if (PriorityListMask
& Mask
) {
87 current_entry
= PriorityListHead
[Priority
].Flink
;
89 while (current_entry
!= &PriorityListHead
[Priority
]) {
91 current
= CONTAINING_RECORD(current_entry
, KTHREAD
, WaitListEntry
);
93 if (current
->State
!= Ready
) {
95 DPRINT1("%d/%d\n", ¤t
, current
->State
);
98 ASSERT(current
->State
== Ready
);
100 if (current
->Affinity
& Affinity
) {
102 KiRemoveFromThreadList(current
);
106 current_entry
= current_entry
->Flink
;
115 KiDispatchThreadNoLock(ULONG NewThreadStatus
)
117 KPRIORITY CurrentPriority
;
120 PKTHREAD CurrentThread
= KeGetCurrentThread();
122 DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
123 CurrentThread
, NewThreadStatus
, CurrentThread
->State
);
125 CurrentThread
->State
= (UCHAR
)NewThreadStatus
;
127 if (NewThreadStatus
== Ready
) {
129 KiInsertIntoThreadList(CurrentThread
->Priority
,
133 Affinity
= 1 << KeGetCurrentProcessorNumber();
135 for (CurrentPriority
= HIGH_PRIORITY
; CurrentPriority
>= LOW_PRIORITY
; CurrentPriority
--) {
137 Candidate
= KiScanThreadList(CurrentPriority
, Affinity
);
139 if (Candidate
== CurrentThread
) {
141 Candidate
->State
= Running
;
142 KeReleaseDispatcherDatabaseLockFromDpcLevel();
146 if (Candidate
!= NULL
) {
151 DPRINT("Scheduling %x(%d)\n",Candidate
, CurrentPriority
);
153 Candidate
->State
= Running
;
155 OldThread
= CurrentThread
;
156 CurrentThread
= Candidate
;
157 IdleThread
= KeGetCurrentPrcb()->IdleThread
;
159 if (OldThread
== IdleThread
) {
161 IdleProcessorMask
&= ~Affinity
;
163 } else if (CurrentThread
== IdleThread
) {
165 IdleProcessorMask
|= Affinity
;
168 MmUpdatePageDir(PsGetCurrentProcess(),((PETHREAD
)CurrentThread
)->ThreadsProcess
, sizeof(EPROCESS
));
170 /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
171 DPRINT("You are : %x, swapping to: %x\n", OldThread
, CurrentThread
);
172 KiArchContextSwitch(CurrentThread
);
173 DPRINT("You are : %x, swapped from: %x\n", OldThread
, CurrentThread
);
178 DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
184 KiBlockThread(PNTSTATUS Status
,
189 PKTHREAD Thread
= KeGetCurrentThread();
190 PKWAIT_BLOCK WaitBlock
;
192 if (Thread
->ApcState
.KernelApcPending
) {
194 DPRINT("Dispatching Thread as ready (APC!)\n");
197 WaitBlock
= Thread
->WaitBlockList
;
199 RemoveEntryList (&WaitBlock
->WaitListEntry
);
200 WaitBlock
= WaitBlock
->NextWaitBlock
;
201 } while (WaitBlock
!= Thread
->WaitBlockList
);
202 Thread
->WaitBlockList
= NULL
;
204 /* Dispatch it and return status */
205 KiDispatchThreadNoLock (Ready
);
206 if (Status
!= NULL
) *Status
= STATUS_KERNEL_APC
;
210 /* Set the Thread Data as Requested */
211 DPRINT("Dispatching Thread as blocked: %d\n", Thread
->WaitStatus
);
212 Thread
->Alertable
= Alertable
;
213 Thread
->WaitMode
= (UCHAR
)WaitMode
;
214 Thread
->WaitReason
= WaitReason
;
216 /* Dispatch it and return status */
217 KiDispatchThreadNoLock(Waiting
);
218 DPRINT("Dispatching Thread as blocked: %d\n", Thread
->WaitStatus
);
219 if (Status
!= NULL
) *Status
= Thread
->WaitStatus
;
222 DPRINT("Releasing Dispatcher Lock\n");
223 KfLowerIrql(Thread
->WaitIrql
);
228 KiDispatchThread(ULONG NewThreadStatus
)
232 if (KeGetCurrentPrcb()->IdleThread
== NULL
) {
236 OldIrql
= KeAcquireDispatcherDatabaseLock();
237 KiDispatchThreadNoLock(NewThreadStatus
);
238 KeLowerIrql(OldIrql
);
243 KiUnblockThread(PKTHREAD Thread
,
244 PNTSTATUS WaitStatus
,
247 if (Terminated
== Thread
->State
) {
249 DPRINT("Can't unblock thread 0x%x because it's terminating\n",
252 } else if (Ready
== Thread
->State
||
253 Running
== Thread
->State
) {
255 DPRINT("Can't unblock thread 0x%x because it's %s\n",
256 Thread
, (Thread
->State
== Ready
? "ready" : "running"));
263 /* FIXME: This propably isn't the right way to do it... */
264 /* No it's not... i'll fix it later-- Alex */
265 if (Thread
->Priority
< LOW_REALTIME_PRIORITY
&&
266 Thread
->BasePriority
< LOW_REALTIME_PRIORITY
- 2) {
268 if (!Thread
->PriorityDecrement
&& !Thread
->DisableBoost
) {
270 Thread
->Priority
= Thread
->BasePriority
+ Increment
;
271 Thread
->PriorityDecrement
= Increment
;
274 /* Also decrease quantum */
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 KiAdjustQuantumThread(IN PKTHREAD Thread
)
328 /* Don't adjust for RT threads */
329 if ((Thread
->Priority
< LOW_REALTIME_PRIORITY
) &&
330 Thread
->BasePriority
< LOW_REALTIME_PRIORITY
- 2)
332 /* Decrease Quantum by one and see if we've ran out */
333 if (--Thread
->Quantum
<= 0)
336 Thread
->Quantum
= Thread
->QuantumReset
;
338 /* Calculate new Priority */
339 Priority
= Thread
->Priority
- (Thread
->PriorityDecrement
+ 1);
341 /* Normalize it if we've gone too low */
342 if (Priority
< Thread
->BasePriority
) Priority
= Thread
->BasePriority
;
344 /* Reset the priority decrement, we've done it */
345 Thread
->PriorityDecrement
= 0;
347 /* Set the new priority, if needed */
348 if (Priority
!= Thread
->Priority
)
351 * HACK HACK This isn't nice, but it's the only way with our
354 Thread
->Priority
= Priority
;
358 /* FIXME: Priority hasn't changed, find a new thread */
363 /* Nothing to do... */
370 KiSuspendThreadKernelRoutine(PKAPC Apc
,
371 PKNORMAL_ROUTINE
* NormalRoutine
,
372 PVOID
* NormalContext
,
373 PVOID
* SystemArgument1
,
374 PVOID
* SystemArguemnt2
)
380 KiSuspendThreadNormalRoutine(PVOID NormalContext
,
381 PVOID SystemArgument1
,
382 PVOID SystemArgument2
)
384 PKTHREAD CurrentThread
= KeGetCurrentThread();
386 /* Non-alertable kernel-mode suspended wait */
387 DPRINT("Waiting...\n");
388 KeWaitForSingleObject(&CurrentThread
->SuspendSemaphore
,
393 DPRINT("Done Waiting\n");
396 #ifdef KeGetCurrentThread
397 #undef KeGetCurrentThread
404 KeGetCurrentThread(VOID
)
409 Ke386SaveFlags(Flags
);
410 Ke386DisableInterrupts();
411 Thread
= KeGetCurrentPrcb()->CurrentThread
;
412 Ke386RestoreFlags(Flags
);
415 return(KeGetCurrentPrcb()->CurrentThread
);
421 KeSetPreviousMode(ULONG Mode
)
423 PsGetCurrentThread()->Tcb
.PreviousMode
= (UCHAR
)Mode
;
431 KeGetPreviousMode(VOID
)
433 return (ULONG
)PsGetCurrentThread()->Tcb
.PreviousMode
;
438 KeDisableThreadApcQueueing(IN PKTHREAD Thread
)
441 BOOLEAN PreviousState
;
443 /* Lock the Dispatcher Database */
444 OldIrql
= KeAcquireDispatcherDatabaseLock();
447 PreviousState
= Thread
->ApcQueueable
;
450 Thread
->ApcQueueable
= FALSE
;
452 /* Release the Lock */
453 KeReleaseDispatcherDatabaseLock(OldIrql
);
455 /* Return old state */
456 return PreviousState
;
461 KeRundownThread(VOID
)
464 PKTHREAD Thread
= KeGetCurrentThread();
465 PLIST_ENTRY CurrentEntry
;
468 DPRINT("KeRundownThread: %x\n", Thread
);
470 /* Lock the Dispatcher Database */
471 OldIrql
= KeAcquireDispatcherDatabaseLock();
473 while (!IsListEmpty(&Thread
->MutantListHead
)) {
476 CurrentEntry
= RemoveHeadList(&Thread
->MutantListHead
);
477 Mutant
= CONTAINING_RECORD(CurrentEntry
, KMUTANT
, MutantListEntry
);
478 ASSERT(Mutant
->ApcDisable
== 0);
480 /* Uncondtionally abandon it */
481 DPRINT("Abandonning the Mutant\n");
482 Mutant
->Header
.SignalState
= 1;
483 Mutant
->Abandoned
= TRUE
;
484 Mutant
->OwnerThread
= NULL
;
485 RemoveEntryList(&Mutant
->MutantListEntry
);
487 /* Check if the Wait List isn't empty */
488 DPRINT("Checking whether to wake the Mutant\n");
489 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
)) {
491 /* Wake the Mutant */
492 DPRINT("Waking the Mutant\n");
493 KiWaitTest(&Mutant
->Header
, MUTANT_INCREMENT
);
497 /* Release the Lock */
498 KeReleaseDispatcherDatabaseLock(OldIrql
);
503 KeResumeThread(PKTHREAD Thread
)
508 DPRINT("KeResumeThread (Thread %p called). %x, %x\n", Thread
,
509 Thread
->SuspendCount
, Thread
->FreezeCount
);
511 /* Lock the Dispatcher */
512 OldIrql
= KeAcquireDispatcherDatabaseLock();
514 /* Save the Old Count */
515 PreviousCount
= Thread
->SuspendCount
;
517 /* Check if it existed */
520 Thread
->SuspendCount
--;
522 /* Decrease the current Suspend Count and Check Freeze Count */
523 if ((!Thread
->SuspendCount
) && (!Thread
->FreezeCount
)) {
525 /* Signal the Suspend Semaphore */
526 Thread
->SuspendSemaphore
.Header
.SignalState
++;
527 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
531 /* Release Lock and return the Old State */
532 KeReleaseDispatcherDatabaseLock(OldIrql
);
533 return PreviousCount
;
538 KiInsertQueueApc(PKAPC Apc
,
539 KPRIORITY PriorityBoost
);
542 * Used by the debugging code to freeze all the process's threads
543 * while the debugger is examining their state.
547 KeFreezeAllThreads(PKPROCESS Process
)
550 PLIST_ENTRY CurrentEntry
;
552 PKTHREAD CurrentThread
= KeGetCurrentThread();
555 OldIrql
= KeAcquireDispatcherDatabaseLock();
557 /* Loop the Process's Threads */
558 CurrentEntry
= Process
->ThreadListHead
.Flink
;
559 while (CurrentEntry
!= &Process
->ThreadListHead
)
562 Current
= CONTAINING_RECORD(CurrentEntry
, KTHREAD
, ThreadListEntry
);
564 /* Make sure it's not ours */
565 if (Current
== CurrentThread
) continue;
567 /* Make sure it wasn't already frozen, and that it's not suspended */
568 if (!(++Current
->FreezeCount
) && !(Current
->SuspendCount
))
571 if (!KiInsertQueueApc(&Current
->SuspendApc
, IO_NO_INCREMENT
))
573 /* Unsignal the Semaphore, the APC already got inserted */
574 Current
->SuspendSemaphore
.Header
.SignalState
--;
578 CurrentEntry
= CurrentEntry
->Flink
;
581 /* Release the lock */
582 KeReleaseDispatcherDatabaseLock(OldIrql
);
587 KeSuspendThread(PKTHREAD Thread
)
592 DPRINT("KeSuspendThread (Thread %p called). %x, %x\n", Thread
, Thread
->SuspendCount
, Thread
->FreezeCount
);
594 /* Lock the Dispatcher */
595 OldIrql
= KeAcquireDispatcherDatabaseLock();
597 /* Save the Old Count */
598 PreviousCount
= Thread
->SuspendCount
;
600 /* Handle the maximum */
601 if (PreviousCount
== MAXIMUM_SUSPEND_COUNT
)
603 /* Raise an exception */
604 KeReleaseDispatcherDatabaseLock(OldIrql
);
605 ExRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED
);
609 Thread
->SuspendCount
++;
611 /* Check if we should suspend it */
612 if (!PreviousCount
&& !Thread
->FreezeCount
) {
615 if (!KiInsertQueueApc(&Thread
->SuspendApc
, IO_NO_INCREMENT
)) {
617 /* Unsignal the Semaphore, the APC already got inserted */
618 Thread
->SuspendSemaphore
.Header
.SignalState
--;
622 /* Release Lock and return the Old State */
623 KeReleaseDispatcherDatabaseLock(OldIrql
);
624 return PreviousCount
;
629 KeForceResumeThread(IN PKTHREAD Thread
)
634 /* Lock the Dispatcher Database and the APC Queue */
635 OldIrql
= KeAcquireDispatcherDatabaseLock();
637 /* Save the old Suspend Count */
638 PreviousCount
= Thread
->SuspendCount
+ Thread
->FreezeCount
;
640 /* If the thread is suspended, wake it up!!! */
643 /* Unwait it completely */
644 Thread
->SuspendCount
= 0;
645 Thread
->FreezeCount
= 0;
647 /* Signal and satisfy */
648 Thread
->SuspendSemaphore
.Header
.SignalState
++;
649 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
652 /* Release Lock and return the Old State */
653 KeReleaseDispatcherDatabaseLock(OldIrql
);
654 return PreviousCount
;
659 KeAlertResumeThread(IN PKTHREAD Thread
)
664 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
666 /* Lock the Dispatcher Database and the APC Queue */
667 OldIrql
= KeAcquireDispatcherDatabaseLock();
668 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
670 /* Return if Thread is already alerted. */
671 if (Thread
->Alerted
[KernelMode
] == FALSE
) {
673 /* If it's Blocked, unblock if it we should */
674 if (Thread
->State
== Waiting
&& Thread
->Alertable
) {
676 DPRINT("Aborting Wait\n");
677 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
681 /* If not, simply Alert it */
682 Thread
->Alerted
[KernelMode
] = TRUE
;
686 /* Save the old Suspend Count */
687 PreviousCount
= Thread
->SuspendCount
;
689 /* If the thread is suspended, decrease one of the suspend counts */
692 /* Decrease count. If we are now zero, unwait it completely */
693 if (--Thread
->SuspendCount
) {
695 /* Signal and satisfy */
696 Thread
->SuspendSemaphore
.Header
.SignalState
++;
697 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
701 /* Release Locks and return the Old State */
702 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
703 KeReleaseDispatcherDatabaseLock(OldIrql
);
704 return PreviousCount
;
709 KeAlertThread(PKTHREAD Thread
,
710 KPROCESSOR_MODE AlertMode
)
713 BOOLEAN PreviousState
;
715 /* Acquire the Dispatcher Database Lock */
716 OldIrql
= KeAcquireDispatcherDatabaseLock();
718 /* Save the Previous State */
719 PreviousState
= Thread
->Alerted
[AlertMode
];
721 /* Return if Thread is already alerted. */
722 if (PreviousState
== FALSE
) {
724 /* If it's Blocked, unblock if it we should */
725 if (Thread
->State
== Waiting
&&
726 (AlertMode
== KernelMode
|| Thread
->WaitMode
== AlertMode
) &&
729 DPRINT("Aborting Wait\n");
730 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
734 /* If not, simply Alert it */
735 Thread
->Alerted
[AlertMode
] = TRUE
;
739 /* Release the Dispatcher Lock */
740 KeReleaseDispatcherDatabaseLock(OldIrql
);
742 /* Return the old state */
743 return PreviousState
;
751 KeCapturePersistentThreadState(IN PVOID CurrentThread
,
757 IN PVOID ThreadState
)
763 * FUNCTION: Initialize the microkernel state of the thread
767 KeInitializeThread(PKPROCESS Process
,
769 PKSYSTEM_ROUTINE SystemRoutine
,
770 PKSTART_ROUTINE StartRoutine
,
776 /* Initalize the Dispatcher Header */
777 DPRINT("Initializing Dispatcher Header for New Thread: %x in Process: %x\n", Thread
, Process
);
778 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
783 DPRINT("Thread Header Created. SystemRoutine: %x, StartRoutine: %x with Context: %x\n",
784 SystemRoutine
, StartRoutine
, StartContext
);
785 DPRINT("UserMode Information. Context: %x, Teb: %x\n", Context
, Teb
);
787 /* Initialize the Mutant List */
788 InitializeListHead(&Thread
->MutantListHead
);
790 /* Setup the Service Descriptor Table for Native Calls */
791 Thread
->ServiceTable
= KeServiceDescriptorTable
;
793 /* Setup APC Fields */
794 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
795 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
796 Thread
->ApcState
.Process
= Process
;
797 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
798 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
799 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
800 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
802 /* Initialize the Suspend APC */
803 KeInitializeApc(&Thread
->SuspendApc
,
805 OriginalApcEnvironment
,
806 KiSuspendThreadKernelRoutine
,
808 KiSuspendThreadNormalRoutine
,
812 /* Initialize the Suspend Semaphore */
813 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 128);
815 /* FIXME OPTIMIZATION OF DOOM. DO NOT ENABLE FIXME */
817 Thread
->WaitBlock
[3].Object
= (PVOID
)&Thread
->Timer
;
818 Thread
->WaitBlock
[3].Thread
= Thread
;
819 Thread
->WaitBlock
[3].WaitKey
= STATUS_TIMEOUT
;
820 Thread
->WaitBlock
[3].WaitType
= WaitAny
;
821 Thread
->WaitBlock
[3].NextWaitBlock
= NULL
;
822 InsertTailList(&Thread
->Timer
.Header
.WaitListHead
,
823 &Thread
->WaitBlock
[3].WaitListEntry
);
825 KeInitializeTimer(&Thread
->Timer
);
830 /* Set the Thread Stacks */
831 Thread
->InitialStack
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
832 Thread
->StackBase
= (PCHAR
)KernelStack
+ MM_STACK_SIZE
;
833 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
;
834 Thread
->KernelStackResident
= TRUE
;
837 * Establish the pde's for the new stack and the thread structure within the
838 * address space of the new process. They are accessed while taskswitching or
839 * while handling page faults. At this point it isn't possible to call the
840 * page fault handler for the missing pde's.
842 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
->StackLimit
, MM_STACK_SIZE
);
843 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
845 /* Initalize the Thread Context */
846 DPRINT("Initializing the Context for the thread: %x\n", Thread
);
847 KiArchInitThreadWithContext(Thread
,
853 /* Setup scheduler Fields based on Parent */
854 DPRINT("Thread context created, setting Scheduler Data\n");
855 Thread
->BasePriority
= Process
->BasePriority
;
856 Thread
->Quantum
= Process
->QuantumReset
;
857 Thread
->QuantumReset
= Process
->QuantumReset
;
858 Thread
->Affinity
= Process
->Affinity
;
859 Thread
->Priority
= Process
->BasePriority
;
860 Thread
->UserAffinity
= Process
->Affinity
;
861 Thread
->DisableBoost
= Process
->DisableBoost
;
862 Thread
->AutoAlignment
= Process
->AutoAlignment
;
863 Thread
->Iopl
= Process
->Iopl
;
865 /* Set the Thread to initalized */
866 Thread
->State
= Initialized
;
869 * Insert the Thread into the Process's Thread List
870 * Note, this is the KTHREAD Thread List. It is removed in
871 * ke/kthread.c!KeTerminateThread.
873 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
874 DPRINT("Thread initalized\n");
883 KeQueryPriorityThread (IN PKTHREAD Thread
)
885 return Thread
->Priority
;
893 KeQueryRuntimeThread(IN PKTHREAD Thread
,
896 /* Return the User Time */
897 *UserTime
= Thread
->UserTime
;
899 /* Return the Kernel Time */
900 return Thread
->KernelTime
;
908 KeSetKernelStackSwapEnable(IN BOOLEAN Enable
)
910 PKTHREAD Thread
= KeGetCurrentThread();
911 BOOLEAN PreviousState
;
914 /* Lock the Dispatcher Database */
915 OldIrql
= KeAcquireDispatcherDatabaseLock();
918 PreviousState
= Thread
->EnableStackSwap
;
921 Thread
->EnableStackSwap
= Enable
;
923 /* No, Release Lock */
924 KeReleaseDispatcherDatabaseLock(OldIrql
);
926 /* Return Old State */
927 return PreviousState
;
935 KeRevertToUserAffinityThread(VOID
)
937 PKTHREAD CurrentThread
= KeGetCurrentThread();
940 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
942 /* Lock the Dispatcher Database */
943 OldIrql
= KeAcquireDispatcherDatabaseLock();
945 /* Return to User Affinity */
946 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
948 /* Disable System Affinity */
949 CurrentThread
->SystemAffinityActive
= FALSE
;
951 /* Check if we need to Dispatch a New thread */
952 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber())) {
954 /* No, just release */
955 KeReleaseDispatcherDatabaseLock(OldIrql
);
959 /* We need to dispatch a new thread */
960 CurrentThread
->WaitIrql
= OldIrql
;
961 KiDispatchThreadNoLock(Ready
);
962 KeLowerIrql(OldIrql
);
971 KeSetIdealProcessorThread(IN PKTHREAD Thread
,
974 CCHAR PreviousIdealProcessor
;
977 /* Lock the Dispatcher Database */
978 OldIrql
= KeAcquireDispatcherDatabaseLock();
980 /* Save Old Ideal Processor */
981 PreviousIdealProcessor
= Thread
->IdealProcessor
;
983 /* Set New Ideal Processor */
984 Thread
->IdealProcessor
= Processor
;
987 KeReleaseDispatcherDatabaseLock(OldIrql
);
989 /* Return Old Ideal Processor */
990 return PreviousIdealProcessor
;
998 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
1000 PKTHREAD CurrentThread
= KeGetCurrentThread();
1003 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
1005 /* Lock the Dispatcher Database */
1006 OldIrql
= KeAcquireDispatcherDatabaseLock();
1008 /* Set the System Affinity Specified */
1009 CurrentThread
->Affinity
= Affinity
;
1011 /* Enable System Affinity */
1012 CurrentThread
->SystemAffinityActive
= TRUE
;
1014 /* Check if we need to Dispatch a New thread */
1015 if (Affinity
& (1 << KeGetCurrentProcessorNumber())) {
1017 /* No, just release */
1018 KeReleaseDispatcherDatabaseLock(OldIrql
);
1022 /* We need to dispatch a new thread */
1023 CurrentThread
->WaitIrql
= OldIrql
;
1024 KiDispatchThreadNoLock(Ready
);
1025 KeLowerIrql(OldIrql
);
1031 KeQueryBasePriorityThread(IN PKTHREAD Thread
)
1033 LONG BasePriorityIncrement
;
1037 /* Lock the Dispatcher Database */
1038 OldIrql
= KeAcquireDispatcherDatabaseLock();
1040 /* Get the Process */
1041 Process
= Thread
->ApcStatePointer
[0]->Process
;
1043 /* Calculate the BPI */
1044 BasePriorityIncrement
= Thread
->BasePriority
- Process
->BasePriority
;
1046 /* If saturation occured, return the SI instead */
1047 if (Thread
->Saturation
) BasePriorityIncrement
= (HIGH_PRIORITY
+ 1) / 2 *
1051 KeReleaseDispatcherDatabaseLock(OldIrql
);
1053 /* Return Increment */
1054 return BasePriorityIncrement
;
1061 KeSetBasePriorityThread (PKTHREAD Thread
,
1064 * Sets thread's base priority relative to the process' base priority
1065 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
1073 else if (Increment
> 2)
1077 Priority
= ((PETHREAD
)Thread
)->ThreadsProcess
->Pcb
.BasePriority
+ Increment
;
1078 if (Priority
< LOW_PRIORITY
)
1080 Priority
= LOW_PRIORITY
;
1082 else if (Priority
>= MAXIMUM_PRIORITY
)
1084 Thread
->BasePriority
= HIGH_PRIORITY
;
1086 KeSetPriorityThread(Thread
, Priority
);
1095 KeSetPriorityThread(PKTHREAD Thread
,
1098 KPRIORITY OldPriority
;
1100 PKTHREAD CurrentThread
;
1105 if (Priority
< LOW_PRIORITY
|| Priority
>= MAXIMUM_PRIORITY
) {
1110 OldIrql
= KeAcquireDispatcherDatabaseLock();
1112 OldPriority
= Thread
->Priority
;
1114 if (OldPriority
!= Priority
) {
1116 CurrentThread
= KeGetCurrentThread();
1118 if (Thread
->State
== Ready
) {
1120 KiRemoveFromThreadList(Thread
);
1121 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1122 KiInsertIntoThreadList(Priority
, Thread
);
1124 if (CurrentThread
->Priority
< Priority
) {
1126 KiDispatchThreadNoLock(Ready
);
1127 KeLowerIrql(OldIrql
);
1128 return (OldPriority
);
1131 } else if (Thread
->State
== Running
) {
1133 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1135 if (Priority
< OldPriority
) {
1137 /* Check for threads with a higher priority */
1138 Mask
= ~((1 << (Priority
+ 1)) - 1);
1139 if (PriorityListMask
& Mask
) {
1141 if (Thread
== CurrentThread
) {
1143 KiDispatchThreadNoLock(Ready
);
1144 KeLowerIrql(OldIrql
);
1145 return (OldPriority
);
1149 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1151 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1153 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1155 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1156 KiRequestReschedule(i
);
1157 KeLowerIrql(OldIrql
);
1158 return (OldPriority
);
1166 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
1170 KeReleaseDispatcherDatabaseLock(OldIrql
);
1171 return(OldPriority
);
1177 * Sets thread's affinity
1181 KeSetAffinityThread(PKTHREAD Thread
,
1187 KAFFINITY ProcessorMask
;
1189 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread
, Affinity
);
1191 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
1193 OldIrql
= KeAcquireDispatcherDatabaseLock();
1195 Thread
->UserAffinity
= Affinity
;
1197 if (Thread
->SystemAffinityActive
== FALSE
) {
1199 Thread
->Affinity
= Affinity
;
1201 if (Thread
->State
== Running
) {
1203 ProcessorMask
= 1 << KeGetCurrentKPCR()->Number
;
1204 if (Thread
== KeGetCurrentThread()) {
1206 if (!(Affinity
& ProcessorMask
)) {
1208 KiDispatchThreadNoLock(Ready
);
1209 KeLowerIrql(OldIrql
);
1210 return STATUS_SUCCESS
;
1215 for (i
= 0; i
< KeNumberProcessors
; i
++) {
1217 Pcr
= (PKPCR
)(KPCR_BASE
+ i
* PAGE_SIZE
);
1218 if (Pcr
->Prcb
->CurrentThread
== Thread
) {
1220 if (!(Affinity
& ProcessorMask
)) {
1222 KeReleaseDispatcherDatabaseLockFromDpcLevel();
1223 KiRequestReschedule(i
);
1224 KeLowerIrql(OldIrql
);
1225 return STATUS_SUCCESS
;
1232 ASSERT (i
< KeNumberProcessors
);
1237 KeReleaseDispatcherDatabaseLock(OldIrql
);
1238 return STATUS_SUCCESS
;
1244 /* The Increment Argument seems to be ignored by NT and always 0 when called */
1247 KeTerminateThread(IN KPRIORITY Increment
)
1250 PKTHREAD Thread
= KeGetCurrentThread();
1252 /* Lock the Dispatcher Database and the APC Queue */
1253 DPRINT("Terminating\n");
1254 OldIrql
= KeAcquireDispatcherDatabaseLock();
1256 /* Remove the thread from the list */
1257 RemoveEntryList(&Thread
->ThreadListEntry
);
1259 /* Insert into the Reaper List */
1260 DPRINT("List: %p\n", PspReaperList
);
1261 ((PETHREAD
)Thread
)->ReaperLink
= PspReaperList
;
1262 PspReaperList
= (PETHREAD
)Thread
;
1263 DPRINT("List: %p\n", PspReaperList
);
1265 /* Check if it's active */
1266 if (PspReaping
== FALSE
) {
1268 /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */
1270 DPRINT("Terminating\n");
1271 KiInsertQueue(&ExWorkerQueue
[HyperCriticalWorkQueue
].WorkerQueue
,
1272 &PspReaperWorkItem
.List
,
1276 /* Handle Kernel Queues */
1277 if (Thread
->Queue
) {
1279 DPRINT("Waking Queue\n");
1280 RemoveEntryList(&Thread
->QueueListEntry
);
1281 KiWakeQueue(Thread
->Queue
);
1284 /* Signal the thread */
1285 Thread
->DispatcherHeader
.SignalState
= TRUE
;
1286 if (IsListEmpty(&Thread
->DispatcherHeader
.WaitListHead
) != TRUE
) {
1289 KiWaitTest((PVOID
)Thread
, Increment
);
1292 /* Find a new Thread */
1293 KiDispatchThreadNoLock(Terminated
);
1297 * FUNCTION: Tests whether there are any pending APCs for the current thread
1298 * and if so the APCs will be delivered on exit from kernel mode
1302 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode
)
1305 PKTHREAD Thread
= KeGetCurrentThread();
1308 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1310 /* Lock the Dispatcher Database and the APC Queue */
1311 OldIrql
= KeAcquireDispatcherDatabaseLock();
1312 KiAcquireSpinLock(&Thread
->ApcQueueLock
);
1314 /* Save the old State */
1315 OldState
= Thread
->Alerted
[AlertMode
];
1317 /* If the Thread is Alerted, Clear it */
1320 Thread
->Alerted
[AlertMode
] = FALSE
;
1322 } else if ((AlertMode
== UserMode
) && (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
]))) {
1324 /* If the mode is User and the Queue isn't empty, set Pending */
1325 Thread
->ApcState
.UserApcPending
= TRUE
;
1328 /* Release Locks and return the Old State */
1329 KiReleaseSpinLock(&Thread
->ApcQueueLock
);
1330 KeReleaseDispatcherDatabaseLock(OldIrql
);
1335 KiServiceCheck (VOID
)
1337 PKTHREAD Thread
= KeGetCurrentThread();
1339 /* Check if we need to inialize Win32 for this Thread */
1340 if (Thread
->ServiceTable
!= KeServiceDescriptorTableShadow
) {
1342 /* We do. Initialize it and save the new table */
1343 PsInitWin32Thread((PETHREAD
)Thread
);
1344 Thread
->ServiceTable
= KeServiceDescriptorTableShadow
;
1354 NtAlertResumeThread(IN HANDLE ThreadHandle
,
1355 OUT PULONG SuspendCount
)
1357 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1360 ULONG PreviousState
;
1362 /* Check if parameters are valid */
1363 if(PreviousMode
!= KernelMode
) {
1367 ProbeForWrite(SuspendCount
,
1373 Status
= _SEH_GetExceptionCode();
1378 /* Reference the Object */
1379 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1380 THREAD_SUSPEND_RESUME
,
1386 /* Check for Success */
1387 if (NT_SUCCESS(Status
)) {
1389 /* Call the Kernel Function */
1390 PreviousState
= KeAlertResumeThread(&Thread
->Tcb
);
1392 /* Dereference Object */
1393 ObDereferenceObject(Thread
);
1399 *SuspendCount
= PreviousState
;
1403 Status
= _SEH_GetExceptionCode();
1420 NtAlertThread (IN HANDLE ThreadHandle
)
1422 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1426 /* Reference the Object */
1427 Status
= ObReferenceObjectByHandle(ThreadHandle
,
1428 THREAD_SUSPEND_RESUME
,
1434 /* Check for Success */
1435 if (NT_SUCCESS(Status
)) {
1438 * Do an alert depending on the processor mode. If some kmode code wants to
1439 * enforce a umode alert it should call KeAlertThread() directly. If kmode
1440 * code wants to do a kmode alert it's sufficient to call it with Zw or just
1441 * use KeAlertThread() directly
1443 KeAlertThread(&Thread
->Tcb
, PreviousMode
);
1445 /* Dereference Object */
1446 ObDereferenceObject(Thread
);
1455 NtDelayExecution(IN BOOLEAN Alertable
,
1456 IN PLARGE_INTEGER DelayInterval
)
1458 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
1459 LARGE_INTEGER SafeInterval
;
1462 /* Check if parameters are valid */
1463 if(PreviousMode
!= KernelMode
) {
1467 ProbeForRead(DelayInterval
,
1468 sizeof(LARGE_INTEGER
),
1471 /* make a copy on the kernel stack and let DelayInterval point to it so
1472 we don't need to wrap KeDelayExecutionThread in SEH! */
1473 SafeInterval
= *DelayInterval
;
1477 Status
= _SEH_GetExceptionCode();
1481 /* Call the Kernel Function */
1482 Status
= KeDelayExecutionThread(PreviousMode
,