|
|
/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
sleep.c
Abstract:
This handles sleep requests on the part of the interpreter
Author:
Stephane Plante (splante)
Environment:
NT Kernel Mode Driver only
NB: Win9x can run this code also, but they will choose not do so.
--*/
#include "pch.h"
VOID SleepQueueDpc( PKDPC Dpc, PVOID Context, PVOID Argument1, PVOID Argument2 ) /*++
Routine Description:
This routine is fired when a timer event occurs
Arguments:
Dpc - The DPC that was fired Context - Not used Argument1 - Time.LowPart -- Not used Argument2 - Time.HighPart -- Not used
Return Value:
VOID --*/ { LARGE_INTEGER currentTime; LARGE_INTEGER dueTime; LIST_ENTRY localList; PLIST_ENTRY listEntry; PSLEEP sleepItem;
UNREFERENCED_PARAMETER( Dpc ); UNREFERENCED_PARAMETER( Context ); UNREFERENCED_PARAMETER( Argument1 ); UNREFERENCED_PARAMETER( Argument2 );
//
// Initialize the local list. Contrary to what the docs say, this code
// can be called from any IRQL (as long as the mem is resident)
//
InitializeListHead(&localList);
//
// Acquire the lock, since we must remove the things from the list
// under some kind of protection.
//
AcquireMutex(&gmutSleep);
//
// Find the correct time. This *must* be done after we are acquire the
// lock because there might be a long delay between trying to acquire
// the lock and actually getting it
//
currentTime.QuadPart = KeQueryInterruptTime();
//
// Loop until we are done
//
while (!IsListEmpty(&SleepQueue)) {
//
// Obtain the first element in the global list again
//
sleepItem = CONTAINING_RECORD(SleepQueue.Flink, SLEEP, ListEntry);
//
// Should the current item be removed?
//
if (sleepItem->SleepTime.QuadPart > currentTime.QuadPart) {
//
// No, so we need to set the timer to take care of this request
//
dueTime.QuadPart = currentTime.QuadPart - sleepItem->SleepTime.QuadPart; KeSetTimer( &SleepTimer, dueTime, &SleepDpc ); break;
}
//
// Yes, so remove it
//
listEntry = RemoveHeadList(&SleepQueue);
//
// Now, add the entry to the next queue
//
InsertTailList(&localList, listEntry);
}
//
// Done with lock. This may cause another DPC to process more elements
//
ReleaseMutex(&gmutSleep);
//
// At this point, we are free to remove items from the local list and
// try to do work on them.
//
while (!IsListEmpty(&localList)) {
//
// Remove the first element from the local list
//
listEntry = RemoveHeadList(&localList); sleepItem = CONTAINING_RECORD(listEntry, SLEEP, ListEntry);
//
// Force the interpreter to run
//
RestartContext(sleepItem->Context, (BOOLEAN)((sleepItem->Context->dwfCtxt & CTXTF_ASYNC_EVAL) == 0)); } }
#ifdef LOCKABLE_PRAGMA
#pragma ACPI_LOCKABLE_DATA
#pragma ACPI_LOCKABLE_CODE
#endif
NTSTATUS LOCAL SleepQueueRequest( IN PCTXT Context, IN ULONG SleepTime ) /*++
Routine Description:
This routine is responsible for adding the sleep request to the system queue for pending sleep requests
Arguments:
Context - The current execution context SleepTime - The amount of sleep time, in MilliSeconds
Rreturn Value:
NTSTATUS
--*/ { TRACENAME("SLEEPQUEUEREQUEST") BOOLEAN timerSet = FALSE; NTSTATUS status; PLIST_ENTRY listEntry; PSLEEP currentSleep; PSLEEP listSleep; ULONGLONG currentTime; LARGE_INTEGER dueTime;
ENTER(2, ("SleepQueueRequest(Context=%x,SleepTime=%d)\n", Context, SleepTime) );
status = PushFrame(Context, SIG_SLEEP, sizeof(SLEEP), ProcessSleep, ¤tSleep);
if (NT_SUCCESS(status)) { //
// The first step is acquire the timer lock, since we must protect it
//
AcquireMutex(&gmutSleep);
//
// Next step is to determine time at which we should wake up this
// context
//
currentTime = KeQueryInterruptTime(); currentSleep->SleepTime.QuadPart = currentTime + ((ULONGLONG)SleepTime*10000); currentSleep->Context = Context;
//
// At this point, it becomes easier to walk the list backwards
//
listEntry = &SleepQueue; while (listEntry->Blink != &SleepQueue) {
listSleep = CONTAINING_RECORD(listEntry->Blink, SLEEP, ListEntry);
//
// Do we have to add the new element after the current one?
//
if (currentSleep->SleepTime.QuadPart >= listSleep->SleepTime.QuadPart) {
//
// Yes
//
InsertHeadList( &(listSleep->ListEntry), &(currentSleep->ListEntry) );
break; }
//
// Next entry
//
listEntry = listEntry->Blink; }
//
// Look to see if we got to the head
//
if (listEntry->Blink == &SleepQueue) {
//
// If we get to this point, it is because we have
// gone all the around the list. If we add to the
// front of the list, we must set the timer
//
InsertHeadList(&SleepQueue, ¤tSleep->ListEntry); dueTime.QuadPart = currentTime - currentSleep->SleepTime.QuadPart; timerSet = KeSetTimer( &SleepTimer, dueTime, &SleepDpc ); } //
// Done with the lock
//
ReleaseMutex(&gmutSleep); }
EXIT(2, ("SleepQueueReqest=%x (currentSleep=%x timerSet=%x)\n", status, currentSleep, timerSet) ); return status;
}
/***LP ProcessSleep - post processing of sleep
* * ENTRY * pctxt -> CTXT * psleep -> SLEEP * rc - status code * * EXIT-SUCCESS * returns STATUS_SUCCESS * EXIT-FAILURE * returns AMLIERR_ code */
NTSTATUS LOCAL ProcessSleep(PCTXT pctxt, PSLEEP psleep, NTSTATUS rc) { TRACENAME("PROCESSSLEEP")
ENTER(2, ("ProcessSleep(pctxt=%x,pbOp=%x,psleep=%x,rc=%x)\n", pctxt, pctxt->pbOp, psleep, rc));
ASSERT(psleep->FrameHdr.dwSig == SIG_SLEEP);
PopFrame(pctxt);
EXIT(2, ("ProcessSleep=%x\n", rc)); return rc; } //ProcessSleep
|