VOID NTAPI KiReadyThread(IN PKTHREAD Thread) { IN PKPROCESS Process = Thread->ApcState.Process; /* Check if the process is paged out */ if (Process->State != ProcessInMemory) { /* We don't page out processes in ROS */ ASSERT(FALSE); } else if (!Thread->KernelStackResident) { /* Increase the stack count */ ASSERT(Process->StackCount != MAXULONG_PTR); Process->StackCount++; /* Set the thread to transition */ ASSERT(Thread->State != Transition); Thread->State = Transition; /* The stack is always resident in ROS */ ASSERT(FALSE); } else { /* Insert the thread on the deferred ready list */ KiInsertDeferredReadyList(Thread); } }
/*++ * @name KiInsertQueueApc * * The KiInsertQueueApc routine queues a APC for execution when the right * scheduler environment exists. * * @param Apc * Pointer to an initialized control object of type APC for which the * caller provides the storage. * * @param PriorityBoost * Priority Boost to apply to the Thread. * * @return None * * @remarks The APC will execute at APC_LEVEL for the KernelRoutine registered, * and at PASSIVE_LEVEL for the NormalRoutine registered. * * Callers of this routine must have locked the dipatcher database. * *--*/ VOID FASTCALL KiInsertQueueApc(IN PKAPC Apc, IN KPRIORITY PriorityBoost) { PKTHREAD Thread = Apc->Thread; PKAPC_STATE ApcState; KPROCESSOR_MODE ApcMode; PLIST_ENTRY ListHead, NextEntry; PKAPC QueuedApc; PKGATE Gate; NTSTATUS Status; BOOLEAN RequestInterrupt = FALSE; /* * Check if the caller wanted this APC to use the thread's environment at * insertion time. */ if (Apc->ApcStateIndex == InsertApcEnvironment) { /* Copy it over */ Apc->ApcStateIndex = Thread->ApcStateIndex; } /* Get the APC State for this Index, and the mode too */ ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex]; ApcMode = Apc->ApcMode; /* The APC must be "inserted" already */ ASSERT(Apc->Inserted == TRUE); /* Three scenarios: * 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List * 2) User APC which is PsExitSpecialApc = Put it at the front of the List * 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list */ if (Apc->NormalRoutine) { /* Normal APC; is it the Thread Termination APC? */ if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc)) { /* Set User APC pending to true */ Thread->ApcState.UserApcPending = TRUE; /* Insert it at the top of the list */ InsertHeadList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry); } else { /* Regular user or kernel Normal APC */ InsertTailList(&ApcState->ApcListHead[ApcMode], &Apc->ApcListEntry); } } else { /* Special APC, find the last one in the list */ ListHead = &ApcState->ApcListHead[ApcMode]; NextEntry = ListHead->Blink; while (NextEntry != ListHead) { /* Get the APC */ QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry); /* Is this a No-Normal APC? If so, break */ if (!QueuedApc->NormalRoutine) break; /* Move to the previous APC in the Queue */ NextEntry = NextEntry->Blink; } /* Insert us here */ InsertHeadList(NextEntry, &Apc->ApcListEntry); } /* Now check if the Apc State Indexes match */ if (Thread->ApcStateIndex == Apc->ApcStateIndex) { /* Check that the thread matches */ if (Thread == KeGetCurrentThread()) { /* Sanity check */ ASSERT(Thread->State == Running); /* Check if this is kernel mode */ if (ApcMode == KernelMode) { /* All valid, a Kernel APC is pending now */ Thread->ApcState.KernelApcPending = TRUE; /* Check if Special APCs are disabled */ if (!Thread->SpecialApcDisable) { /* They're not, so request the interrupt */ HalRequestSoftwareInterrupt(APC_LEVEL); } } } else { /* Acquire the dispatcher lock */ KiAcquireDispatcherLock(); /* Check if this is a kernel-mode APC */ if (ApcMode == KernelMode) { /* Kernel-mode APC, set us pending */ Thread->ApcState.KernelApcPending = TRUE; /* Are we currently running? */ if (Thread->State == Running) { /* The thread is running, so remember to send a request */ RequestInterrupt = TRUE; } else if ((Thread->State == Waiting) && (Thread->WaitIrql == PASSIVE_LEVEL) && !(Thread->SpecialApcDisable) && (!(Apc->NormalRoutine) || (!(Thread->KernelApcDisable) && !(Thread->ApcState.KernelApcInProgress)))) { /* We'll unwait with this status */ Status = STATUS_KERNEL_APC; /* Wake up the thread */ KiUnwaitThread(Thread, Status, PriorityBoost); } else if (Thread->State == GateWait) { /* Lock the thread */ KiAcquireThreadLock(Thread); /* Essentially do the same check as above */ if ((Thread->State == GateWait) && (Thread->WaitIrql == PASSIVE_LEVEL) && !(Thread->SpecialApcDisable) && (!(Apc->NormalRoutine) || (!(Thread->KernelApcDisable) && !(Thread->ApcState.KernelApcInProgress)))) { /* We were in a gate wait. Handle this. */ DPRINT1("A thread was in a gate wait\n"); /* Get the gate */ Gate = Thread->GateObject; /* Lock the gate */ KiAcquireDispatcherObject(&Gate->Header); /* Remove it from the waiters list */ RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry); /* Unlock the gate */ KiReleaseDispatcherObject(&Gate->Header); /* Increase the queue counter if needed */ if (Thread->Queue) Thread->Queue->CurrentCount++; /* Put into deferred ready list with this status */ Thread->WaitStatus = STATUS_KERNEL_APC; KiInsertDeferredReadyList(Thread); } /* Release the thread lock */ KiReleaseThreadLock(Thread); } } else if ((Thread->State == Waiting) && (Thread->WaitMode == UserMode) && ((Thread->Alertable) || (Thread->ApcState.UserApcPending))) { /* Set user-mode APC pending */ Thread->ApcState.UserApcPending = TRUE; Status = STATUS_USER_APC; /* Wake up the thread */ KiUnwaitThread(Thread, Status, PriorityBoost); } /* Release dispatcher lock */ KiReleaseDispatcherLockFromDpcLevel(); /* Check if an interrupt was requested */ KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor); } } }
VOID FASTCALL KiSetPriorityThread(IN PKTHREAD Thread, IN KPRIORITY Priority) { PKPRCB Prcb; ULONG Processor; BOOLEAN RequestInterrupt = FALSE; KPRIORITY OldPriority; PKTHREAD NewThread; ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY)); /* Check if priority changed */ if (Thread->Priority != Priority) { /* Loop priority setting in case we need to start over */ for (;;) { /* Choose action based on thread's state */ if (Thread->State == Ready) { /* Make sure we're not on the ready queue */ if (!Thread->ProcessReadyQueue) { /* Get the PRCB for the thread and lock it */ Processor = Thread->NextProcessor; Prcb = KiProcessorBlock[Processor]; KiAcquirePrcbLock(Prcb); /* Make sure the thread is still ready and on this CPU */ if ((Thread->State == Ready) && (Thread->NextProcessor == Prcb->Number)) { /* Sanity check */ ASSERT((Prcb->ReadySummary & PRIORITY_MASK(Thread->Priority))); /* Remove it from the current queue */ if (RemoveEntryList(&Thread->WaitListEntry)) { /* Update the ready summary */ Prcb->ReadySummary ^= PRIORITY_MASK(Thread-> Priority); } /* Update priority */ Thread->Priority = (SCHAR)Priority; /* Re-insert it at its current priority */ KiInsertDeferredReadyList(Thread); /* Release the PRCB Lock */ KiReleasePrcbLock(Prcb); } else { /* Release the lock and loop again */ KiReleasePrcbLock(Prcb); continue; } } else { /* It's already on the ready queue, just update priority */ Thread->Priority = (SCHAR)Priority; } } else if (Thread->State == Standby) { /* Get the PRCB for the thread and lock it */ Processor = Thread->NextProcessor; Prcb = KiProcessorBlock[Processor]; KiAcquirePrcbLock(Prcb); /* Check if we're still the next thread to run */ if (Thread == Prcb->NextThread) { /* Get the old priority and update ours */ OldPriority = Thread->Priority; Thread->Priority = (SCHAR)Priority; /* Check if there was a change */ if (Priority < OldPriority) { /* Find a new thread */ NewThread = KiSelectReadyThread(Priority + 1, Prcb); if (NewThread) { /* Found a new one, set it on standby */ NewThread->State = Standby; Prcb->NextThread = NewThread; /* Dispatch our thread */ KiInsertDeferredReadyList(Thread); } } /* Release the PRCB lock */ KiReleasePrcbLock(Prcb); } else { /* Release the lock and try again */ KiReleasePrcbLock(Prcb); continue; } } else if (Thread->State == Running) { /* Get the PRCB for the thread and lock it */ Processor = Thread->NextProcessor; Prcb = KiProcessorBlock[Processor]; KiAcquirePrcbLock(Prcb); /* Check if we're still the current thread running */ if (Thread == Prcb->CurrentThread) { /* Get the old priority and update ours */ OldPriority = Thread->Priority; Thread->Priority = (SCHAR)Priority; /* Check if there was a change and there's no new thread */ if ((Priority < OldPriority) && !(Prcb->NextThread)) { /* Find a new thread */ NewThread = KiSelectReadyThread(Priority + 1, Prcb); if (NewThread) { /* Found a new one, set it on standby */ NewThread->State = Standby; Prcb->NextThread = NewThread; /* Request an interrupt */ RequestInterrupt = TRUE; } } /* Release the lock and check if we need an interrupt */ KiReleasePrcbLock(Prcb); if (RequestInterrupt) { /* Check if we're running on another CPU */ if (KeGetCurrentProcessorNumber() != Processor) { /* We are, send an IPI */ KiIpiSend(AFFINITY_MASK(Processor), IPI_DPC); } } } else { /* Thread changed, release lock and restart */ KiReleasePrcbLock(Prcb); continue; } } else if (Thread->State == DeferredReady) { /* FIXME: TODO */ DPRINT1("Deferred state not yet supported\n"); ASSERT(FALSE); } else { /* Any other state, just change priority */ Thread->Priority = (SCHAR)Priority; } /* If we got here, then thread state was consistent, so bail out */ break; } } }