|
|
/*** 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;
//
// Log the start of a method
//
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 ": %p: %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
|