mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 19:42:57 +00:00
- Thread Support cleanup 1: Separate kthread.c into thrdobj.c (Exported and globally accesible functions dealing with the KTHREAD object) and thrdschd.c (Fully internal thread scheduling routines for Ke* only).
- Also fix KeSetAffinityThread to return the old affinity, instead of NTSTATUS and move NtYieldExecution from Ps to Ke, and move NtDelayExecution to wait.c - No code changes. svn path=/trunk/; revision=24024
This commit is contained in:
parent
f9b0ee1a03
commit
aafcd436d5
8 changed files with 1672 additions and 1630 deletions
|
@ -73,7 +73,7 @@ KeSetEventBoostPriority(
|
||||||
IN PKTHREAD *Thread OPTIONAL
|
IN PKTHREAD *Thread OPTIONAL
|
||||||
);
|
);
|
||||||
|
|
||||||
NTSTATUS
|
KAFFINITY
|
||||||
NTAPI
|
NTAPI
|
||||||
KeSetAffinityThread(
|
KeSetAffinityThread(
|
||||||
PKTHREAD Thread,
|
PKTHREAD Thread,
|
||||||
|
|
|
@ -126,7 +126,7 @@ extern LIST_ENTRY KiStackInSwapListHead;
|
||||||
extern KEVENT KiSwapEvent;
|
extern KEVENT KiSwapEvent;
|
||||||
extern PKPRCB KiProcessorBlock[];
|
extern PKPRCB KiProcessorBlock[];
|
||||||
extern ULONG KiMask32Array[MAXIMUM_PRIORITY];
|
extern ULONG KiMask32Array[MAXIMUM_PRIORITY];
|
||||||
extern ULONG IdleProcessorMask;
|
extern ULONG KiIdleSummary;
|
||||||
extern VOID KiTrap8(VOID);
|
extern VOID KiTrap8(VOID);
|
||||||
extern VOID KiTrap2(VOID);
|
extern VOID KiTrap2(VOID);
|
||||||
|
|
||||||
|
@ -242,7 +242,8 @@ KAFFINITY
|
||||||
NTAPI
|
NTAPI
|
||||||
KiSetAffinityThread(
|
KiSetAffinityThread(
|
||||||
IN PKTHREAD Thread,
|
IN PKTHREAD Thread,
|
||||||
IN KAFFINITY Affinity
|
IN KAFFINITY Affinity,
|
||||||
|
IN PBOOLEAN Released // hack
|
||||||
);
|
);
|
||||||
|
|
||||||
PKTHREAD
|
PKTHREAD
|
||||||
|
|
|
@ -337,7 +337,7 @@ KeInsertQueueDpc(IN PKDPC Dpc,
|
||||||
if (((Dpc->Importance == HighImportance) ||
|
if (((Dpc->Importance == HighImportance) ||
|
||||||
(DpcData->DpcQueueDepth >=
|
(DpcData->DpcQueueDepth >=
|
||||||
Prcb->MaximumDpcQueueDepth)) &&
|
Prcb->MaximumDpcQueueDepth)) &&
|
||||||
(!(AFFINITY_MASK(Cpu) & IdleProcessorMask) ||
|
(!(AFFINITY_MASK(Cpu) & KiIdleSummary) ||
|
||||||
(Prcb->Sleeping)))
|
(Prcb->Sleeping)))
|
||||||
{
|
{
|
||||||
/* Set interrupt requested */
|
/* Set interrupt requested */
|
||||||
|
|
|
@ -1,27 +1,18 @@
|
||||||
/*
|
/*
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* PROJECT: ReactOS Kernel
|
||||||
* PROJECT: ReactOS kernel
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* FILE: ntoskrnl/ke/kthread.c
|
* FILE: ntoskrnl/ke/thrdobj.c
|
||||||
* PURPOSE: Microkernel thread support
|
* PURPOSE: Implements routines to manage the Kernel Thread Object
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
||||||
* David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
|
extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue];
|
||||||
|
|
||||||
/*
|
|
||||||
* PURPOSE: List of threads associated with each priority level
|
|
||||||
*/
|
|
||||||
LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
|
|
||||||
static ULONG PriorityListMask = 0;
|
|
||||||
ULONG IdleProcessorMask = 0;
|
|
||||||
extern LIST_ENTRY PspReaperListHead;
|
extern LIST_ENTRY PspReaperListHead;
|
||||||
|
|
||||||
ULONG KiMask32Array[MAXIMUM_PRIORITY] =
|
ULONG KiMask32Array[MAXIMUM_PRIORITY] =
|
||||||
|
@ -55,250 +46,6 @@ KeFindNextRightSetAffinity(IN UCHAR Number,
|
||||||
return (UCHAR)Result;
|
return (UCHAR)Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
KiRequestReschedule(CCHAR Processor)
|
|
||||||
{
|
|
||||||
PKPCR Pcr;
|
|
||||||
|
|
||||||
Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE);
|
|
||||||
Pcr->Prcb->QuantumEnd = TRUE;
|
|
||||||
KiIpiSendRequest(1 << Processor, IPI_DPC);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
KiInsertIntoThreadList(KPRIORITY Priority,
|
|
||||||
PKTHREAD Thread)
|
|
||||||
{
|
|
||||||
ASSERT(Ready == Thread->State);
|
|
||||||
ASSERT(Thread->Priority == Priority);
|
|
||||||
|
|
||||||
if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) {
|
|
||||||
|
|
||||||
DPRINT1("Invalid thread priority (%d)\n", Priority);
|
|
||||||
KEBUGCHECK(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
InsertTailList(&PriorityListHead[Priority], &Thread->WaitListEntry);
|
|
||||||
PriorityListMask |= (1 << Priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
VOID
|
|
||||||
KiRemoveFromThreadList(PKTHREAD Thread)
|
|
||||||
{
|
|
||||||
ASSERT(Ready == Thread->State);
|
|
||||||
RemoveEntryList(&Thread->WaitListEntry);
|
|
||||||
if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Priority])) {
|
|
||||||
|
|
||||||
PriorityListMask &= ~(1 << Thread->Priority);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
PKTHREAD
|
|
||||||
KiScanThreadList(KPRIORITY Priority,
|
|
||||||
KAFFINITY Affinity)
|
|
||||||
{
|
|
||||||
PKTHREAD current;
|
|
||||||
ULONG Mask;
|
|
||||||
|
|
||||||
Mask = (1 << Priority);
|
|
||||||
|
|
||||||
if (PriorityListMask & Mask) {
|
|
||||||
|
|
||||||
LIST_FOR_EACH(current, &PriorityListHead[Priority], KTHREAD, WaitListEntry) {
|
|
||||||
|
|
||||||
if (current->State != Ready) {
|
|
||||||
|
|
||||||
DPRINT1("%p/%d\n", current, current->State);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT(current->State == Ready);
|
|
||||||
|
|
||||||
if (current->Affinity & Affinity) {
|
|
||||||
|
|
||||||
KiRemoveFromThreadList(current);
|
|
||||||
return(current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOLEAN
|
|
||||||
STDCALL
|
|
||||||
KiDispatchThreadNoLock(ULONG NewThreadStatus)
|
|
||||||
{
|
|
||||||
KPRIORITY CurrentPriority;
|
|
||||||
PKTHREAD Candidate;
|
|
||||||
ULONG Affinity;
|
|
||||||
PKTHREAD CurrentThread = KeGetCurrentThread();
|
|
||||||
BOOLEAN ApcState;
|
|
||||||
|
|
||||||
DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
|
|
||||||
CurrentThread, NewThreadStatus, CurrentThread->State);
|
|
||||||
|
|
||||||
CurrentThread->State = (UCHAR)NewThreadStatus;
|
|
||||||
|
|
||||||
if (NewThreadStatus == Ready) {
|
|
||||||
|
|
||||||
KiInsertIntoThreadList(CurrentThread->Priority,
|
|
||||||
CurrentThread);
|
|
||||||
}
|
|
||||||
|
|
||||||
Affinity = 1 << KeGetCurrentProcessorNumber();
|
|
||||||
|
|
||||||
for (CurrentPriority = HIGH_PRIORITY; CurrentPriority >= LOW_PRIORITY; CurrentPriority--) {
|
|
||||||
|
|
||||||
Candidate = KiScanThreadList(CurrentPriority, Affinity);
|
|
||||||
|
|
||||||
if (Candidate == CurrentThread) {
|
|
||||||
|
|
||||||
Candidate->State = Running;
|
|
||||||
KeReleaseDispatcherDatabaseLockFromDpcLevel();
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Candidate != NULL) {
|
|
||||||
|
|
||||||
PKTHREAD OldThread;
|
|
||||||
PKTHREAD IdleThread;
|
|
||||||
|
|
||||||
DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
|
|
||||||
|
|
||||||
Candidate->State = Running;
|
|
||||||
|
|
||||||
OldThread = CurrentThread;
|
|
||||||
CurrentThread = Candidate;
|
|
||||||
IdleThread = KeGetCurrentPrcb()->IdleThread;
|
|
||||||
|
|
||||||
if (OldThread == IdleThread) {
|
|
||||||
|
|
||||||
IdleProcessorMask &= ~Affinity;
|
|
||||||
|
|
||||||
} else if (CurrentThread == IdleThread) {
|
|
||||||
|
|
||||||
IdleProcessorMask |= Affinity;
|
|
||||||
}
|
|
||||||
|
|
||||||
MmUpdatePageDir((PEPROCESS)PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
|
|
||||||
|
|
||||||
/* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
|
|
||||||
DPRINT("You are : %x, swapping to: %x.\n", OldThread, CurrentThread);
|
|
||||||
ApcState = KiSwapContext(OldThread, CurrentThread);
|
|
||||||
DPRINT("You are : %x, swapped from: %x\n", OldThread, CurrentThread);
|
|
||||||
return ApcState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
|
|
||||||
KEBUGCHECK(0);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
FASTCALL
|
|
||||||
KiSwapThread(IN PKTHREAD CurrentThread,
|
|
||||||
IN PKPRCB Prcb)
|
|
||||||
{
|
|
||||||
BOOLEAN ApcState;
|
|
||||||
|
|
||||||
/* Find a new thread to run */
|
|
||||||
DPRINT("Dispatching Thread as blocked\n");
|
|
||||||
ApcState = KiDispatchThreadNoLock(Waiting);
|
|
||||||
|
|
||||||
/* Check if we need to deliver APCs */
|
|
||||||
if (ApcState)
|
|
||||||
{
|
|
||||||
/* Lower to APC_LEVEL */
|
|
||||||
KeLowerIrql(APC_LEVEL);
|
|
||||||
|
|
||||||
/* Deliver APCs */
|
|
||||||
KiDeliverApc(KernelMode, NULL, NULL);
|
|
||||||
ASSERT(CurrentThread->WaitIrql == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lower IRQL back to what it was */
|
|
||||||
KfLowerIrql(CurrentThread->WaitIrql);
|
|
||||||
|
|
||||||
/* Return the wait status */
|
|
||||||
return CurrentThread->WaitStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
STDCALL
|
|
||||||
KiDispatchThread(ULONG NewThreadStatus)
|
|
||||||
{
|
|
||||||
KIRQL OldIrql;
|
|
||||||
|
|
||||||
if (KeGetCurrentPrcb()->IdleThread == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
|
||||||
KiDispatchThreadNoLock(NewThreadStatus);
|
|
||||||
KeLowerIrql(OldIrql);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
NTAPI
|
|
||||||
KiReadyThread(IN PKTHREAD Thread)
|
|
||||||
{
|
|
||||||
/* Makes a thread ready */
|
|
||||||
Thread->State = Ready;
|
|
||||||
KiInsertIntoThreadList(Thread->Priority, Thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
VOID
|
|
||||||
STDCALL
|
|
||||||
KiAdjustQuantumThread(IN PKTHREAD Thread)
|
|
||||||
{
|
|
||||||
KPRIORITY Priority;
|
|
||||||
|
|
||||||
/* Don't adjust for RT threads */
|
|
||||||
if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
|
|
||||||
Thread->BasePriority < LOW_REALTIME_PRIORITY - 2)
|
|
||||||
{
|
|
||||||
/* Decrease Quantum by one and see if we've ran out */
|
|
||||||
if (--Thread->Quantum <= 0)
|
|
||||||
{
|
|
||||||
/* Return quantum */
|
|
||||||
Thread->Quantum = Thread->QuantumReset;
|
|
||||||
|
|
||||||
/* Calculate new Priority */
|
|
||||||
Priority = Thread->Priority - (Thread->PriorityDecrement + 1);
|
|
||||||
|
|
||||||
/* Normalize it if we've gone too low */
|
|
||||||
if (Priority < Thread->BasePriority) Priority = Thread->BasePriority;
|
|
||||||
|
|
||||||
/* Reset the priority decrement, we've done it */
|
|
||||||
Thread->PriorityDecrement = 0;
|
|
||||||
|
|
||||||
/* Set the new priority, if needed */
|
|
||||||
if (Priority != Thread->Priority)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* FIXME: This should be a call to KiSetPriorityThread but
|
|
||||||
* due to the current ""scheduler"" in ROS, it can't be done
|
|
||||||
* cleanly since it actualyl dispatches threads instead.
|
|
||||||
*/
|
|
||||||
Thread->Priority = Priority;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* FIXME: Priority hasn't changed, find a new thread */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Nothing to do... */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
STDCALL
|
STDCALL
|
||||||
KiSuspendThreadKernelRoutine(PKAPC Apc,
|
KiSuspendThreadKernelRoutine(PKAPC Apc,
|
||||||
|
@ -490,11 +237,6 @@ KeResumeThread(IN PKTHREAD Thread)
|
||||||
return PreviousCount;
|
return PreviousCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
|
||||||
FASTCALL
|
|
||||||
KiInsertQueueApc(PKAPC Apc,
|
|
||||||
KPRIORITY PriorityBoost);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Used by the debugging code to freeze all the process's threads
|
* Used by the debugging code to freeze all the process's threads
|
||||||
* while the debugger is examining their state.
|
* while the debugger is examining their state.
|
||||||
|
@ -1156,86 +898,6 @@ KeQueryBasePriorityThread(IN PKTHREAD Thread)
|
||||||
return BasePriorityIncrement;
|
return BasePriorityIncrement;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
|
||||||
STDCALL
|
|
||||||
KiSetPriorityThread(PKTHREAD Thread,
|
|
||||||
KPRIORITY Priority,
|
|
||||||
PBOOLEAN Released)
|
|
||||||
{
|
|
||||||
KPRIORITY OldPriority = Thread->Priority;
|
|
||||||
ULONG Mask;
|
|
||||||
int i;
|
|
||||||
PKPCR Pcr;
|
|
||||||
DPRINT("Changing prio to : %lx\n", Priority);
|
|
||||||
|
|
||||||
/* Check if priority changed */
|
|
||||||
if (OldPriority != Priority)
|
|
||||||
{
|
|
||||||
/* Set it */
|
|
||||||
Thread->Priority = Priority;
|
|
||||||
|
|
||||||
/* Choose action based on thread's state */
|
|
||||||
if (Thread->State == Ready)
|
|
||||||
{
|
|
||||||
/* Remove it from the current queue */
|
|
||||||
KiRemoveFromThreadList(Thread);
|
|
||||||
|
|
||||||
/* Re-insert it at its current priority */
|
|
||||||
KiInsertIntoThreadList(Priority, Thread);
|
|
||||||
|
|
||||||
/* Check if the old priority was lower */
|
|
||||||
if (KeGetCurrentThread()->Priority < Priority)
|
|
||||||
{
|
|
||||||
/* Dispatch it immediately */
|
|
||||||
KiDispatchThreadNoLock(Ready);
|
|
||||||
*Released = TRUE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (Thread->State == Running)
|
|
||||||
{
|
|
||||||
/* Check if the new priority is lower */
|
|
||||||
if (Priority < OldPriority)
|
|
||||||
{
|
|
||||||
/* Check for threads with a higher priority */
|
|
||||||
Mask = ~((1 << (Priority + 1)) - 1);
|
|
||||||
if (PriorityListMask & Mask)
|
|
||||||
{
|
|
||||||
/* Found a thread, is it us? */
|
|
||||||
if (Thread == KeGetCurrentThread())
|
|
||||||
{
|
|
||||||
/* Dispatch us */
|
|
||||||
KiDispatchThreadNoLock(Ready);
|
|
||||||
*Released = TRUE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Loop every CPU */
|
|
||||||
for (i = 0; i < KeNumberProcessors; i++)
|
|
||||||
{
|
|
||||||
/* Get the PCR for this CPU */
|
|
||||||
Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
|
|
||||||
|
|
||||||
/* Reschedule if the new one is already on a CPU */
|
|
||||||
if (Pcr->Prcb->CurrentThread == Thread)
|
|
||||||
{
|
|
||||||
KeReleaseDispatcherDatabaseLockFromDpcLevel();
|
|
||||||
KiRequestReschedule(i);
|
|
||||||
*Released = TRUE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return to caller */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
|
@ -1383,71 +1045,33 @@ KeSetPriorityThread(PKTHREAD Thread,
|
||||||
*
|
*
|
||||||
* Sets thread's affinity
|
* Sets thread's affinity
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
KAFFINITY
|
||||||
STDCALL
|
STDCALL
|
||||||
KeSetAffinityThread(PKTHREAD Thread,
|
KeSetAffinityThread(PKTHREAD Thread,
|
||||||
KAFFINITY Affinity)
|
KAFFINITY Affinity)
|
||||||
{
|
{
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
LONG i;
|
KAFFINITY OldAffinity;
|
||||||
PKPCR Pcr;
|
BOOLEAN Released;
|
||||||
KAFFINITY ProcessorMask;
|
|
||||||
|
|
||||||
DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
|
DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
|
||||||
|
|
||||||
/* Verify correct affinity */
|
|
||||||
if ((Affinity & Thread->ApcStatePointer[0]->Process->Affinity) !=
|
|
||||||
Affinity || !Affinity)
|
|
||||||
{
|
|
||||||
KEBUGCHECK(INVALID_AFFINITY_SET);
|
|
||||||
}
|
|
||||||
|
|
||||||
OldIrql = KeAcquireDispatcherDatabaseLock();
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
|
|
||||||
Thread->UserAffinity = Affinity;
|
/* Call the internal function */
|
||||||
|
OldAffinity = KiSetAffinityThread(Thread, Affinity, &Released);
|
||||||
if (Thread->SystemAffinityActive == FALSE) {
|
|
||||||
|
|
||||||
Thread->Affinity = Affinity;
|
|
||||||
|
|
||||||
if (Thread->State == Running) {
|
|
||||||
|
|
||||||
ProcessorMask = 1 << KeGetCurrentProcessorNumber();
|
|
||||||
if (Thread == KeGetCurrentThread()) {
|
|
||||||
|
|
||||||
if (!(Affinity & ProcessorMask)) {
|
|
||||||
|
|
||||||
KiDispatchThreadNoLock(Ready);
|
|
||||||
KeLowerIrql(OldIrql);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
for (i = 0; i < KeNumberProcessors; i++) {
|
|
||||||
|
|
||||||
Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
|
|
||||||
if (Pcr->Prcb->CurrentThread == Thread) {
|
|
||||||
|
|
||||||
if (!(Affinity & ProcessorMask)) {
|
|
||||||
|
|
||||||
KeReleaseDispatcherDatabaseLockFromDpcLevel();
|
|
||||||
KiRequestReschedule(i);
|
|
||||||
KeLowerIrql(OldIrql);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ASSERT (i < KeNumberProcessors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Release Lock if needed */
|
||||||
|
if (!Released)
|
||||||
|
{
|
||||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||||
return STATUS_SUCCESS;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KeLowerIrql(OldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OldAffinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1572,43 +1196,3 @@ KeTestAlertThread(IN KPROCESSOR_MODE AlertMode)
|
||||||
return OldState;
|
return OldState;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
STDCALL
|
|
||||||
NtDelayExecution(IN BOOLEAN Alertable,
|
|
||||||
IN PLARGE_INTEGER DelayInterval)
|
|
||||||
{
|
|
||||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
|
||||||
LARGE_INTEGER SafeInterval;
|
|
||||||
NTSTATUS Status;
|
|
||||||
|
|
||||||
/* Check if parameters are valid */
|
|
||||||
if(PreviousMode != KernelMode) {
|
|
||||||
|
|
||||||
Status = STATUS_SUCCESS;
|
|
||||||
|
|
||||||
_SEH_TRY {
|
|
||||||
|
|
||||||
/* make a copy on the kernel stack and let DelayInterval point to it so
|
|
||||||
we don't need to wrap KeDelayExecutionThread in SEH! */
|
|
||||||
SafeInterval = ProbeForReadLargeInteger(DelayInterval);
|
|
||||||
DelayInterval = &SafeInterval;
|
|
||||||
|
|
||||||
} _SEH_HANDLE {
|
|
||||||
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
} _SEH_END;
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Call the Kernel Function */
|
|
||||||
Status = KeDelayExecutionThread(PreviousMode,
|
|
||||||
Alertable,
|
|
||||||
DelayInterval);
|
|
||||||
|
|
||||||
/* Return Status */
|
|
||||||
return Status;
|
|
||||||
}
|
|
430
reactos/ntoskrnl/ke/thrdschd.c
Normal file
430
reactos/ntoskrnl/ke/thrdschd.c
Normal file
|
@ -0,0 +1,430 @@
|
||||||
|
/*
|
||||||
|
* PROJECT: ReactOS Kernel
|
||||||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
|
* FILE: ntoskrnl/ke/thrdschd.c
|
||||||
|
* PURPOSE: Kernel Thread Scheduler (Affinity, Priority, Scheduling)
|
||||||
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
|
#include <ntoskrnl.h>
|
||||||
|
#define NDEBUG
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
|
LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
|
||||||
|
ULONG PriorityListMask = 0;
|
||||||
|
ULONG KiIdleSummary;
|
||||||
|
ULONG KiIdleSMTSummary;
|
||||||
|
|
||||||
|
/* FUNCTIONS *****************************************************************/
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
KiRequestReschedule(CCHAR Processor)
|
||||||
|
{
|
||||||
|
PKPCR Pcr;
|
||||||
|
|
||||||
|
Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE);
|
||||||
|
Pcr->Prcb->QuantumEnd = TRUE;
|
||||||
|
KiIpiSendRequest(1 << Processor, IPI_DPC);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
KiInsertIntoThreadList(KPRIORITY Priority,
|
||||||
|
PKTHREAD Thread)
|
||||||
|
{
|
||||||
|
ASSERT(Ready == Thread->State);
|
||||||
|
ASSERT(Thread->Priority == Priority);
|
||||||
|
|
||||||
|
if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) {
|
||||||
|
|
||||||
|
DPRINT1("Invalid thread priority (%d)\n", Priority);
|
||||||
|
KEBUGCHECK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertTailList(&PriorityListHead[Priority], &Thread->WaitListEntry);
|
||||||
|
PriorityListMask |= (1 << Priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
VOID
|
||||||
|
KiRemoveFromThreadList(PKTHREAD Thread)
|
||||||
|
{
|
||||||
|
ASSERT(Ready == Thread->State);
|
||||||
|
RemoveEntryList(&Thread->WaitListEntry);
|
||||||
|
if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Priority])) {
|
||||||
|
|
||||||
|
PriorityListMask &= ~(1 << Thread->Priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
PKTHREAD
|
||||||
|
KiScanThreadList(KPRIORITY Priority,
|
||||||
|
KAFFINITY Affinity)
|
||||||
|
{
|
||||||
|
PKTHREAD current;
|
||||||
|
ULONG Mask;
|
||||||
|
|
||||||
|
Mask = (1 << Priority);
|
||||||
|
|
||||||
|
if (PriorityListMask & Mask) {
|
||||||
|
|
||||||
|
LIST_FOR_EACH(current, &PriorityListHead[Priority], KTHREAD, WaitListEntry) {
|
||||||
|
|
||||||
|
if (current->State != Ready) {
|
||||||
|
|
||||||
|
DPRINT1("%p/%d\n", current, current->State);
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(current->State == Ready);
|
||||||
|
|
||||||
|
if (current->Affinity & Affinity) {
|
||||||
|
|
||||||
|
KiRemoveFromThreadList(current);
|
||||||
|
return(current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN
|
||||||
|
STDCALL
|
||||||
|
KiDispatchThreadNoLock(ULONG NewThreadStatus)
|
||||||
|
{
|
||||||
|
KPRIORITY CurrentPriority;
|
||||||
|
PKTHREAD Candidate;
|
||||||
|
ULONG Affinity;
|
||||||
|
PKTHREAD CurrentThread = KeGetCurrentThread();
|
||||||
|
BOOLEAN ApcState;
|
||||||
|
|
||||||
|
DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
|
||||||
|
CurrentThread, NewThreadStatus, CurrentThread->State);
|
||||||
|
|
||||||
|
CurrentThread->State = (UCHAR)NewThreadStatus;
|
||||||
|
|
||||||
|
if (NewThreadStatus == Ready) {
|
||||||
|
|
||||||
|
KiInsertIntoThreadList(CurrentThread->Priority,
|
||||||
|
CurrentThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
Affinity = 1 << KeGetCurrentProcessorNumber();
|
||||||
|
|
||||||
|
for (CurrentPriority = HIGH_PRIORITY; CurrentPriority >= LOW_PRIORITY; CurrentPriority--) {
|
||||||
|
|
||||||
|
Candidate = KiScanThreadList(CurrentPriority, Affinity);
|
||||||
|
|
||||||
|
if (Candidate == CurrentThread) {
|
||||||
|
|
||||||
|
Candidate->State = Running;
|
||||||
|
KeReleaseDispatcherDatabaseLockFromDpcLevel();
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Candidate != NULL) {
|
||||||
|
|
||||||
|
PKTHREAD OldThread;
|
||||||
|
PKTHREAD IdleThread;
|
||||||
|
|
||||||
|
DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
|
||||||
|
|
||||||
|
Candidate->State = Running;
|
||||||
|
|
||||||
|
OldThread = CurrentThread;
|
||||||
|
CurrentThread = Candidate;
|
||||||
|
IdleThread = KeGetCurrentPrcb()->IdleThread;
|
||||||
|
|
||||||
|
if (OldThread == IdleThread) {
|
||||||
|
|
||||||
|
KiIdleSummary &= ~Affinity;
|
||||||
|
|
||||||
|
} else if (CurrentThread == IdleThread) {
|
||||||
|
|
||||||
|
KiIdleSummary |= Affinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
MmUpdatePageDir((PEPROCESS)PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS));
|
||||||
|
|
||||||
|
/* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */
|
||||||
|
DPRINT("You are : %x, swapping to: %x.\n", OldThread, CurrentThread);
|
||||||
|
ApcState = KiSwapContext(OldThread, CurrentThread);
|
||||||
|
DPRINT("You are : %x, swapped from: %x\n", OldThread, CurrentThread);
|
||||||
|
return ApcState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
|
||||||
|
KEBUGCHECK(0);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FASTCALL
|
||||||
|
KiSwapThread(IN PKTHREAD CurrentThread,
|
||||||
|
IN PKPRCB Prcb)
|
||||||
|
{
|
||||||
|
BOOLEAN ApcState;
|
||||||
|
|
||||||
|
/* Find a new thread to run */
|
||||||
|
DPRINT("Dispatching Thread as blocked\n");
|
||||||
|
ApcState = KiDispatchThreadNoLock(Waiting);
|
||||||
|
|
||||||
|
/* Check if we need to deliver APCs */
|
||||||
|
if (ApcState)
|
||||||
|
{
|
||||||
|
/* Lower to APC_LEVEL */
|
||||||
|
KeLowerIrql(APC_LEVEL);
|
||||||
|
|
||||||
|
/* Deliver APCs */
|
||||||
|
KiDeliverApc(KernelMode, NULL, NULL);
|
||||||
|
ASSERT(CurrentThread->WaitIrql == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lower IRQL back to what it was */
|
||||||
|
KfLowerIrql(CurrentThread->WaitIrql);
|
||||||
|
|
||||||
|
/* Return the wait status */
|
||||||
|
return CurrentThread->WaitStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KiDispatchThread(ULONG NewThreadStatus)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
if (KeGetCurrentPrcb()->IdleThread == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OldIrql = KeAcquireDispatcherDatabaseLock();
|
||||||
|
KiDispatchThreadNoLock(NewThreadStatus);
|
||||||
|
KeLowerIrql(OldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
KiReadyThread(IN PKTHREAD Thread)
|
||||||
|
{
|
||||||
|
/* Makes a thread ready */
|
||||||
|
Thread->State = Ready;
|
||||||
|
KiInsertIntoThreadList(Thread->Priority, Thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KiAdjustQuantumThread(IN PKTHREAD Thread)
|
||||||
|
{
|
||||||
|
KPRIORITY Priority;
|
||||||
|
|
||||||
|
/* Don't adjust for RT threads */
|
||||||
|
if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
|
||||||
|
Thread->BasePriority < LOW_REALTIME_PRIORITY - 2)
|
||||||
|
{
|
||||||
|
/* Decrease Quantum by one and see if we've ran out */
|
||||||
|
if (--Thread->Quantum <= 0)
|
||||||
|
{
|
||||||
|
/* Return quantum */
|
||||||
|
Thread->Quantum = Thread->QuantumReset;
|
||||||
|
|
||||||
|
/* Calculate new Priority */
|
||||||
|
Priority = Thread->Priority - (Thread->PriorityDecrement + 1);
|
||||||
|
|
||||||
|
/* Normalize it if we've gone too low */
|
||||||
|
if (Priority < Thread->BasePriority) Priority = Thread->BasePriority;
|
||||||
|
|
||||||
|
/* Reset the priority decrement, we've done it */
|
||||||
|
Thread->PriorityDecrement = 0;
|
||||||
|
|
||||||
|
/* Set the new priority, if needed */
|
||||||
|
if (Priority != Thread->Priority)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* FIXME: This should be a call to KiSetPriorityThread but
|
||||||
|
* due to the current ""scheduler"" in ROS, it can't be done
|
||||||
|
* cleanly since it actualyl dispatches threads instead.
|
||||||
|
*/
|
||||||
|
Thread->Priority = Priority;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* FIXME: Priority hasn't changed, find a new thread */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Nothing to do... */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
STDCALL
|
||||||
|
KiSetPriorityThread(PKTHREAD Thread,
|
||||||
|
KPRIORITY Priority,
|
||||||
|
PBOOLEAN Released)
|
||||||
|
{
|
||||||
|
KPRIORITY OldPriority = Thread->Priority;
|
||||||
|
ULONG Mask;
|
||||||
|
int i;
|
||||||
|
PKPCR Pcr;
|
||||||
|
DPRINT("Changing prio to : %lx\n", Priority);
|
||||||
|
|
||||||
|
/* Check if priority changed */
|
||||||
|
if (OldPriority != Priority)
|
||||||
|
{
|
||||||
|
/* Set it */
|
||||||
|
Thread->Priority = Priority;
|
||||||
|
|
||||||
|
/* Choose action based on thread's state */
|
||||||
|
if (Thread->State == Ready)
|
||||||
|
{
|
||||||
|
/* Remove it from the current queue */
|
||||||
|
KiRemoveFromThreadList(Thread);
|
||||||
|
|
||||||
|
/* Re-insert it at its current priority */
|
||||||
|
KiInsertIntoThreadList(Priority, Thread);
|
||||||
|
|
||||||
|
/* Check if the old priority was lower */
|
||||||
|
if (KeGetCurrentThread()->Priority < Priority)
|
||||||
|
{
|
||||||
|
/* Dispatch it immediately */
|
||||||
|
KiDispatchThreadNoLock(Ready);
|
||||||
|
*Released = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Thread->State == Running)
|
||||||
|
{
|
||||||
|
/* Check if the new priority is lower */
|
||||||
|
if (Priority < OldPriority)
|
||||||
|
{
|
||||||
|
/* Check for threads with a higher priority */
|
||||||
|
Mask = ~((1 << (Priority + 1)) - 1);
|
||||||
|
if (PriorityListMask & Mask)
|
||||||
|
{
|
||||||
|
/* Found a thread, is it us? */
|
||||||
|
if (Thread == KeGetCurrentThread())
|
||||||
|
{
|
||||||
|
/* Dispatch us */
|
||||||
|
KiDispatchThreadNoLock(Ready);
|
||||||
|
*Released = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Loop every CPU */
|
||||||
|
for (i = 0; i < KeNumberProcessors; i++)
|
||||||
|
{
|
||||||
|
/* Get the PCR for this CPU */
|
||||||
|
Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
|
||||||
|
|
||||||
|
/* Reschedule if the new one is already on a CPU */
|
||||||
|
if (Pcr->Prcb->CurrentThread == Thread)
|
||||||
|
{
|
||||||
|
KeReleaseDispatcherDatabaseLockFromDpcLevel();
|
||||||
|
KiRequestReschedule(i);
|
||||||
|
*Released = TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return to caller */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
KAFFINITY
|
||||||
|
NTAPI
|
||||||
|
KiSetAffinityThread(IN PKTHREAD Thread,
|
||||||
|
IN KAFFINITY Affinity,
|
||||||
|
PBOOLEAN Released)
|
||||||
|
{
|
||||||
|
KAFFINITY OldAffinity;
|
||||||
|
ULONG ProcessorMask;
|
||||||
|
ULONG i;
|
||||||
|
PKPCR Pcr;
|
||||||
|
|
||||||
|
/* Make sure that the affinity is valid */
|
||||||
|
if (((Affinity & Thread->ApcState.Process->Affinity) != (Affinity)) ||
|
||||||
|
(!Affinity))
|
||||||
|
{
|
||||||
|
/* Bugcheck the system */
|
||||||
|
KeBugCheck(INVALID_AFFINITY_SET);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the old affinity */
|
||||||
|
OldAffinity = Thread->UserAffinity;
|
||||||
|
|
||||||
|
Thread->UserAffinity = Affinity;
|
||||||
|
|
||||||
|
if (Thread->SystemAffinityActive == FALSE) {
|
||||||
|
|
||||||
|
Thread->Affinity = Affinity;
|
||||||
|
|
||||||
|
if (Thread->State == Running) {
|
||||||
|
|
||||||
|
ProcessorMask = 1 << KeGetCurrentProcessorNumber();
|
||||||
|
if (Thread == KeGetCurrentThread()) {
|
||||||
|
|
||||||
|
if (!(Affinity & ProcessorMask)) {
|
||||||
|
|
||||||
|
KiDispatchThreadNoLock(Ready);
|
||||||
|
*Released = TRUE;
|
||||||
|
return OldAffinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
for (i = 0; i < KeNumberProcessors; i++) {
|
||||||
|
|
||||||
|
Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
|
||||||
|
if (Pcr->Prcb->CurrentThread == Thread) {
|
||||||
|
|
||||||
|
if (!(Affinity & ProcessorMask)) {
|
||||||
|
|
||||||
|
KeReleaseDispatcherDatabaseLockFromDpcLevel();
|
||||||
|
KiRequestReschedule(i);
|
||||||
|
*Released = TRUE;
|
||||||
|
return OldAffinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT (i < KeNumberProcessors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*Released = FALSE;
|
||||||
|
return OldAffinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
|
*/
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtYieldExecution(VOID)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// TODO (nothing too hard, just want to test out other code)
|
||||||
|
//
|
||||||
|
//DPRINT1("NO YIELD PERFORMED! If you see this, contact Alex\n");
|
||||||
|
//return STATUS_NO_YIELD_PERFORMED;
|
||||||
|
KiDispatchThread(Ready);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -861,4 +861,41 @@ DontWait:
|
||||||
return WaitStatus;
|
return WaitStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
NtDelayExecution(IN BOOLEAN Alertable,
|
||||||
|
IN PLARGE_INTEGER DelayInterval)
|
||||||
|
{
|
||||||
|
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||||
|
LARGE_INTEGER SafeInterval;
|
||||||
|
NTSTATUS Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
/* Check if parameters are valid */
|
||||||
|
if(PreviousMode != KernelMode)
|
||||||
|
{
|
||||||
|
_SEH_TRY
|
||||||
|
{
|
||||||
|
/* make a copy on the kernel stack and let DelayInterval point to it so
|
||||||
|
we don't need to wrap KeDelayExecutionThread in SEH! */
|
||||||
|
SafeInterval = ProbeForReadLargeInteger(DelayInterval);
|
||||||
|
DelayInterval = &SafeInterval;
|
||||||
|
}
|
||||||
|
_SEH_HANDLE
|
||||||
|
{
|
||||||
|
Status = _SEH_GetExceptionCode();
|
||||||
|
}
|
||||||
|
_SEH_END;
|
||||||
|
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the Kernel Function */
|
||||||
|
Status = KeDelayExecutionThread(PreviousMode,
|
||||||
|
Alertable,
|
||||||
|
DelayInterval);
|
||||||
|
|
||||||
|
/* Return Status */
|
||||||
|
return Status;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -57,13 +57,14 @@
|
||||||
<file>ipi.c</file>
|
<file>ipi.c</file>
|
||||||
<file>kqueue.c</file>
|
<file>kqueue.c</file>
|
||||||
<file>krnlinit.c</file>
|
<file>krnlinit.c</file>
|
||||||
<file>kthread.c</file>
|
|
||||||
<file>mutex.c</file>
|
<file>mutex.c</file>
|
||||||
<file>process.c</file>
|
<file>process.c</file>
|
||||||
<file>profile.c</file>
|
<file>profile.c</file>
|
||||||
<file>queue.c</file>
|
<file>queue.c</file>
|
||||||
<file>sem.c</file>
|
<file>sem.c</file>
|
||||||
<file>spinlock.c</file>
|
<file>spinlock.c</file>
|
||||||
|
<file>thrdschd.c</file>
|
||||||
|
<file>thrdobj.c</file>
|
||||||
<file>timer.c</file>
|
<file>timer.c</file>
|
||||||
<file>usercall.c</file>
|
<file>usercall.c</file>
|
||||||
<file>wait.c</file>
|
<file>wait.c</file>
|
||||||
|
|
|
@ -1077,15 +1077,4 @@ NtOpenThread(OUT PHANDLE ThreadHandle,
|
||||||
return Status;
|
return Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
|
||||||
NtYieldExecution(VOID)
|
|
||||||
{
|
|
||||||
KiDispatchThread(Ready);
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue