分类:
2008-10-13 16:11:10
NTSTATUS
STDCALL
KeDelayExecutionThread(KPROCESSOR_MODE WaitMode,
BOOLEAN Alertable,
PLARGE_INTEGER Interval)
{
PKWAIT_BLOCK TimerWaitBlock;
PKTIMER ThreadTimer;
PKTHREAD CurrentThread = KeGetCurrentThread();
NTSTATUS Status;
DPRINT("Entering KeDelayExecutionThread\n");
/* Check if the lock is already held */
if (CurrentThread->WaitNext) {
/* Lock is held, disable Wait Next */
DPRINT("Lock is held\n");
CurrentThread->WaitNext = FALSE;
} else {
/* Lock not held, acquire it */
DPRINT("Lock is not held, acquiring\n");
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
}
/* Use built-in Wait block */
TimerWaitBlock = &CurrentThread->WaitBlock[TIMER_WAIT_BLOCK];
/* Start Wait Loop */
do {
/* We are going to wait no matter what (that's the point), so test Alertability */
if (KiCheckAlertability(Alertable, CurrentThread, WaitMode, &Status))
break;
/* Set Timer */
ThreadTimer = &CurrentThread->Timer;
/* Setup the Wait Block */
CurrentThread->WaitBlockList = TimerWaitBlock;
TimerWaitBlock->Object = (PVOID)ThreadTimer;
TimerWaitBlock->Thread = CurrentThread;
TimerWaitBlock->WaitKey = (USHORT)STATUS_TIMEOUT;
TimerWaitBlock->WaitType = WaitAny;
TimerWaitBlock->NextWaitBlock = TimerWaitBlock;
/* Link the timer to this Wait Block */
InitializeListHead(&ThreadTimer->Header.WaitListHead);
InsertTailList(&ThreadTimer->Header.WaitListHead, &TimerWaitBlock->WaitListEntry);
/* Insert the Timer into the Timer Lists and enable it */
if (!KiInsertTimer(ThreadTimer, *Interval)) {
/* FIXME: The timer already expired, we should find a new ready thread */
Status = STATUS_SUCCESS;
break;
}
/* Handle Kernel Queues */
if (CurrentThread->Queue) {
DPRINT("Waking Queue\n");
KiWakeQueue(CurrentThread->Queue);
}
/* Block the Thread */
DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable, WaitMode, KeGetCurrentThread());
KiBlockThread(&Status,
Alertable,
WaitMode,
DelayExecution);
/* Check if we were executing an APC or if we timed out */
if (Status != STATUS_KERNEL_APC) {
/* This is a good thing */
if (Status == STATUS_TIMEOUT) Status = STATUS_SUCCESS;
/* Return Status */
return Status;
}
DPRINT("Looping Again\n");
CurrentThread->WaitIrql = KeAcquireDispatcherDatabaseLock();
} while (TRUE);
/* Release the Lock, we are done */
DPRINT("Returning from KeDelayExecutionThread(), %x. Status: %d\n", KeGetCurrentThread(), Status);
KeReleaseDispatcherDatabaseLock(CurrentThread->WaitIrql);
return Status;
}