986 lines
28 KiB
C
986 lines
28 KiB
C
/*** sync.c - synchronization functions
|
|
*
|
|
* Copyright (c) 1996,1997 Microsoft Corporation
|
|
* Author: Michael Tsang (MikeTs)
|
|
* Created 04/16/97
|
|
*
|
|
* MODIFICATION HISTORY
|
|
*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef LOCKABLE_PRAGMA
|
|
#pragma ACPI_LOCKABLE_DATA
|
|
#pragma ACPI_LOCKABLE_CODE
|
|
#endif
|
|
|
|
/***LP AysncCallBack - Call back async function
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* rcCtxt - return status of the context
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID LOCAL AsyncCallBack(PCTXT pctxt, NTSTATUS rcCtxt)
|
|
{
|
|
TRACENAME("ASYNCCALLBACK")
|
|
PFNACB pfnAsyncCallBack;
|
|
PNSOBJ pnsObj;
|
|
POBJDATA pdataCallBack;
|
|
PVOID pvContext;
|
|
|
|
rcCtxt = ((rcCtxt == STATUS_SUCCESS) || (rcCtxt == AMLISTA_CONTINUE))?
|
|
rcCtxt: NTERR(rcCtxt);
|
|
|
|
if (pctxt->pnctxt != NULL)
|
|
{
|
|
//
|
|
// We have a nested context here. We are calling back the nested
|
|
// context, not the parent context.
|
|
//
|
|
pfnAsyncCallBack = pctxt->pnctxt->pfnAsyncCallBack;
|
|
pnsObj = pctxt->pnctxt->pnsObj;
|
|
pdataCallBack = pctxt->pnctxt->pdataCallBack;
|
|
pvContext = pctxt->pnctxt->pvContext;
|
|
}
|
|
else
|
|
{
|
|
pfnAsyncCallBack = pctxt->pfnAsyncCallBack;
|
|
pnsObj = pctxt->pnsObj;
|
|
pdataCallBack = pctxt->pdataCallBack;
|
|
pvContext = pctxt->pvContext;
|
|
}
|
|
|
|
ENTER(2, ("AsyncCallBack(pctxt=%x,rc=%x,Obj=%s,pdataCallBack=%x,pvContext=%x)\n",
|
|
pctxt, rcCtxt, GetObjectPath(pnsObj), pdataCallBack, pvContext));
|
|
|
|
|
|
if (pfnAsyncCallBack == (PFNACB)EvalMethodComplete)
|
|
{
|
|
LOGSCHEDEVENT('DONE', (ULONG_PTR)pnsObj, (ULONG_PTR)rcCtxt,
|
|
(ULONG_PTR)pvContext);
|
|
EvalMethodComplete(pctxt, rcCtxt, (PSYNCEVENT)pvContext);
|
|
}
|
|
else if (pfnAsyncCallBack != NULL)
|
|
{
|
|
if (rcCtxt == AMLISTA_CONTINUE)
|
|
{
|
|
//
|
|
// We are not done yet, restart the AsyncEval context using
|
|
// current thread.
|
|
//
|
|
ASSERT(pctxt->dwfCtxt & CTXTF_ASYNC_EVAL);
|
|
RestartContext(pctxt, FALSE);
|
|
}
|
|
else
|
|
{
|
|
LOGSCHEDEVENT('ASCB', (ULONG_PTR)pnsObj, (ULONG_PTR)rcCtxt,
|
|
(ULONG_PTR)pvContext);
|
|
pfnAsyncCallBack(pnsObj, rcCtxt, pdataCallBack, pvContext);
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("AsyncCallBack!\n"));
|
|
} //AsyncCallBack
|
|
|
|
/***LP EvalMethodComplete - eval completion callback
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* rc - evaluation status
|
|
* pse -> SyncEvent
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID EXPORT EvalMethodComplete(PCTXT pctxt, NTSTATUS rc, PSYNCEVENT pse)
|
|
{
|
|
TRACENAME("EVALMETHODCOMPLETE")
|
|
ENTER(2, ("EvalMethodComplete(pctxt=%x,rc=%x,pse=%x\n", pctxt, rc, pse));
|
|
|
|
pse->rcCompleted = rc;
|
|
pse->pctxt = pctxt;
|
|
KeSetEvent(&pse->Event, 0, FALSE);
|
|
|
|
EXIT(2, ("EvalMethodComplete!\n"));
|
|
} //EvalMethodComplete
|
|
|
|
/***LP SyncEvalObject - evaluate an object synchronously
|
|
*
|
|
* ENTRY
|
|
* pns -> object
|
|
* pdataResult -> to hold result data
|
|
* icArgs - number of arguments to the method object
|
|
* pdataArgs -> argument array
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL SyncEvalObject(PNSOBJ pns, POBJDATA pdataResult, int icArgs,
|
|
POBJDATA pdataArgs)
|
|
{
|
|
TRACENAME("SYNCEVALOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
SYNCEVENT seEvalObj;
|
|
|
|
ENTER(2, ("SyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x)\n",
|
|
GetObjectPath(pns), pdataResult, icArgs, pdataArgs));
|
|
|
|
KeInitializeEvent(&seEvalObj.Event, SynchronizationEvent, FALSE);
|
|
|
|
if (KeGetCurrentThread() == gReadyQueue.pkthCurrent)
|
|
{
|
|
if (!(gReadyQueue.pctxtCurrent->dwfCtxt & CTXTF_ASYNC_EVAL))
|
|
{
|
|
LOGSCHEDEVENT('NSYN', (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)pns,
|
|
0);
|
|
//
|
|
// Somebody is re-entering with the active context thread, so we
|
|
// must nest using the existing active context.
|
|
//
|
|
if ((rc = NestAsyncEvalObject(pns, pdataResult, icArgs, pdataArgs,
|
|
(PFNACB)EvalMethodComplete,
|
|
&seEvalObj, FALSE)) ==
|
|
AMLISTA_PENDING)
|
|
{
|
|
rc = RestartContext(gReadyQueue.pctxtCurrent, FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("SyncEvalObject: cannot nest a SyncEval on an async. context"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LOGSCHEDEVENT('SYNC', (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)pns, 0);
|
|
rc = AsyncEvalObject(pns, pdataResult, icArgs, pdataArgs,
|
|
(PFNACB)EvalMethodComplete, &seEvalObj, FALSE);
|
|
}
|
|
|
|
if (KeGetCurrentIrql() < DISPATCH_LEVEL)
|
|
{
|
|
while (rc == AMLISTA_PENDING)
|
|
{
|
|
if ((rc = KeWaitForSingleObject(&seEvalObj.Event, Executive,
|
|
KernelMode, FALSE,
|
|
(PLARGE_INTEGER)NULL)) ==
|
|
STATUS_SUCCESS)
|
|
{
|
|
if (seEvalObj.rcCompleted == AMLISTA_CONTINUE)
|
|
{
|
|
rc = RestartContext(seEvalObj.pctxt, FALSE);
|
|
}
|
|
else
|
|
{
|
|
rc = AMLIERR(seEvalObj.rcCompleted);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("SyncEvalObject: object synchronization failed (rc=%x)",
|
|
rc));
|
|
}
|
|
}
|
|
}
|
|
else if (rc == AMLISTA_PENDING)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("SyncEvalObject: object %s being evaluated at IRQL >= DISPATCH_LEVEL",
|
|
GetObjectPath(pns)));
|
|
}
|
|
|
|
EXIT(2, ("SyncEvalObject=%x\n", rc));
|
|
return rc;
|
|
} //SyncEvalObject
|
|
|
|
/***LP AsyncEvalObject - evaluate an object asynchronously
|
|
*
|
|
* ENTRY
|
|
* pns -> object
|
|
* pdataResult -> to hold result data
|
|
* icArgs - number of arguments to the method object
|
|
* pdataArgs -> argument array
|
|
* pfnAsyncCallBack -> completion callback function
|
|
* pvContext -> context data
|
|
* fAsync - TRUE if this is from an AsyncEval call
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL AsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult, int icArgs,
|
|
POBJDATA pdataArgs, PFNACB pfnAsyncCallBack,
|
|
PVOID pvContext, BOOLEAN fAsync)
|
|
{
|
|
TRACENAME("ASYNCEVALOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PCTXT pctxt = NULL;
|
|
|
|
ENTER(2, ("AsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x,pvContext=%x,fAsync=%x)\n",
|
|
GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
|
|
pfnAsyncCallBack, pvContext, fAsync));
|
|
|
|
LOGSCHEDEVENT('ASYN', (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)pns, 0);
|
|
if ((rc = NewContext(&pctxt)) == STATUS_SUCCESS)
|
|
{
|
|
BOOLEAN fQueueContext = FALSE;
|
|
|
|
pctxt->pnsObj = pns;
|
|
pctxt->pnsScope = pns;
|
|
pctxt->pfnAsyncCallBack = pfnAsyncCallBack;
|
|
pctxt->pdataCallBack = pdataResult;
|
|
pctxt->pvContext = pvContext;
|
|
|
|
ACPIWMILOGEVENT((1,
|
|
EVENT_TRACE_TYPE_START,
|
|
GUID_List[AMLI_LOG_GUID],
|
|
"Object = %s",
|
|
GetObjectPath(pctxt->pnsObj)
|
|
));
|
|
|
|
if (fAsync)
|
|
{
|
|
pctxt->dwfCtxt |= CTXTF_ASYNC_EVAL;
|
|
}
|
|
|
|
if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
|
|
{
|
|
if ((rc = PushCall(pctxt, pns, &pctxt->Result)) == STATUS_SUCCESS)
|
|
{
|
|
PCALL pcall;
|
|
|
|
ASSERT(((PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd)->dwSig ==
|
|
SIG_CALL);
|
|
|
|
pcall = (PCALL)pctxt->LocalHeap.pbHeapEnd;
|
|
|
|
if (icArgs != pcall->icArgs)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INCORRECT_NUMARG,
|
|
("AsyncEvalObject: incorrect number of arguments (NumArg=%d,Expected=%d)",
|
|
icArgs, pcall->icArgs));
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger &
|
|
(DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PRINTF("\n" MODNAME ": %08x: %s(",
|
|
KeGetCurrentThread(), GetObjectPath(pns));
|
|
}
|
|
#endif
|
|
//
|
|
// Copying arguments to the call frame manually will skip
|
|
// the argument parsing stage.
|
|
//
|
|
for (pcall->iArg = 0; pcall->iArg < icArgs; ++pcall->iArg)
|
|
{
|
|
if ((rc = DupObjData(pctxt->pheapCurrent,
|
|
&pcall->pdataArgs[pcall->iArg],
|
|
&pdataArgs[pcall->iArg])) !=
|
|
STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger &
|
|
(DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PrintObject(&pdataArgs[pcall->iArg]);
|
|
if (pcall->iArg + 1 < icArgs)
|
|
{
|
|
PRINTF(",");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger &
|
|
(DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PRINTF(")\n");
|
|
}
|
|
#endif
|
|
//
|
|
// Skip the argument parsing stage.
|
|
//
|
|
pcall->FrameHdr.dwfFrame = 2;
|
|
fQueueContext = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (((rc = PushPost(pctxt, ProcessEvalObj, (ULONG_PTR)pns, 0,
|
|
&pctxt->Result)) == STATUS_SUCCESS) &&
|
|
((rc = ReadObject(pctxt, &pns->ObjData, &pctxt->Result)) !=
|
|
AMLISTA_PENDING))
|
|
{
|
|
fQueueContext = TRUE;
|
|
}
|
|
|
|
if (fQueueContext)
|
|
{
|
|
rc = RestartContext(pctxt, FALSE);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we never queue the context because we bailed,
|
|
// we must free it.
|
|
//
|
|
FreeContext(pctxt);
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("AsyncEvalObject=%x\n", rc));
|
|
return rc;
|
|
} //AsyncEvalObject
|
|
|
|
/***LP NestAsyncEvalObject - evaluate an object asynchronously using the
|
|
* current context
|
|
*
|
|
* ENTRY
|
|
* pns -> object
|
|
* pdataResult -> to hold result data
|
|
* icArgs - number of arguments to the method object
|
|
* pdataArgs -> argument array
|
|
* pfnAsyncCallBack -> completion callback function
|
|
* pvContext -> context data
|
|
* fAsync - TRUE if this is from an AsyncEval call
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
NTSTATUS LOCAL NestAsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult,
|
|
int icArgs, POBJDATA pdataArgs,
|
|
PFNACB pfnAsyncCallBack, PVOID pvContext,
|
|
BOOLEAN fAsync)
|
|
{
|
|
TRACENAME("NESTASYNCEVALOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PCTXT pctxt = NULL;
|
|
|
|
ENTER(2, ("NestAsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x,pvContext=%x,fAsync=%x)\n",
|
|
GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
|
|
pfnAsyncCallBack, pvContext, fAsync));
|
|
|
|
//
|
|
// Context must be the current one in progress.
|
|
//
|
|
ASSERT(gReadyQueue.pkthCurrent == KeGetCurrentThread());
|
|
pctxt = gReadyQueue.pctxtCurrent;
|
|
|
|
LOGSCHEDEVENT('NASY', (ULONG_PTR)pns, (ULONG_PTR)pfnAsyncCallBack,
|
|
(ULONG_PTR)pctxt);
|
|
if ((pctxt != NULL) &&
|
|
(gReadyQueue.pkthCurrent == KeGetCurrentThread()))
|
|
{
|
|
PNESTEDCTXT pnctxt;
|
|
|
|
rc = PushFrame(pctxt, SIG_NESTEDCTXT, sizeof(NESTEDCTXT),
|
|
ParseNestedContext, &pnctxt);
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
pnctxt->pnsObj = pns;
|
|
pnctxt->pnsScope = pns;
|
|
pnctxt->pfnAsyncCallBack = pfnAsyncCallBack;
|
|
pnctxt->pdataCallBack = pdataResult;
|
|
pnctxt->pvContext = pvContext;
|
|
pnctxt->pnctxtPrev = pctxt->pnctxt;
|
|
pnctxt->dwfPrevCtxt = pctxt->dwfCtxt;
|
|
pctxt->pnctxt = pnctxt;
|
|
pctxt->dwfCtxt |= CTXTF_NEST_EVAL;
|
|
|
|
if (fAsync)
|
|
{
|
|
pctxt->dwfCtxt |= CTXTF_ASYNC_EVAL;
|
|
}
|
|
else
|
|
{
|
|
pctxt->dwfCtxt &= ~CTXTF_ASYNC_EVAL;
|
|
}
|
|
|
|
if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
|
|
{
|
|
if ((rc = PushCall(pctxt, pns, &pnctxt->Result)) ==
|
|
STATUS_SUCCESS)
|
|
{
|
|
PCALL pcall;
|
|
|
|
ASSERT(((PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd)->dwSig ==
|
|
SIG_CALL);
|
|
|
|
pcall = (PCALL)pctxt->LocalHeap.pbHeapEnd;
|
|
|
|
if (icArgs != pcall->icArgs)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INCORRECT_NUMARG,
|
|
("NestAsyncEvalObject: incorrect number of arguments (NumArg=%d,Expected=%d)",
|
|
icArgs, pcall->icArgs));
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger &
|
|
(DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PRINTF("\n" MODNAME ": %s(", GetObjectPath(pns));
|
|
}
|
|
#endif
|
|
//
|
|
// Copying arguments to the call frame manually will
|
|
// skip the argument parsing stage.
|
|
//
|
|
for (pcall->iArg = 0;
|
|
pcall->iArg < icArgs;
|
|
++pcall->iArg)
|
|
{
|
|
if ((rc = DupObjData(pctxt->pheapCurrent,
|
|
&pcall->pdataArgs[pcall->iArg],
|
|
&pdataArgs[pcall->iArg])) !=
|
|
STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger &
|
|
(DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PrintObject(&pdataArgs[pcall->iArg]);
|
|
if (pcall->iArg + 1 < icArgs)
|
|
{
|
|
PRINTF(",");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PRINTF(")\n");
|
|
}
|
|
#endif
|
|
//
|
|
// Skip the argument parsing stage.
|
|
//
|
|
pcall->FrameHdr.dwfFrame = 2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Delay the evaluate the object.
|
|
//
|
|
rc = PushPost(pctxt, ProcessEvalObj, (ULONG_PTR)pns, 0,
|
|
&pnctxt->Result);
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
ReadObject(pctxt, &pns->ObjData, &pnctxt->Result);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Always return AMLISTA_PENDING.
|
|
//
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We cannot use the nested version --- fail the call
|
|
//
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("NestAsyncEvalObject: pns=%08x No current context\n",
|
|
pns));
|
|
}
|
|
|
|
EXIT(2, ("NestAsyncEvalObject=%x\n", rc));
|
|
return rc;
|
|
} //NestAsyncEvalObject
|
|
|
|
/***LP ProcessEvalObj - post process of EvalObj
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* ppost -> POST
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL ProcessEvalObj(PCTXT pctxt, PPOST ppost, NTSTATUS rc)
|
|
{
|
|
TRACENAME("PROCESSEVALOBJ")
|
|
|
|
ENTER(2, ("ProcessEvalObj(pctxt=%x,pbOp=%x,ppost=%x,rc=%x)\n",
|
|
pctxt, pctxt->pbOp, ppost, rc));
|
|
|
|
ASSERT(ppost->FrameHdr.dwSig == SIG_POST);
|
|
#ifdef DEBUGGER
|
|
if ((gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES)) &&
|
|
(rc == STATUS_SUCCESS))
|
|
{
|
|
PRINTF("\n" MODNAME ": EvalObject(%s)=",
|
|
GetObjectPath((PNSOBJ)ppost->uipData1));
|
|
DumpObject(ppost->pdataResult, NULL, 0);
|
|
PRINTF("\n");
|
|
}
|
|
#else
|
|
DEREF(ppost);
|
|
#endif
|
|
|
|
PopFrame(pctxt);
|
|
|
|
EXIT(2, ("ProcessEvalObj=%x\n", rc));
|
|
return rc;
|
|
} //ProcessEvalObj
|
|
|
|
/***LP TimeoutCallback - DPC callback for Mutex/Event timeout
|
|
*
|
|
* ENTRY
|
|
* pkdpc -> DPC
|
|
* pctxt -> CTXT
|
|
* SysArg1 - not used
|
|
* SysArg2 - not used
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID TimeoutCallback(PKDPC pkdpc, PCTXT pctxt, PVOID SysArg1, PVOID SysArg2)
|
|
{
|
|
TRACENAME("TIMEOUTCALLBACK")
|
|
|
|
ENTER(2, ("TimeoutCallback(pkdpc=%x,pctxt=%x,SysArg1=%x,SysArg2=%x)\n",
|
|
pkdpc, pctxt, SysArg1, SysArg2));
|
|
|
|
DEREF(pkdpc);
|
|
DEREF(SysArg1);
|
|
DEREF(SysArg2);
|
|
|
|
if (pctxt->dwfCtxt & CTXTF_TIMER_PENDING)
|
|
{
|
|
//
|
|
// Timer has timed out.
|
|
//
|
|
pctxt->dwfCtxt &= ~CTXTF_TIMER_PENDING;
|
|
pctxt->dwfCtxt |= CTXTF_TIMEOUT;
|
|
|
|
//
|
|
// Remove from waiting queue.
|
|
//
|
|
ASSERT(pctxt->pplistCtxtQueue != NULL);
|
|
ListRemoveEntry(&((PCTXT)pctxt)->listQueue,
|
|
((PCTXT)pctxt)->pplistCtxtQueue);
|
|
pctxt->pplistCtxtQueue = NULL;
|
|
|
|
RestartContext(pctxt,
|
|
(BOOLEAN)((pctxt->dwfCtxt & CTXTF_ASYNC_EVAL) == 0));
|
|
}
|
|
else if (pctxt->dwfCtxt & CTXTF_TIMER_DISPATCH)
|
|
{
|
|
//
|
|
// Timer couldn't be cancelled while queuing context. Since the
|
|
// queuing was aborted, we continue the queuing here.
|
|
//
|
|
pctxt->dwfCtxt &= ~CTXTF_TIMER_DISPATCH;
|
|
RestartContext(pctxt,
|
|
(BOOLEAN)((pctxt->dwfCtxt & CTXTF_ASYNC_EVAL) == 0));
|
|
}
|
|
else
|
|
{
|
|
// Should not be here
|
|
ASSERT(pctxt->dwfCtxt & (CTXTF_TIMER_PENDING | CTXTF_TIMER_DISPATCH));
|
|
}
|
|
|
|
EXIT(2, ("TimeoutCallback!\n"));
|
|
} //TimeoutCallback
|
|
|
|
/***LP QueueContext - queue control method context
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* wTimeOut - timeout in ms
|
|
* pplist -> list to insert created context
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID LOCAL QueueContext(PCTXT pctxt, USHORT wTimeout, PPLIST pplist)
|
|
{
|
|
TRACENAME("QUEUECONTEXT")
|
|
|
|
ENTER(2, ("QueueContext(pctxt=%x,Timeout=%d,pplist=%x)\n",
|
|
pctxt, wTimeout, pplist));
|
|
|
|
AcquireMutex(&gReadyQueue.mutCtxtQ);
|
|
|
|
//
|
|
// make sure this context isn't queued somewhere else.
|
|
//
|
|
ASSERT(pctxt->pplistCtxtQueue == NULL);
|
|
ASSERT(pplist != NULL);
|
|
ASSERT(!(pctxt->dwfCtxt &
|
|
(CTXTF_TIMER_PENDING | CTXTF_TIMER_DISPATCH | CTXTF_TIMEOUT |
|
|
CTXTF_READY)));
|
|
ListInsertTail(&pctxt->listQueue, pplist);
|
|
pctxt->pplistCtxtQueue = pplist;
|
|
|
|
if (wTimeout != 0xffff)
|
|
{
|
|
LARGE_INTEGER liTimeout;
|
|
|
|
pctxt->dwfCtxt |= CTXTF_TIMER_PENDING;
|
|
liTimeout.QuadPart = (INT_PTR)(-10000*(INT_PTR)wTimeout);
|
|
KeSetTimer(&pctxt->Timer, liTimeout, &pctxt->Dpc);
|
|
}
|
|
|
|
ReleaseMutex(&gReadyQueue.mutCtxtQ);
|
|
|
|
EXIT(2, ("QueueContext!\n"));
|
|
} //QueueContext
|
|
|
|
/***LP DequeueAndReadyContext - dequeue context and insert to ready queue
|
|
*
|
|
* ENTRY
|
|
* pplist -> context list to dequeue from
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns pctxt
|
|
* EXIT-FAILURE
|
|
* returns NULL
|
|
*/
|
|
|
|
PCTXT LOCAL DequeueAndReadyContext(PPLIST pplist)
|
|
{
|
|
TRACENAME("DEQUEUEANDREADYCONTEXT")
|
|
PCTXT pctxt = NULL;
|
|
PLIST plist;
|
|
|
|
ENTER(2, ("DequeueAndReadyContext(pplist=%x)\n", pplist));
|
|
|
|
AcquireMutex(&gReadyQueue.mutCtxtQ);
|
|
if ((plist = ListRemoveHead(pplist)) != NULL)
|
|
{
|
|
pctxt = CONTAINING_RECORD(plist, CTXT, listQueue);
|
|
ASSERT(pctxt->dwSig == SIG_CTXT);
|
|
ASSERT(pctxt->pplistCtxtQueue == pplist);
|
|
pctxt->pplistCtxtQueue = NULL;
|
|
InsertReadyQueue(pctxt, TRUE);
|
|
}
|
|
|
|
ReleaseMutex(&gReadyQueue.mutCtxtQ);
|
|
|
|
EXIT(2, ("DequeueAndReadyContext=%x\n", pctxt));
|
|
return pctxt;
|
|
} //DequeueAndReadyContext
|
|
|
|
/***LP AcquireASLMutex - acquire ASL mutex
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pm -> MUTEX structure
|
|
* wTimeOut - timeout in ms
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL AcquireASLMutex(PCTXT pctxt, PMUTEXOBJ pm, USHORT wTimeout)
|
|
{
|
|
TRACENAME("ACQUIREASLMUTEX")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(2, ("AcquireASLMutex(pctxt=%x,pm=%x,Timeout=%d)\n",
|
|
pctxt, pm, wTimeout));
|
|
|
|
if (pctxt->dwfCtxt & CTXTF_TIMEOUT)
|
|
{
|
|
pctxt->dwfCtxt &= ~CTXTF_TIMEOUT;
|
|
rc = AMLISTA_TIMEOUT;
|
|
}
|
|
else if (pm->dwSyncLevel < pctxt->dwSyncLevel)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_MUTEX_INVALID_LEVEL,
|
|
("AcquireASLMutex: invalid sync level"));
|
|
}
|
|
else if (pm->dwcOwned == 0)
|
|
{
|
|
PRESOURCE pres;
|
|
|
|
pres = NEWCROBJ(pctxt->pheapCurrent, sizeof(RESOURCE));
|
|
if (pres == NULL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("AcquireASLMutex: failed to allocate context resource"));
|
|
}
|
|
else
|
|
{
|
|
pres->dwResType = RESTYPE_MUTEX;
|
|
pres->pctxtOwner = pctxt;
|
|
pres->pvResObj = pm;
|
|
ListInsertHead(&pres->list, &pctxt->plistResources);
|
|
|
|
pm->dwcOwned = 1;
|
|
pm->hOwner = (HANDLE)pres;
|
|
pctxt->dwSyncLevel = pm->dwSyncLevel;
|
|
}
|
|
}
|
|
else if (((PRESOURCE)pm->hOwner)->pctxtOwner == pctxt)
|
|
{
|
|
pm->dwcOwned++;
|
|
}
|
|
else
|
|
{
|
|
QueueContext(pctxt, wTimeout, &pm->plistWaiters);
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
|
|
EXIT(2, ("AcquireASLMutex=%x (CurrentOwner=%x)\n", rc, pm->hOwner));
|
|
return rc;
|
|
} //AcquireASLMutex
|
|
|
|
/***LP ReleaseASLMutex - release ASL mutex
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pm -> MUTEX structure
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL ReleaseASLMutex(PCTXT pctxt, PMUTEXOBJ pm)
|
|
{
|
|
TRACENAME("RELEASEASLMUTEX")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(2, ("ReleaseASLMutex(pctxt=%x,pm=%x)\n", pctxt, pm));
|
|
|
|
if (pm->dwcOwned == 0)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_MUTEX_NOT_OWNED,
|
|
("ReleaseASLMutex: Mutex is not owned"));
|
|
}
|
|
else
|
|
{
|
|
PRESOURCE pres;
|
|
|
|
pres = (PRESOURCE)pm->hOwner;
|
|
if ((pres == NULL) || (pres->pctxtOwner != pctxt))
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_MUTEX_NOT_OWNER,
|
|
("ReleaseASLMutex: Mutex is owned by a different owner"));
|
|
}
|
|
else if (pm->dwSyncLevel > pctxt->dwSyncLevel)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_MUTEX_INVALID_LEVEL,
|
|
("ReleaseASLMutex: invalid sync level (MutexLevel=%d,CurrentLevel=%x",
|
|
pm->dwSyncLevel, pctxt->dwSyncLevel));
|
|
}
|
|
else
|
|
{
|
|
pctxt->dwSyncLevel = pm->dwSyncLevel;
|
|
pm->dwcOwned--;
|
|
if (pm->dwcOwned == 0)
|
|
{
|
|
ListRemoveEntry(&pres->list, &pctxt->plistResources);
|
|
FREECROBJ(pres);
|
|
pm->hOwner = NULL;
|
|
DequeueAndReadyContext(&pm->plistWaiters);
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("ReleaseASLMutex=%x\n", rc));
|
|
return rc;
|
|
} //ReleaseASLMutex
|
|
|
|
/***LP WaitASLEvent - wait ASL event
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pe -> EVENT structure
|
|
* wTimeOut - timeout in ms
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WaitASLEvent(PCTXT pctxt, PEVENTOBJ pe, USHORT wTimeout)
|
|
{
|
|
TRACENAME("WAITASLEVENT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(2, ("WaitASLEvent(pctxt=%x,pe=%x,Timeout=%d)\n", pctxt, pe, wTimeout));
|
|
|
|
if (pctxt->dwfCtxt & CTXTF_TIMEOUT)
|
|
{
|
|
pctxt->dwfCtxt &= ~CTXTF_TIMEOUT;
|
|
rc = AMLISTA_TIMEOUT;
|
|
}
|
|
else if (pe->dwcSignaled > 0)
|
|
{
|
|
pe->dwcSignaled--;
|
|
}
|
|
else
|
|
{
|
|
QueueContext(pctxt, wTimeout, &pe->plistWaiters);
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
|
|
EXIT(2, ("WaitASLEvent=%x\n", rc));
|
|
return rc;
|
|
} //WaitASLEvent
|
|
|
|
/***LP ResetASLEvent - reset ASL event
|
|
*
|
|
* ENTRY
|
|
* pe -> EVENT structure
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID LOCAL ResetASLEvent(PEVENTOBJ pe)
|
|
{
|
|
TRACENAME("RESETASLEVENT")
|
|
|
|
ENTER(2, ("ResetASLEvent(pe=%x)\n", pe));
|
|
|
|
pe->dwcSignaled = 0;
|
|
|
|
EXIT(2, ("ResetASLEvent!\n"));
|
|
} //ResetASLEvent
|
|
|
|
/***LP SignalASLEvent - signal ASL event
|
|
*
|
|
* ENTRY
|
|
* pe -> EVENT structure
|
|
*
|
|
* EXIT
|
|
* None
|
|
*/
|
|
|
|
VOID LOCAL SignalASLEvent(PEVENTOBJ pe)
|
|
{
|
|
TRACENAME("SIGNALASLEVENT")
|
|
|
|
ENTER(2, ("SignalASLEvent(pe=%x)\n", pe));
|
|
|
|
if (DequeueAndReadyContext(&pe->plistWaiters) == NULL)
|
|
{
|
|
pe->dwcSignaled++;
|
|
}
|
|
|
|
EXIT(2, ("SignalASLEvent!\n"));
|
|
} //SignalASLEvent
|
|
|
|
/***LP SyncLoadDDB - load a DDB synchronously
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL SyncLoadDDB(PCTXT pctxt)
|
|
{
|
|
TRACENAME("SYNCLOADDDB")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(2, ("SyncLoadDDB(pctxt=%x)\n", pctxt));
|
|
|
|
if (KeGetCurrentThread() == gReadyQueue.pkthCurrent)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("SyncLoadDDB: cannot nest a SyncLoadDDB"));
|
|
pctxt->powner = NULL;
|
|
FreeContext(pctxt);
|
|
}
|
|
else if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("SyncLoadDDB: cannot SyncLoadDDB at IRQL >= DISPATCH_LEVEL"));
|
|
pctxt->powner = NULL;
|
|
FreeContext(pctxt);
|
|
}
|
|
else
|
|
{
|
|
SYNCEVENT seEvalObj;
|
|
|
|
KeInitializeEvent(&seEvalObj.Event, SynchronizationEvent, FALSE);
|
|
pctxt->pfnAsyncCallBack = (PFNACB)EvalMethodComplete;
|
|
pctxt->pvContext = &seEvalObj;
|
|
rc = RestartContext(pctxt, FALSE);
|
|
|
|
while (rc == AMLISTA_PENDING)
|
|
{
|
|
if ((rc = KeWaitForSingleObject(&seEvalObj.Event, Executive,
|
|
KernelMode, FALSE,
|
|
(PLARGE_INTEGER)NULL)) ==
|
|
STATUS_SUCCESS)
|
|
{
|
|
if (seEvalObj.rcCompleted == AMLISTA_CONTINUE)
|
|
{
|
|
rc = RestartContext(seEvalObj.pctxt, FALSE);
|
|
}
|
|
else
|
|
{
|
|
rc = AMLIERR(seEvalObj.rcCompleted);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("SyncLoadDDB: object synchronization failed (rc=%x)",
|
|
rc));
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT(2, ("SyncLoadDDB=%x\n", rc));
|
|
return rc;
|
|
} //SyncLoadDDB
|