301 lines
7.2 KiB
C
301 lines
7.2 KiB
C
/*++
|
||
|
||
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
|