2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/thrdobj.c
5 * PURPOSE: Implements routines to manage the Kernel Thread Object
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
13 #include <internal/debug.h>
15 extern EX_WORK_QUEUE ExWorkerQueue
[MaximumWorkQueue
];
16 extern LIST_ENTRY PspReaperListHead
;
18 ULONG KiMask32Array
[MAXIMUM_PRIORITY
] =
20 0x1, 0x2, 0x4, 0x8, 0x10, 0x20,
21 0x40, 0x80, 0x100, 0x200, 0x4000, 0x800,
22 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000,
23 0x40000, 0x80000, 0x100000, 0x200000, 0x400000, 0x800000,
24 0x1000000, 0x2000000, 0x4000000, 0x8000000, 0x10000000, 0x20000000,
25 0x40000000, 0x80000000
28 /* FUNCTIONS *****************************************************************/
32 KeFindNextRightSetAffinity(IN UCHAR Number
,
38 /* Calculate the mask */
39 Bit
= (AFFINITY_MASK(Number
) - 1) & Set
;
41 /* If it's 0, use the one we got */
44 /* Now find the right set and return it */
45 BitScanReverse(&Result
, Bit
);
50 #ifdef KeGetCurrentThread
51 #undef KeGetCurrentThread
58 KeGetCurrentThread(VOID
)
63 Ke386SaveFlags(Flags
);
64 Ke386DisableInterrupts();
65 Thread
= KeGetCurrentPrcb()->CurrentThread
;
66 Ke386RestoreFlags(Flags
);
69 return(KeGetCurrentPrcb()->CurrentThread
);
75 KeSetPreviousMode(ULONG Mode
)
77 PsGetCurrentThread()->Tcb
.PreviousMode
= (UCHAR
)Mode
;
85 KeGetPreviousMode(VOID
)
87 return (ULONG
)PsGetCurrentThread()->Tcb
.PreviousMode
;
92 KeDisableThreadApcQueueing(IN PKTHREAD Thread
)
95 BOOLEAN PreviousState
;
97 /* Lock the Dispatcher Database */
98 OldIrql
= KeAcquireDispatcherDatabaseLock();
101 PreviousState
= Thread
->ApcQueueable
;
104 Thread
->ApcQueueable
= FALSE
;
106 /* Release the Lock */
107 KeReleaseDispatcherDatabaseLock(OldIrql
);
109 /* Return old state */
110 return PreviousState
;
115 KeRundownThread(VOID
)
118 PKTHREAD Thread
= KeGetCurrentThread();
119 PLIST_ENTRY NextEntry
, ListHead
;
121 DPRINT("KeRundownThread: %x\n", Thread
);
123 /* Optimized path if nothing is on the list at the moment */
124 if (IsListEmpty(&Thread
->MutantListHead
)) return;
126 /* Lock the Dispatcher Database */
127 OldIrql
= KeAcquireDispatcherDatabaseLock();
129 /* Get the List Pointers */
130 ListHead
= &Thread
->MutantListHead
;
131 NextEntry
= ListHead
->Flink
;
132 while (NextEntry
!= ListHead
)
135 Mutant
= CONTAINING_RECORD(NextEntry
, KMUTANT
, MutantListEntry
);
136 DPRINT1("Mutant: %p. Type, Size %x %x\n",
139 Mutant
->Header
.Size
);
141 /* Make sure it's not terminating with APCs off */
142 if (Mutant
->ApcDisable
)
144 /* Bugcheck the system */
145 KEBUGCHECKEX(0,//THREAD_TERMINATE_HELD_MUTEX,
152 /* Now we can remove it */
153 RemoveEntryList(&Mutant
->MutantListEntry
);
155 /* Unconditionally abandon it */
156 DPRINT("Abandonning the Mutant\n");
157 Mutant
->Header
.SignalState
= 1;
158 Mutant
->Abandoned
= TRUE
;
159 Mutant
->OwnerThread
= NULL
;
161 /* Check if the Wait List isn't empty */
162 DPRINT("Checking whether to wake the Mutant\n");
163 if (!IsListEmpty(&Mutant
->Header
.WaitListHead
))
165 /* Wake the Mutant */
166 DPRINT("Waking the Mutant\n");
167 KiWaitTest(&Mutant
->Header
, MUTANT_INCREMENT
);
171 NextEntry
= NextEntry
->Flink
;
174 /* Release the Lock */
175 KeReleaseDispatcherDatabaseLock(OldIrql
);
179 * Used by the debugging code to freeze all the process's threads
180 * while the debugger is examining their state.
184 KeFreezeAllThreads(IN PKPROCESS Process
)
186 KLOCK_QUEUE_HANDLE LockHandle
, ApcLock
;
187 PKTHREAD Current
, CurrentThread
= KeGetCurrentThread();
188 PLIST_ENTRY ListHead
, NextEntry
;
190 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
192 /* Lock the process */
193 KiAcquireProcessLock(Process
, &LockHandle
);
195 /* If someone is already trying to free us, try again */
196 while (CurrentThread
->FreezeCount
)
198 /* Release and re-acquire the process lock so the APC will go through */
199 KiReleaseProcessLock(&LockHandle
);
200 KiAcquireProcessLock(Process
, &LockHandle
);
203 /* Enter a critical region */
204 KeEnterCriticalRegion();
206 /* Loop the Process's Threads */
207 ListHead
= &Process
->ThreadListHead
;
208 NextEntry
= ListHead
->Flink
;
209 while (NextEntry
!= ListHead
)
211 /* Get the current thread */
212 Current
= CONTAINING_RECORD(NextEntry
, KTHREAD
, ThreadListEntry
);
215 KiAcquireApcLockAtDpcLevel(Current
, &ApcLock
);
217 /* Make sure it's not ours, and check if APCs are enabled */
218 if ((Current
!= CurrentThread
) && (Current
->ApcQueueable
))
221 OldCount
= Current
->SuspendCount
;
222 ASSERT(OldCount
!= MAXIMUM_SUSPEND_COUNT
);
224 /* Increase the freeze count */
225 Current
->FreezeCount
++;
227 /* Make sure it wasn't already suspended */
228 if (!(OldCount
) && !(Current
->SuspendCount
))
230 /* Did we already insert it? */
231 if (!Current
->SuspendApc
.Inserted
)
234 Current
->SuspendApc
.Inserted
= TRUE
;
235 KiInsertQueueApc(&Current
->SuspendApc
, IO_NO_INCREMENT
);
239 /* Lock the dispatcher */
240 KiAcquireDispatcherLockAtDpcLevel();
242 /* Unsignal the semaphore, the APC was already inserted */
243 Current
->SuspendSemaphore
.Header
.SignalState
--;
245 /* Release the dispatcher */
246 KiReleaseDispatcherLockFromDpcLevel();
251 /* Release the APC lock */
252 KiReleaseApcLockFromDpcLevel(&ApcLock
);
255 /* Release the process lock and exit the dispatcher */
256 KiReleaseProcessLock(&LockHandle
);
257 KiExitDispatcher(LockHandle
.OldIrql
);
262 KeResumeThread(IN PKTHREAD Thread
)
264 KLOCK_QUEUE_HANDLE ApcLock
;
266 ASSERT_THREAD(Thread
);
267 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
269 /* Lock the APC Queue */
270 KiAcquireApcLock(Thread
, &ApcLock
);
272 /* Save the Old Count */
273 PreviousCount
= Thread
->SuspendCount
;
275 /* Check if it existed */
278 /* Decrease the suspend count */
279 Thread
->SuspendCount
--;
281 /* Check if the thrad is still suspended or not */
282 if ((!Thread
->SuspendCount
) && (!Thread
->FreezeCount
))
284 /* Acquire the dispatcher lock */
285 KiAcquireDispatcherLockAtDpcLevel();
287 /* Signal the Suspend Semaphore */
288 Thread
->SuspendSemaphore
.Header
.SignalState
++;
289 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
291 /* Release the dispatcher lock */
292 KiReleaseDispatcherLockFromDpcLevel();
296 /* Release APC Queue lock and return the Old State */
297 KiReleaseApcLockFromDpcLevel(&ApcLock
);
298 KiExitDispatcher(ApcLock
.OldIrql
);
299 return PreviousCount
;
304 KiSuspendRundown(IN PKAPC Apc
)
307 UNREFERENCED_PARAMETER(Apc
);
312 KiSuspendNop(IN PKAPC Apc
,
313 IN PKNORMAL_ROUTINE
*NormalRoutine
,
314 IN PVOID
*NormalContext
,
315 IN PVOID
*SystemArgument1
,
316 IN PVOID
*SystemArgument2
)
319 UNREFERENCED_PARAMETER(Apc
);
320 UNREFERENCED_PARAMETER(NormalRoutine
);
321 UNREFERENCED_PARAMETER(NormalContext
);
322 UNREFERENCED_PARAMETER(SystemArgument1
);
323 UNREFERENCED_PARAMETER(SystemArgument2
);
328 KiSuspendThread(IN PVOID NormalContext
,
329 IN PVOID SystemArgument1
,
330 IN PVOID SystemArgument2
)
332 /* Non-alertable kernel-mode suspended wait */
333 KeWaitForSingleObject(&KeGetCurrentThread()->SuspendSemaphore
,
342 KeSuspendThread(PKTHREAD Thread
)
344 KLOCK_QUEUE_HANDLE ApcLock
;
346 ASSERT_THREAD(Thread
);
347 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
349 /* Lock the APC Queue */
350 KiAcquireApcLock(Thread
, &ApcLock
);
352 /* Save the Old Count */
353 PreviousCount
= Thread
->SuspendCount
;
355 /* Handle the maximum */
356 if (PreviousCount
== MAXIMUM_SUSPEND_COUNT
)
358 /* Raise an exception */
359 KiReleaseApcLock(&ApcLock
);
360 RtlRaiseStatus(STATUS_SUSPEND_COUNT_EXCEEDED
);
363 /* Should we bother to queue at all? */
364 if (Thread
->ApcQueueable
)
366 /* Increment the suspend count */
367 Thread
->SuspendCount
++;
369 /* Check if we should suspend it */
370 if (!(PreviousCount
) && !(Thread
->FreezeCount
))
372 /* Is the APC already inserted? */
373 if (!Thread
->SuspendApc
.Inserted
)
375 /* Not inserted, insert it */
376 Thread
->SuspendApc
.Inserted
= TRUE
;
377 KiInsertQueueApc(&Thread
->SuspendApc
, IO_NO_INCREMENT
);
381 /* Lock the dispatcher */
382 KiAcquireDispatcherLockAtDpcLevel();
384 /* Unsignal the semaphore, the APC was already inserted */
385 Thread
->SuspendSemaphore
.Header
.SignalState
--;
387 /* Release the dispatcher */
388 KiReleaseDispatcherLockFromDpcLevel();
393 /* Release Lock and return the Old State */
394 KiReleaseApcLockFromDpcLevel(&ApcLock
);
395 KiExitDispatcher(ApcLock
.OldIrql
);
396 return PreviousCount
;
401 KeForceResumeThread(IN PKTHREAD Thread
)
403 KLOCK_QUEUE_HANDLE ApcLock
;
405 ASSERT_THREAD(Thread
);
406 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
408 /* Lock the APC Queue */
409 KiAcquireApcLock(Thread
, &ApcLock
);
411 /* Save the old Suspend Count */
412 PreviousCount
= Thread
->SuspendCount
+ Thread
->FreezeCount
;
414 /* If the thread is suspended, wake it up!!! */
417 /* Unwait it completely */
418 Thread
->SuspendCount
= 0;
419 Thread
->FreezeCount
= 0;
421 /* Lock the dispatcher */
422 KiAcquireDispatcherLockAtDpcLevel();
424 /* Signal and satisfy */
425 Thread
->SuspendSemaphore
.Header
.SignalState
++;
426 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
428 /* Release the dispatcher */
429 KiReleaseDispatcherLockFromDpcLevel();
432 /* Release Lock and return the Old State */
433 KiReleaseApcLockFromDpcLevel(&ApcLock
);
434 KiExitDispatcher(ApcLock
.OldIrql
);
435 return PreviousCount
;
440 KeAlertResumeThread(IN PKTHREAD Thread
)
443 KLOCK_QUEUE_HANDLE ApcLock
;
444 ASSERT_THREAD(Thread
);
445 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
447 /* Lock the Dispatcher Database and the APC Queue */
448 KiAcquireApcLock(Thread
, &ApcLock
);
449 KiAcquireDispatcherLockAtDpcLevel();
451 /* Return if Thread is already alerted. */
452 if (!Thread
->Alerted
[KernelMode
])
454 /* If it's Blocked, unblock if it we should */
455 if ((Thread
->State
== Waiting
) && (Thread
->Alertable
))
458 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
462 /* If not, simply Alert it */
463 Thread
->Alerted
[KernelMode
] = TRUE
;
467 /* Save the old Suspend Count */
468 PreviousCount
= Thread
->SuspendCount
;
470 /* If the thread is suspended, decrease one of the suspend counts */
473 /* Decrease count. If we are now zero, unwait it completely */
474 if (--Thread
->SuspendCount
)
476 /* Signal and satisfy */
477 Thread
->SuspendSemaphore
.Header
.SignalState
++;
478 KiWaitTest(&Thread
->SuspendSemaphore
.Header
, IO_NO_INCREMENT
);
482 /* Release Locks and return the Old State */
483 KiReleaseDispatcherLockFromDpcLevel();
484 KiReleaseApcLockFromDpcLevel(&ApcLock
);
485 KiExitDispatcher(ApcLock
.OldIrql
);
486 return PreviousCount
;
491 KeAlertThread(IN PKTHREAD Thread
,
492 IN KPROCESSOR_MODE AlertMode
)
494 BOOLEAN PreviousState
;
495 KLOCK_QUEUE_HANDLE ApcLock
;
496 ASSERT_THREAD(Thread
);
497 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
499 /* Lock the Dispatcher Database and the APC Queue */
500 KiAcquireApcLock(Thread
, &ApcLock
);
501 KiAcquireDispatcherLockAtDpcLevel();
503 /* Save the Previous State */
504 PreviousState
= Thread
->Alerted
[AlertMode
];
506 /* Check if it's already alerted */
509 /* Check if the thread is alertable, and blocked in the given mode */
510 if ((Thread
->State
== Waiting
) &&
511 ((AlertMode
== KernelMode
) || (Thread
->WaitMode
== AlertMode
)) &&
514 /* Abort the wait to alert the thread */
515 KiAbortWaitThread(Thread
, STATUS_ALERTED
, THREAD_ALERT_INCREMENT
);
519 /* Otherwise, merely set the alerted state */
520 Thread
->Alerted
[AlertMode
] = TRUE
;
524 /* Release the Dispatcher Lock */
525 KiReleaseDispatcherLockFromDpcLevel();
526 KiReleaseApcLockFromDpcLevel(&ApcLock
);
527 KiExitDispatcher(ApcLock
.OldIrql
);
529 /* Return the old state */
530 return PreviousState
;
535 KeTestAlertThread(IN KPROCESSOR_MODE AlertMode
)
537 PKTHREAD Thread
= KeGetCurrentThread();
539 KLOCK_QUEUE_HANDLE ApcLock
;
540 ASSERT_THREAD(Thread
);
541 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
543 /* Lock the Dispatcher Database and the APC Queue */
544 KiAcquireApcLock(Thread
, &ApcLock
);
545 KiAcquireDispatcherLockAtDpcLevel();
547 /* Save the old State */
548 OldState
= Thread
->Alerted
[AlertMode
];
550 /* Check the Thread is alerted */
553 /* Disable alert for this mode */
554 Thread
->Alerted
[AlertMode
] = FALSE
;
556 else if ((AlertMode
!= KernelMode
) &&
557 (!IsListEmpty(&Thread
->ApcState
.ApcListHead
[UserMode
])))
559 /* If the mode is User and the Queue isn't empty, set Pending */
560 Thread
->ApcState
.UserApcPending
= TRUE
;
563 /* Release Locks and return the Old State */
564 KiReleaseDispatcherLockFromDpcLevel();
565 KiReleaseApcLockFromDpcLevel(&ApcLock
);
566 KiExitDispatcher(ApcLock
.OldIrql
);
575 KeCapturePersistentThreadState(IN PVOID CurrentThread
,
581 IN PVOID ThreadState
)
588 KeUninitThread(IN PKTHREAD Thread
)
590 /* Delete the stack */
591 MmDeleteKernelStack(Thread
->StackBase
, FALSE
);
592 Thread
->InitialStack
= NULL
;
597 KeInitThread(IN OUT PKTHREAD Thread
,
598 IN PVOID KernelStack
,
599 IN PKSYSTEM_ROUTINE SystemRoutine
,
600 IN PKSTART_ROUTINE StartRoutine
,
601 IN PVOID StartContext
,
604 IN PKPROCESS Process
)
606 BOOLEAN AllocatedStack
= FALSE
;
608 PKWAIT_BLOCK TimerWaitBlock
;
612 /* Initalize the Dispatcher Header */
613 KeInitializeDispatcherHeader(&Thread
->DispatcherHeader
,
615 sizeof(KTHREAD
) / sizeof(LONG
),
618 /* Initialize the Mutant List */
619 InitializeListHead(&Thread
->MutantListHead
);
621 /* Initialize the wait blocks */
622 for (i
= 0; i
< (THREAD_WAIT_OBJECTS
+ 1); i
++)
624 /* Put our pointer */
625 Thread
->WaitBlock
[i
].Thread
= Thread
;
628 /* Set swap settings */
629 Thread
->EnableStackSwap
= FALSE
;//TRUE;
630 Thread
->IdealProcessor
= 1;
631 Thread
->SwapBusy
= FALSE
;
632 Thread
->AdjustReason
= 0;
634 /* Initialize the lock */
635 KeInitializeSpinLock(&Thread
->ThreadLock
);
637 /* Setup the Service Descriptor Table for Native Calls */
638 Thread
->ServiceTable
= KeServiceDescriptorTable
;
640 /* Setup APC Fields */
641 InitializeListHead(&Thread
->ApcState
.ApcListHead
[0]);
642 InitializeListHead(&Thread
->ApcState
.ApcListHead
[1]);
643 Thread
->ApcState
.Process
= Process
;
644 Thread
->ApcStatePointer
[OriginalApcEnvironment
] = &Thread
->ApcState
;
645 Thread
->ApcStatePointer
[AttachedApcEnvironment
] = &Thread
->SavedApcState
;
646 Thread
->ApcStateIndex
= OriginalApcEnvironment
;
647 Thread
->ApcQueueable
= TRUE
;
648 KeInitializeSpinLock(&Thread
->ApcQueueLock
);
650 /* Initialize the Suspend APC */
651 KeInitializeApc(&Thread
->SuspendApc
,
653 OriginalApcEnvironment
,
660 /* Initialize the Suspend Semaphore */
661 KeInitializeSemaphore(&Thread
->SuspendSemaphore
, 0, 2);
663 /* Setup the timer */
664 Timer
= &Thread
->Timer
;
665 KeInitializeTimer(Timer
);
666 TimerWaitBlock
= &Thread
->WaitBlock
[TIMER_WAIT_BLOCK
];
667 TimerWaitBlock
->Object
= Timer
;
668 TimerWaitBlock
->WaitKey
= STATUS_TIMEOUT
;
669 TimerWaitBlock
->WaitType
= WaitAny
;
670 TimerWaitBlock
->NextWaitBlock
= NULL
;
672 /* Link the two wait lists together */
673 TimerWaitBlock
->WaitListEntry
.Flink
= &Timer
->Header
.WaitListHead
;
674 TimerWaitBlock
->WaitListEntry
.Blink
= &Timer
->Header
.WaitListHead
;
679 /* Check if we have a kernel stack */
682 /* We don't, allocate one */
683 KernelStack
= (PVOID
)((ULONG_PTR
)MmCreateKernelStack(FALSE
) +
685 if (!KernelStack
) return STATUS_INSUFFICIENT_RESOURCES
;
687 /* Remember for later */
688 AllocatedStack
= TRUE
;
691 /* Set the Thread Stacks */
692 Thread
->InitialStack
= (PCHAR
)KernelStack
;
693 Thread
->StackBase
= (PCHAR
)KernelStack
;
694 Thread
->StackLimit
= (ULONG_PTR
)KernelStack
- KERNEL_STACK_SIZE
;
695 Thread
->KernelStackResident
= TRUE
;
698 MmUpdatePageDir((PEPROCESS
)Process
,
699 (PVOID
)Thread
->StackLimit
,
701 MmUpdatePageDir((PEPROCESS
)Process
, (PVOID
)Thread
, sizeof(ETHREAD
));
703 /* Enter SEH to avoid crashes due to user mode */
704 Status
= STATUS_SUCCESS
;
707 /* Initalize the Thread Context */
708 Ke386InitThreadWithContext(Thread
,
716 /* Set failure status */
717 Status
= STATUS_UNSUCCESSFUL
;
719 /* Check if a stack was allocated */
722 /* Delete the stack */
723 MmDeleteKernelStack(Thread
->StackBase
, FALSE
);
724 Thread
->InitialStack
= NULL
;
729 /* Set the Thread to initalized */
730 Thread
->State
= Initialized
;
736 KeInitializeThread(IN PKPROCESS Process
,
737 IN OUT PKTHREAD Thread
,
738 IN PKSYSTEM_ROUTINE SystemRoutine
,
739 IN PKSTART_ROUTINE StartRoutine
,
740 IN PVOID StartContext
,
743 IN PVOID KernelStack
)
745 /* Initailize and start the thread on success */
746 if (NT_SUCCESS(KeInitThread(Thread
,
756 KeStartThread(Thread
);
762 KeStartThread(IN OUT PKTHREAD Thread
)
764 KLOCK_QUEUE_HANDLE LockHandle
;
770 UCHAR IdealProcessor
= 0;
771 PKPROCESS Process
= Thread
->ApcState
.Process
;
773 /* Setup static fields from parent */
774 Thread
->Iopl
= Process
->Iopl
;
775 Thread
->Quantum
= Process
->QuantumReset
;
776 Thread
->QuantumReset
= Process
->QuantumReset
;
777 Thread
->SystemAffinityActive
= FALSE
;
779 /* Lock the process */
780 KiAcquireProcessLock(Process
, &LockHandle
);
782 /* Setup volatile data */
783 Thread
->Priority
= Process
->BasePriority
;
784 Thread
->BasePriority
= Process
->BasePriority
;
785 Thread
->Affinity
= Process
->Affinity
;
786 Thread
->UserAffinity
= Process
->Affinity
;
789 /* Get the KNODE and its PRCB */
790 Node
= KeNodeBlock
[Process
->IdealNode
];
791 NodePrcb
= (PKPRCB
)(KPCR_BASE
+ (Process
->ThreadSeed
* PAGE_SIZE
));
793 /* Calculate affinity mask */
794 Set
= ~NodePrcb
->MultiThreadProcessorSet
;
795 Mask
= (ULONG
)(Node
->ProcessorMask
& Process
->Affinity
);
799 /* Get the new thread seed */
800 IdealProcessor
= KeFindNextRightSetAffinity(Process
->ThreadSeed
, Mask
);
801 Process
->ThreadSeed
= IdealProcessor
;
804 ASSERT((Thread
->UserAffinity
& AFFINITY_MASK(IdealProcessor
)));
807 /* Set the Ideal Processor */
808 Thread
->IdealProcessor
= IdealProcessor
;
809 Thread
->UserIdealProcessor
= IdealProcessor
;
811 /* Lock the Dispatcher Database */
812 KiAcquireDispatcherLockAtDpcLevel();
814 /* Insert the thread into the process list */
815 InsertTailList(&Process
->ThreadListHead
, &Thread
->ThreadListEntry
);
817 /* Increase the stack count */
818 ASSERT(Process
->StackCount
!= MAXULONG_PTR
);
819 Process
->StackCount
++;
821 /* Release locks and return */
822 KiReleaseDispatcherLockFromDpcLevel();
823 KiReleaseProcessLock(&LockHandle
);
831 KeQueryPriorityThread (IN PKTHREAD Thread
)
833 return Thread
->Priority
;
841 KeQueryRuntimeThread(IN PKTHREAD Thread
,
844 /* Return the User Time */
845 *UserTime
= Thread
->UserTime
;
847 /* Return the Kernel Time */
848 return Thread
->KernelTime
;
856 KeSetKernelStackSwapEnable(IN BOOLEAN Enable
)
858 PKTHREAD Thread
= KeGetCurrentThread();
859 BOOLEAN PreviousState
;
862 /* Lock the Dispatcher Database */
863 OldIrql
= KeAcquireDispatcherDatabaseLock();
866 PreviousState
= Thread
->EnableStackSwap
;
869 Thread
->EnableStackSwap
= Enable
;
871 /* No, Release Lock */
872 KeReleaseDispatcherDatabaseLock(OldIrql
);
874 /* Return Old State */
875 return PreviousState
;
883 KeRevertToUserAffinityThread(VOID
)
885 PKTHREAD CurrentThread
= KeGetCurrentThread();
888 ASSERT(CurrentThread
->SystemAffinityActive
!= FALSE
);
890 /* Lock the Dispatcher Database */
891 OldIrql
= KeAcquireDispatcherDatabaseLock();
893 /* Return to User Affinity */
894 CurrentThread
->Affinity
= CurrentThread
->UserAffinity
;
896 /* Disable System Affinity */
897 CurrentThread
->SystemAffinityActive
= FALSE
;
899 /* Check if we need to Dispatch a New thread */
900 if (CurrentThread
->Affinity
& (1 << KeGetCurrentProcessorNumber())) {
902 /* No, just release */
903 KeReleaseDispatcherDatabaseLock(OldIrql
);
907 /* We need to dispatch a new thread */
908 CurrentThread
->WaitIrql
= OldIrql
;
909 KiDispatchThreadNoLock(Ready
);
910 KeLowerIrql(OldIrql
);
919 KeSetIdealProcessorThread(IN PKTHREAD Thread
,
922 CCHAR PreviousIdealProcessor
;
925 /* Lock the Dispatcher Database */
926 OldIrql
= KeAcquireDispatcherDatabaseLock();
928 /* Save Old Ideal Processor */
929 PreviousIdealProcessor
= Thread
->IdealProcessor
;
931 /* Set New Ideal Processor */
932 Thread
->IdealProcessor
= Processor
;
935 KeReleaseDispatcherDatabaseLock(OldIrql
);
937 /* Return Old Ideal Processor */
938 return PreviousIdealProcessor
;
946 KeSetSystemAffinityThread(IN KAFFINITY Affinity
)
948 PKTHREAD CurrentThread
= KeGetCurrentThread();
951 ASSERT(Affinity
& ((1 << KeNumberProcessors
) - 1));
953 /* Lock the Dispatcher Database */
954 OldIrql
= KeAcquireDispatcherDatabaseLock();
956 /* Set the System Affinity Specified */
957 CurrentThread
->Affinity
= Affinity
;
959 /* Enable System Affinity */
960 CurrentThread
->SystemAffinityActive
= TRUE
;
962 /* Check if we need to Dispatch a New thread */
963 if (Affinity
& (1 << KeGetCurrentProcessorNumber())) {
965 /* No, just release */
966 KeReleaseDispatcherDatabaseLock(OldIrql
);
970 /* We need to dispatch a new thread */
971 CurrentThread
->WaitIrql
= OldIrql
;
972 KiDispatchThreadNoLock(Ready
);
973 KeLowerIrql(OldIrql
);
979 KeQueryBasePriorityThread(IN PKTHREAD Thread
)
981 LONG BasePriorityIncrement
;
985 /* Lock the Dispatcher Database */
986 OldIrql
= KeAcquireDispatcherDatabaseLock();
988 /* Get the Process */
989 Process
= Thread
->ApcStatePointer
[0]->Process
;
991 /* Calculate the BPI */
992 BasePriorityIncrement
= Thread
->BasePriority
- Process
->BasePriority
;
994 /* If saturation occured, return the SI instead */
995 if (Thread
->Saturation
) BasePriorityIncrement
= (HIGH_PRIORITY
+ 1) / 2 *
999 KeReleaseDispatcherDatabaseLock(OldIrql
);
1001 /* Return Increment */
1002 return BasePriorityIncrement
;
1010 KeSetBasePriorityThread(PKTHREAD Thread
,
1016 KPRIORITY CurrentBasePriority
;
1017 KPRIORITY BasePriority
;
1018 BOOLEAN Released
= FALSE
;
1019 LONG CurrentIncrement
;
1021 /* Lock the Dispatcher Database */
1022 OldIrql
= KeAcquireDispatcherDatabaseLock();
1024 /* Get the process and calculate current BP and BPI */
1025 Process
= Thread
->ApcStatePointer
[0]->Process
;
1026 CurrentBasePriority
= Thread
->BasePriority
;
1027 CurrentIncrement
= CurrentBasePriority
- Process
->BasePriority
;
1029 /* Change to use the SI if Saturation was used */
1030 if (Thread
->Saturation
) CurrentIncrement
= (HIGH_PRIORITY
+ 1) / 2 *
1033 /* Now check if saturation is being used for the new value */
1034 if (abs(Increment
) >= ((HIGH_PRIORITY
+ 1) / 2))
1036 /* Check if we need positive or negative saturation */
1037 Thread
->Saturation
= (Increment
> 0) ? 1 : -1;
1040 /* Normalize the Base Priority */
1041 BasePriority
= Process
->BasePriority
+ Increment
;
1042 if (Process
->BasePriority
>= LOW_REALTIME_PRIORITY
)
1044 /* Check if it's too low */
1045 if (BasePriority
< LOW_REALTIME_PRIORITY
)
1046 BasePriority
= LOW_REALTIME_PRIORITY
;
1048 /* Check if it's too high */
1049 if (BasePriority
> HIGH_PRIORITY
) BasePriority
= HIGH_PRIORITY
;
1051 /* We are at RTP, so use the raw BP */
1052 Priority
= BasePriority
;
1056 /* Check if it's entering RTP */
1057 if (BasePriority
>= LOW_REALTIME_PRIORITY
)
1058 BasePriority
= LOW_REALTIME_PRIORITY
- 1;
1060 /* Check if it's too low */
1061 if (BasePriority
<= LOW_PRIORITY
)
1064 /* If Saturation is used, then use the raw BP */
1065 if (Thread
->Saturation
)
1067 Priority
= BasePriority
;
1071 /* Calculate the new priority */
1072 Priority
= Thread
->Priority
+ (BasePriority
- CurrentBasePriority
)-
1073 Thread
->PriorityDecrement
;
1075 /* Make sure it won't enter RTP ranges */
1076 if (Priority
>= LOW_REALTIME_PRIORITY
)
1077 Priority
= LOW_REALTIME_PRIORITY
- 1;
1081 /* Finally set the new base priority */
1082 Thread
->BasePriority
= BasePriority
;
1084 /* Reset the decrements */
1085 Thread
->PriorityDecrement
= 0;
1087 /* If the priority will change, reset quantum and change it for real */
1088 if (Priority
!= Thread
->Priority
)
1090 Thread
->Quantum
= Thread
->QuantumReset
;
1091 KiSetPriorityThread(Thread
, Priority
, &Released
);
1094 /* Release Lock if needed */
1097 KeReleaseDispatcherDatabaseLock(OldIrql
);
1101 KeLowerIrql(OldIrql
);
1104 /* Return the Old Increment */
1105 return CurrentIncrement
;
1113 KeSetPriorityThread(PKTHREAD Thread
,
1116 KPRIORITY OldPriority
;
1117 BOOLEAN Released
= FALSE
;
1120 /* Lock the Dispatcher Database */
1121 OldIrql
= KeAcquireDispatcherDatabaseLock();
1123 /* Save the old Priority */
1124 OldPriority
= Thread
->Priority
;
1126 /* Reset the Quantum and Decrements */
1127 Thread
->Quantum
= Thread
->QuantumReset
;
1128 Thread
->PriorityDecrement
= 0;
1130 /* Set the new Priority */
1131 KiSetPriorityThread(Thread
, Priority
, &Released
);
1133 /* Release Lock if needed */
1136 KeReleaseDispatcherDatabaseLock(OldIrql
);
1140 KeLowerIrql(OldIrql
);
1143 /* Return Old Priority */
1150 * Sets thread's affinity
1154 KeSetAffinityThread(PKTHREAD Thread
,
1158 KAFFINITY OldAffinity
;
1161 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread
, Affinity
);
1163 OldIrql
= KeAcquireDispatcherDatabaseLock();
1165 /* Call the internal function */
1166 OldAffinity
= KiSetAffinityThread(Thread
, Affinity
, &Released
);
1168 /* Release Lock if needed */
1171 KeReleaseDispatcherDatabaseLock(OldIrql
);
1175 KeLowerIrql(OldIrql
);
1186 KeTerminateThread(IN KPRIORITY Increment
)
1188 PLIST_ENTRY
*ListHead
;
1189 PETHREAD Entry
, SavedEntry
;
1190 PETHREAD
*ThreadAddr
;
1191 KLOCK_QUEUE_HANDLE LockHandle
;
1192 PKTHREAD Thread
= KeGetCurrentThread();
1193 PKPROCESS Process
= Thread
->ApcState
.Process
;
1194 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1196 /* Lock the process */
1197 KiAcquireProcessLock(Process
, &LockHandle
);
1199 /* Make sure we won't get Swapped */
1200 KiSetThreadSwapBusy(Thread
);
1202 /* Save the Kernel and User Times */
1203 Process
->KernelTime
+= Thread
->KernelTime
;
1204 Process
->UserTime
+= Thread
->UserTime
;
1206 /* Get the current entry and our Port */
1207 Entry
= (PETHREAD
)PspReaperListHead
.Flink
;
1208 ThreadAddr
= &((PETHREAD
)Thread
)->ReaperLink
;
1210 /* Add it to the reaper's list */
1213 /* Get the list head */
1214 ListHead
= &PspReaperListHead
.Flink
;
1216 /* Link ourselves */
1217 *ThreadAddr
= Entry
;
1220 /* Now try to do the exchange */
1221 Entry
= InterlockedCompareExchangePointer(ListHead
, ThreadAddr
, Entry
);
1223 /* Break out if the change was succesful */
1224 } while (Entry
!= SavedEntry
);
1226 /* Acquire the dispatcher lock */
1227 KiAcquireDispatcherLockAtDpcLevel();
1229 /* Check if the reaper wasn't active */
1232 /* Activate it as a work item, directly through its Queue */
1233 KiInsertQueue(&ExWorkerQueue
[HyperCriticalWorkQueue
].WorkerQueue
,
1234 &PspReaperWorkItem
.List
,
1238 /* Check the thread has an associated queue */
1241 /* Remove it from the list, and handle the queue */
1242 RemoveEntryList(&Thread
->QueueListEntry
);
1243 KiWakeQueue(Thread
->Queue
);
1246 /* Signal the thread */
1247 Thread
->DispatcherHeader
.SignalState
= TRUE
;
1248 if (IsListEmpty(&Thread
->DispatcherHeader
.WaitListHead
) != TRUE
)
1251 KiWaitTest((PVOID
)Thread
, Increment
);
1254 /* Remove the thread from the list */
1255 RemoveEntryList(&Thread
->ThreadListEntry
);
1257 /* Release the process lock */
1258 KiReleaseProcessLock(&LockHandle
);
1260 /* Set us as terminated, decrease the Process's stack count */
1261 Thread
->State
= Terminated
;
1263 /* Decrease stack count */
1264 ASSERT(Process
->StackCount
!= 0);
1265 ASSERT(Process
->State
== ProcessInMemory
);
1266 Process
->StackCount
--;
1267 if (!Process
->StackCount
)
1269 /* FIXME: Swap stacks */
1272 /* Rundown arch-specific parts */
1273 KiRundownThread(Thread
);
1275 /* Swap to a new thread */
1276 KiReleaseDispatcherLockFromDpcLevel();
1277 KiSwapThread(Thread
, KeGetCurrentPrcb());