KeWaitForMultipleObjects函数分析之逻辑结构
KeWaitForMultipleObjects
do {
//
// Test to determine if a kernel APC is pending.
//
// If a kernel APC is pending, the special APC disable count is zero,
// and the previous IRQL was less than APC_LEVEL, then a kernel APC
// was queued by another processor just after IRQL was raised to
// DISPATCH_LEVEL, but before the dispatcher database was locked.
//
// N.B. that this can only happen in a multiprocessor system.
//
第一章:
if (Thread->ApcState.KernelApcPending &&
第一章:第0部分:
} else {
第一章:第一部分:
//
// Construct wait blocks and check to determine if the wait is
// already satisfied. If the wait is satisfied, then perform
// wait completion and return. Else put current thread in a wait
// state if an explicit timeout value of zero is not specified.
//
Index = 0;
if (WaitType == WaitAny) {
do {
//
// Test if wait can be satisfied immediately.
//测试是否能立即满足条件,如果立即满足,则退出函数。
Index += 1;
} while(Index < Count);
} else {
do {
//
// Test if wait can be satisfied.
//测试是否能立即满足条件,如果立即满足,则退出函数。
Index += 1;
} while(Index < Count);
//
// If all objects have been scanned, then satisfy the wait.
//
if (Index == Count) {
WaitBlock = &WaitBlockArray[0];
do {
Objectx = (PKMUTANT)WaitBlock->Object;
KiWaitSatisfyAny(Objectx, Thread);
WaitBlock = WaitBlock->NextWaitBlock;
} while (WaitBlock != &WaitBlockArray[0]);
WaitStatus = (NTSTATUS)Thread->WaitStatus;
goto NoWait;
}
} //if (WaitType == WaitAny) { 结束
第一章:第二部分:
第二部分A:
//
// Test for alert pending.
//
TestForAlertPending(Alertable);
//
// Check to determine if a timeout value is specified.
//
if (ARGUMENT_PRESENT(Timeout)) {
//
// If the timeout value is zero, then return immediately without
// waiting.
//
if (Timeout->QuadPart == 0) {
WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
goto NoWait;
}
}
第二部分B:
//
// Insert wait blocks in object wait lists.
//
WaitBlock = &WaitBlockArray[0];
do {
Objectx = (PKMUTANT)WaitBlock->Object;
InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry);
WaitBlock = WaitBlock->NextWaitBlock;
} while (WaitBlock != &WaitBlockArray[0]);
第二部分C:
//
// If the current thread is processing a queue entry, then attempt
// to activate another thread that is blocked on the queue object.
//
Queue = Thread->Queue;
if (Queue != NULL) {
KiActivateWaiterQueue(Queue);
}
第二部分D:
//
// Set the thread wait parameters, set the thread dispatcher state
// to Waiting, and insert the thread in the wait list.
//
CurrentPrcb = KeGetCurrentPrcb();
Thread->State = Waiting;
if (StackSwappable != FALSE) {
InsertTailList(&CurrentPrcb->WaitListHead, &Thread->WaitListEntry);
}
第二部分E:
//
// Set swap busy for the current thread, unlock the dispatcher
// database, and switch to a new thread.
//
// Control is returned at the original IRQL.
//
ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
KiSetContextSwapBusy(Thread);
KiUnlockDispatcherDatabaseFromSynchLevel();
WaitStatus = (NTSTATUS)KiSwapThread(Thread, CurrentPrcb);
第二部分F: KiSwapThread函数返回了,说明满足了条件,可以返回了。 return WaitStatus;
//
// If the thread was not awakened to deliver a kernel mode APC,
// then return the wait status.
//
if (WaitStatus != STATUS_KERNEL_APC) {
return WaitStatus;
}
if (ARGUMENT_PRESENT(Timeout)) {
//
// Reduce the amount of time remaining before timeout occurs.
//
Timeout = KiComputeWaitInterval(OriginalTime,
&DueTime,
&NewTime);
}
} //if (Thread->ApcState.KernelApcPending && 结束
第二章:
//
// Raise IRQL to SYNCH level, initialize the thread local variables,
// and lock the dispatcher database.
//
WaitStart:
Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
InitializeWaitMultiple();
KiLockDispatcherDatabaseAtSynchLevel();
} while (TRUE);