|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
waitsup.c
Abstract:
This module contains the support routines necessary to support the generic kernel wait functions. Functions are provided to test if a wait can be satisfied, to satisfy a wait, and to unwwait a thread.
Author:
David N. Cutler (davec) 24-Mar-1989
Environment:
Kernel mode only.
Revision History:
--*/
#include "ki.h"
VOID FASTCALL KiExitDispatcher ( IN KIRQL OldIrql )
/*++
Routine Description:
This function processes the deferred ready list, possibly switches to a new thread, and lowers IRQL to its previous value.
Arguments:
OldIrql - Supplies the previous IRQL value.
Return Value:
None.
--*/
{
PKTHREAD CurrentThread; PKTHREAD NewThread; BOOLEAN Pending; PKPRCB Prcb;
ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);
//
// Process the deferred ready list if the list is not empty.
//
Prcb = KeGetCurrentPrcb();
#if !defined(NT_UP)
if (Prcb->DeferredReadyListHead.Next != NULL) { KiProcessDeferredReadyList(Prcb); }
#endif
//
// If the old IRQL is less than dispatch level, then a new thread can
// be dispatcher immediately.
//
if (OldIrql < DISPATCH_LEVEL) {
//
// If there is a new thread selected for execution, then switch
// context to the new thread.
//
if (Prcb->NextThread != NULL) { KiAcquirePrcbLock(Prcb); NewThread = Prcb->NextThread; CurrentThread = Prcb->CurrentThread; KiSetContextSwapBusy(CurrentThread); Prcb->NextThread = NULL; Prcb->CurrentThread = NewThread; NewThread->State = Running; KxQueueReadyThread(CurrentThread, Prcb); CurrentThread->WaitIrql = OldIrql; Pending = KiSwapContext(CurrentThread, NewThread); if (Pending != FALSE) { KeLowerIrql(APC_LEVEL); KiDeliverApc(KernelMode, NULL, NULL); ASSERT(OldIrql == 0); } }
} else if ((Prcb->NextThread != NULL) && (Prcb->DpcRoutineActive == FALSE)) {
KiRequestSoftwareInterrupt(DISPATCH_LEVEL); }
//
// Lower IRQL to its previous level.
//
KeLowerIrql(OldIrql); return; }
VOID FASTCALL KiUnwaitThread ( IN PRKTHREAD Thread, IN LONG_PTR WaitStatus, IN KPRIORITY Increment )
/*++
Routine Description:
This function unwaits a thread, sets the thread's wait completion status, calculates the thread's new priority, and either readies the thread for execution or adds the thread to a list of threads to be readied later.
Arguments:
Thread - Supplies a pointer to a dispatcher object of type thread.
WaitStatus - Supplies the wait completion status.
Increment - Supplies the priority increment that is to be applied to the thread's priority.
Return Value:
None.
--*/
{
//
// Unlink thread from the appropriate wait queues and set the wait
// completion status.
//
KiUnlinkThread(Thread, WaitStatus);
//
// Set unwait priority adjustment parameters.
//
ASSERT(Increment >= 0);
Thread->AdjustIncrement = (SCHAR)Increment; Thread->AdjustReason = (UCHAR)AdjustUnwait;
//
// Ready the thread for execution.
//
KiReadyThread(Thread); return; }
VOID FASTCALL KiWaitTest ( IN PVOID Object, IN KPRIORITY Increment )
/*++
Routine Description:
This function tests if a wait can be satisfied when an object attains a state of signaled. If a wait can be satisfied, then the subject thread is unwaited with a completion status that is the WaitKey of the wait block from the object wait list. As many waits as possible are satisfied.
Arguments:
Object - Supplies a pointer to a dispatcher object.
Return Value:
None.
--*/
{
PKEVENT Event; PLIST_ENTRY ListHead; PRKTHREAD Thread; PRKWAIT_BLOCK WaitBlock; PLIST_ENTRY WaitEntry; NTSTATUS WaitStatus;
//
// As long as the signal state of the specified object is Signaled and
// there are waiters in the object wait list, then try to satisfy a wait.
//
Event = (PKEVENT)Object; ListHead = &Event->Header.WaitListHead; WaitEntry = ListHead->Flink; while ((Event->Header.SignalState > 0) && (WaitEntry != ListHead)) {
WaitBlock = CONTAINING_RECORD(WaitEntry, KWAIT_BLOCK, WaitListEntry); Thread = WaitBlock->Thread; WaitStatus = STATUS_KERNEL_APC;
//
// N.B. The below code only satisfies the wait for wait any types.
// Wait all types are satisfied in the wait code itself. This
// is done with a eye to the future when the dispatcher lock is
// split into a lock per waitable object type and a scheduling
// state lock. For now, a kernel APC is simulated for wait all
// types.
//
if (WaitBlock->WaitType == WaitAny) { WaitStatus = (NTSTATUS)WaitBlock->WaitKey; KiWaitSatisfyAny((PKMUTANT)Event, Thread); }
KiUnwaitThread(Thread, WaitStatus, Increment); WaitEntry = ListHead->Flink; }
return; }
|