Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

985 lines
28 KiB

  1. /*** sync.c - synchronization functions
  2. *
  3. * Copyright (c) 1996,1997 Microsoft Corporation
  4. * Author: Michael Tsang (MikeTs)
  5. * Created 04/16/97
  6. *
  7. * MODIFICATION HISTORY
  8. */
  9. #include "pch.h"
  10. #ifdef LOCKABLE_PRAGMA
  11. #pragma ACPI_LOCKABLE_DATA
  12. #pragma ACPI_LOCKABLE_CODE
  13. #endif
  14. /***LP AysncCallBack - Call back async function
  15. *
  16. * ENTRY
  17. * pctxt -> CTXT
  18. * rcCtxt - return status of the context
  19. *
  20. * EXIT
  21. * None
  22. */
  23. VOID LOCAL AsyncCallBack(PCTXT pctxt, NTSTATUS rcCtxt)
  24. {
  25. TRACENAME("ASYNCCALLBACK")
  26. PFNACB pfnAsyncCallBack;
  27. PNSOBJ pnsObj;
  28. POBJDATA pdataCallBack;
  29. PVOID pvContext;
  30. rcCtxt = ((rcCtxt == STATUS_SUCCESS) || (rcCtxt == AMLISTA_CONTINUE))?
  31. rcCtxt: NTERR(rcCtxt);
  32. if (pctxt->pnctxt != NULL)
  33. {
  34. //
  35. // We have a nested context here. We are calling back the nested
  36. // context, not the parent context.
  37. //
  38. pfnAsyncCallBack = pctxt->pnctxt->pfnAsyncCallBack;
  39. pnsObj = pctxt->pnctxt->pnsObj;
  40. pdataCallBack = pctxt->pnctxt->pdataCallBack;
  41. pvContext = pctxt->pnctxt->pvContext;
  42. }
  43. else
  44. {
  45. pfnAsyncCallBack = pctxt->pfnAsyncCallBack;
  46. pnsObj = pctxt->pnsObj;
  47. pdataCallBack = pctxt->pdataCallBack;
  48. pvContext = pctxt->pvContext;
  49. }
  50. ENTER(2, ("AsyncCallBack(pctxt=%x,rc=%x,Obj=%s,pdataCallBack=%x,pvContext=%x)\n",
  51. pctxt, rcCtxt, GetObjectPath(pnsObj), pdataCallBack, pvContext));
  52. if (pfnAsyncCallBack == (PFNACB)EvalMethodComplete)
  53. {
  54. LOGSCHEDEVENT('DONE', (ULONG_PTR)pnsObj, (ULONG_PTR)rcCtxt,
  55. (ULONG_PTR)pvContext);
  56. EvalMethodComplete(pctxt, rcCtxt, (PSYNCEVENT)pvContext);
  57. }
  58. else if (pfnAsyncCallBack != NULL)
  59. {
  60. if (rcCtxt == AMLISTA_CONTINUE)
  61. {
  62. //
  63. // We are not done yet, restart the AsyncEval context using
  64. // current thread.
  65. //
  66. ASSERT(pctxt->dwfCtxt & CTXTF_ASYNC_EVAL);
  67. RestartContext(pctxt, FALSE);
  68. }
  69. else
  70. {
  71. LOGSCHEDEVENT('ASCB', (ULONG_PTR)pnsObj, (ULONG_PTR)rcCtxt,
  72. (ULONG_PTR)pvContext);
  73. pfnAsyncCallBack(pnsObj, rcCtxt, pdataCallBack, pvContext);
  74. }
  75. }
  76. EXIT(2, ("AsyncCallBack!\n"));
  77. } //AsyncCallBack
  78. /***LP EvalMethodComplete - eval completion callback
  79. *
  80. * ENTRY
  81. * pctxt -> CTXT
  82. * rc - evaluation status
  83. * pse -> SyncEvent
  84. *
  85. * EXIT
  86. * None
  87. */
  88. VOID EXPORT EvalMethodComplete(PCTXT pctxt, NTSTATUS rc, PSYNCEVENT pse)
  89. {
  90. TRACENAME("EVALMETHODCOMPLETE")
  91. ENTER(2, ("EvalMethodComplete(pctxt=%x,rc=%x,pse=%x\n", pctxt, rc, pse));
  92. pse->rcCompleted = rc;
  93. pse->pctxt = pctxt;
  94. KeSetEvent(&pse->Event, 0, FALSE);
  95. EXIT(2, ("EvalMethodComplete!\n"));
  96. } //EvalMethodComplete
  97. /***LP SyncEvalObject - evaluate an object synchronously
  98. *
  99. * ENTRY
  100. * pns -> object
  101. * pdataResult -> to hold result data
  102. * icArgs - number of arguments to the method object
  103. * pdataArgs -> argument array
  104. *
  105. * EXIT-SUCCESS
  106. * returns STATUS_SUCCESS
  107. * EXIT-FAILURE
  108. * returns AMLIERR_ code
  109. */
  110. NTSTATUS LOCAL SyncEvalObject(PNSOBJ pns, POBJDATA pdataResult, int icArgs,
  111. POBJDATA pdataArgs)
  112. {
  113. TRACENAME("SYNCEVALOBJECT")
  114. NTSTATUS rc = STATUS_SUCCESS;
  115. SYNCEVENT seEvalObj;
  116. ENTER(2, ("SyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x)\n",
  117. GetObjectPath(pns), pdataResult, icArgs, pdataArgs));
  118. KeInitializeEvent(&seEvalObj.Event, SynchronizationEvent, FALSE);
  119. if (KeGetCurrentThread() == gReadyQueue.pkthCurrent)
  120. {
  121. if (!(gReadyQueue.pctxtCurrent->dwfCtxt & CTXTF_ASYNC_EVAL))
  122. {
  123. LOGSCHEDEVENT('NSYN', (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)pns,
  124. 0);
  125. //
  126. // Somebody is re-entering with the active context thread, so we
  127. // must nest using the existing active context.
  128. //
  129. if ((rc = NestAsyncEvalObject(pns, pdataResult, icArgs, pdataArgs,
  130. (PFNACB)EvalMethodComplete,
  131. &seEvalObj, FALSE)) ==
  132. AMLISTA_PENDING)
  133. {
  134. rc = RestartContext(gReadyQueue.pctxtCurrent, FALSE);
  135. }
  136. }
  137. else
  138. {
  139. rc = AMLI_LOGERR(AMLIERR_FATAL,
  140. ("SyncEvalObject: cannot nest a SyncEval on an async. context"));
  141. }
  142. }
  143. else
  144. {
  145. LOGSCHEDEVENT('SYNC', (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)pns, 0);
  146. rc = AsyncEvalObject(pns, pdataResult, icArgs, pdataArgs,
  147. (PFNACB)EvalMethodComplete, &seEvalObj, FALSE);
  148. }
  149. if (KeGetCurrentIrql() < DISPATCH_LEVEL)
  150. {
  151. while (rc == AMLISTA_PENDING)
  152. {
  153. if ((rc = KeWaitForSingleObject(&seEvalObj.Event, Executive,
  154. KernelMode, FALSE,
  155. (PLARGE_INTEGER)NULL)) ==
  156. STATUS_SUCCESS)
  157. {
  158. if (seEvalObj.rcCompleted == AMLISTA_CONTINUE)
  159. {
  160. rc = RestartContext(seEvalObj.pctxt, FALSE);
  161. }
  162. else
  163. {
  164. rc = AMLIERR(seEvalObj.rcCompleted);
  165. }
  166. }
  167. else
  168. {
  169. rc = AMLI_LOGERR(AMLIERR_FATAL,
  170. ("SyncEvalObject: object synchronization failed (rc=%x)",
  171. rc));
  172. }
  173. }
  174. }
  175. else if (rc == AMLISTA_PENDING)
  176. {
  177. rc = AMLI_LOGERR(AMLIERR_FATAL,
  178. ("SyncEvalObject: object %s being evaluated at IRQL >= DISPATCH_LEVEL",
  179. GetObjectPath(pns)));
  180. }
  181. EXIT(2, ("SyncEvalObject=%x\n", rc));
  182. return rc;
  183. } //SyncEvalObject
  184. /***LP AsyncEvalObject - evaluate an object asynchronously
  185. *
  186. * ENTRY
  187. * pns -> object
  188. * pdataResult -> to hold result data
  189. * icArgs - number of arguments to the method object
  190. * pdataArgs -> argument array
  191. * pfnAsyncCallBack -> completion callback function
  192. * pvContext -> context data
  193. * fAsync - TRUE if this is from an AsyncEval call
  194. *
  195. * EXIT-SUCCESS
  196. * returns STATUS_SUCCESS
  197. * EXIT-FAILURE
  198. * returns AMLIERR_ code
  199. */
  200. NTSTATUS LOCAL AsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult, int icArgs,
  201. POBJDATA pdataArgs, PFNACB pfnAsyncCallBack,
  202. PVOID pvContext, BOOLEAN fAsync)
  203. {
  204. TRACENAME("ASYNCEVALOBJECT")
  205. NTSTATUS rc = STATUS_SUCCESS;
  206. PCTXT pctxt = NULL;
  207. ENTER(2, ("AsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x,pvContext=%x,fAsync=%x)\n",
  208. GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
  209. pfnAsyncCallBack, pvContext, fAsync));
  210. LOGSCHEDEVENT('ASYN', (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)pns, 0);
  211. if ((rc = NewContext(&pctxt)) == STATUS_SUCCESS)
  212. {
  213. BOOLEAN fQueueContext = FALSE;
  214. pctxt->pnsObj = pns;
  215. pctxt->pnsScope = pns;
  216. pctxt->pfnAsyncCallBack = pfnAsyncCallBack;
  217. pctxt->pdataCallBack = pdataResult;
  218. pctxt->pvContext = pvContext;
  219. ACPIWMILOGEVENT((1,
  220. EVENT_TRACE_TYPE_START,
  221. GUID_List[AMLI_LOG_GUID],
  222. "Object = %s",
  223. GetObjectPath(pctxt->pnsObj)
  224. ));
  225. if (fAsync)
  226. {
  227. pctxt->dwfCtxt |= CTXTF_ASYNC_EVAL;
  228. }
  229. if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
  230. {
  231. if ((rc = PushCall(pctxt, pns, &pctxt->Result)) == STATUS_SUCCESS)
  232. {
  233. PCALL pcall;
  234. ASSERT(((PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd)->dwSig ==
  235. SIG_CALL);
  236. pcall = (PCALL)pctxt->LocalHeap.pbHeapEnd;
  237. if (icArgs != pcall->icArgs)
  238. {
  239. rc = AMLI_LOGERR(AMLIERR_INCORRECT_NUMARG,
  240. ("AsyncEvalObject: incorrect number of arguments (NumArg=%d,Expected=%d)",
  241. icArgs, pcall->icArgs));
  242. }
  243. else
  244. {
  245. #ifdef DEBUGGER
  246. if (gDebugger.dwfDebugger &
  247. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  248. {
  249. PRINTF("\n" MODNAME ": %08x: %s(",
  250. KeGetCurrentThread(), GetObjectPath(pns));
  251. }
  252. #endif
  253. //
  254. // Copying arguments to the call frame manually will skip
  255. // the argument parsing stage.
  256. //
  257. for (pcall->iArg = 0; pcall->iArg < icArgs; ++pcall->iArg)
  258. {
  259. if ((rc = DupObjData(pctxt->pheapCurrent,
  260. &pcall->pdataArgs[pcall->iArg],
  261. &pdataArgs[pcall->iArg])) !=
  262. STATUS_SUCCESS)
  263. {
  264. break;
  265. }
  266. #ifdef DEBUGGER
  267. if (gDebugger.dwfDebugger &
  268. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  269. {
  270. PrintObject(&pdataArgs[pcall->iArg]);
  271. if (pcall->iArg + 1 < icArgs)
  272. {
  273. PRINTF(",");
  274. }
  275. }
  276. #endif
  277. }
  278. if (rc == STATUS_SUCCESS)
  279. {
  280. #ifdef DEBUGGER
  281. if (gDebugger.dwfDebugger &
  282. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  283. {
  284. PRINTF(")\n");
  285. }
  286. #endif
  287. //
  288. // Skip the argument parsing stage.
  289. //
  290. pcall->FrameHdr.dwfFrame = 2;
  291. fQueueContext = TRUE;
  292. }
  293. }
  294. }
  295. }
  296. else if (((rc = PushPost(pctxt, ProcessEvalObj, (ULONG_PTR)pns, 0,
  297. &pctxt->Result)) == STATUS_SUCCESS) &&
  298. ((rc = ReadObject(pctxt, &pns->ObjData, &pctxt->Result)) !=
  299. AMLISTA_PENDING))
  300. {
  301. fQueueContext = TRUE;
  302. }
  303. if (fQueueContext)
  304. {
  305. rc = RestartContext(pctxt, FALSE);
  306. }
  307. else
  308. {
  309. //
  310. // If we never queue the context because we bailed,
  311. // we must free it.
  312. //
  313. FreeContext(pctxt);
  314. }
  315. }
  316. EXIT(2, ("AsyncEvalObject=%x\n", rc));
  317. return rc;
  318. } //AsyncEvalObject
  319. /***LP NestAsyncEvalObject - evaluate an object asynchronously using the
  320. * current context
  321. *
  322. * ENTRY
  323. * pns -> object
  324. * pdataResult -> to hold result data
  325. * icArgs - number of arguments to the method object
  326. * pdataArgs -> argument array
  327. * pfnAsyncCallBack -> completion callback function
  328. * pvContext -> context data
  329. * fAsync - TRUE if this is from an AsyncEval call
  330. *
  331. * EXIT-SUCCESS
  332. * returns STATUS_SUCCESS
  333. * EXIT-FAILURE
  334. * returns AMLIERR_ code
  335. */
  336. NTSTATUS LOCAL NestAsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult,
  337. int icArgs, POBJDATA pdataArgs,
  338. PFNACB pfnAsyncCallBack, PVOID pvContext,
  339. BOOLEAN fAsync)
  340. {
  341. TRACENAME("NESTASYNCEVALOBJECT")
  342. NTSTATUS rc = STATUS_SUCCESS;
  343. PCTXT pctxt = NULL;
  344. ENTER(2, ("NestAsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x,pvContext=%x,fAsync=%x)\n",
  345. GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
  346. pfnAsyncCallBack, pvContext, fAsync));
  347. //
  348. // Context must be the current one in progress.
  349. //
  350. ASSERT(gReadyQueue.pkthCurrent == KeGetCurrentThread());
  351. pctxt = gReadyQueue.pctxtCurrent;
  352. LOGSCHEDEVENT('NASY', (ULONG_PTR)pns, (ULONG_PTR)pfnAsyncCallBack,
  353. (ULONG_PTR)pctxt);
  354. if ((pctxt != NULL) &&
  355. (gReadyQueue.pkthCurrent == KeGetCurrentThread()))
  356. {
  357. PNESTEDCTXT pnctxt;
  358. rc = PushFrame(pctxt, SIG_NESTEDCTXT, sizeof(NESTEDCTXT),
  359. ParseNestedContext, &pnctxt);
  360. if (rc == STATUS_SUCCESS)
  361. {
  362. pnctxt->pnsObj = pns;
  363. pnctxt->pnsScope = pns;
  364. pnctxt->pfnAsyncCallBack = pfnAsyncCallBack;
  365. pnctxt->pdataCallBack = pdataResult;
  366. pnctxt->pvContext = pvContext;
  367. pnctxt->pnctxtPrev = pctxt->pnctxt;
  368. pnctxt->dwfPrevCtxt = pctxt->dwfCtxt;
  369. pctxt->pnctxt = pnctxt;
  370. pctxt->dwfCtxt |= CTXTF_NEST_EVAL;
  371. if (fAsync)
  372. {
  373. pctxt->dwfCtxt |= CTXTF_ASYNC_EVAL;
  374. }
  375. else
  376. {
  377. pctxt->dwfCtxt &= ~CTXTF_ASYNC_EVAL;
  378. }
  379. if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
  380. {
  381. if ((rc = PushCall(pctxt, pns, &pnctxt->Result)) ==
  382. STATUS_SUCCESS)
  383. {
  384. PCALL pcall;
  385. ASSERT(((PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd)->dwSig ==
  386. SIG_CALL);
  387. pcall = (PCALL)pctxt->LocalHeap.pbHeapEnd;
  388. if (icArgs != pcall->icArgs)
  389. {
  390. rc = AMLI_LOGERR(AMLIERR_INCORRECT_NUMARG,
  391. ("NestAsyncEvalObject: incorrect number of arguments (NumArg=%d,Expected=%d)",
  392. icArgs, pcall->icArgs));
  393. }
  394. else
  395. {
  396. #ifdef DEBUGGER
  397. if (gDebugger.dwfDebugger &
  398. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  399. {
  400. PRINTF("\n" MODNAME ": %s(", GetObjectPath(pns));
  401. }
  402. #endif
  403. //
  404. // Copying arguments to the call frame manually will
  405. // skip the argument parsing stage.
  406. //
  407. for (pcall->iArg = 0;
  408. pcall->iArg < icArgs;
  409. ++pcall->iArg)
  410. {
  411. if ((rc = DupObjData(pctxt->pheapCurrent,
  412. &pcall->pdataArgs[pcall->iArg],
  413. &pdataArgs[pcall->iArg])) !=
  414. STATUS_SUCCESS)
  415. {
  416. break;
  417. }
  418. #ifdef DEBUGGER
  419. if (gDebugger.dwfDebugger &
  420. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  421. {
  422. PrintObject(&pdataArgs[pcall->iArg]);
  423. if (pcall->iArg + 1 < icArgs)
  424. {
  425. PRINTF(",");
  426. }
  427. }
  428. #endif
  429. }
  430. if (rc == STATUS_SUCCESS)
  431. {
  432. #ifdef DEBUGGER
  433. if (gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  434. {
  435. PRINTF(")\n");
  436. }
  437. #endif
  438. //
  439. // Skip the argument parsing stage.
  440. //
  441. pcall->FrameHdr.dwfFrame = 2;
  442. }
  443. }
  444. }
  445. }
  446. else
  447. {
  448. //
  449. // Delay the evaluate the object.
  450. //
  451. rc = PushPost(pctxt, ProcessEvalObj, (ULONG_PTR)pns, 0,
  452. &pnctxt->Result);
  453. if (rc == STATUS_SUCCESS)
  454. {
  455. ReadObject(pctxt, &pns->ObjData, &pnctxt->Result);
  456. }
  457. }
  458. //
  459. // Always return AMLISTA_PENDING.
  460. //
  461. rc = AMLISTA_PENDING;
  462. }
  463. }
  464. else
  465. {
  466. //
  467. // We cannot use the nested version --- fail the call
  468. //
  469. rc = AMLI_LOGERR(AMLIERR_FATAL,
  470. ("NestAsyncEvalObject: pns=%08x No current context\n",
  471. pns));
  472. }
  473. EXIT(2, ("NestAsyncEvalObject=%x\n", rc));
  474. return rc;
  475. } //NestAsyncEvalObject
  476. /***LP ProcessEvalObj - post process of EvalObj
  477. *
  478. * ENTRY
  479. * pctxt -> CTXT
  480. * ppost -> POST
  481. * rc - status code
  482. *
  483. * EXIT-SUCCESS
  484. * returns STATUS_SUCCESS
  485. * EXIT-FAILURE
  486. * returns AMLIERR_ code
  487. */
  488. NTSTATUS LOCAL ProcessEvalObj(PCTXT pctxt, PPOST ppost, NTSTATUS rc)
  489. {
  490. TRACENAME("PROCESSEVALOBJ")
  491. ENTER(2, ("ProcessEvalObj(pctxt=%x,pbOp=%x,ppost=%x,rc=%x)\n",
  492. pctxt, pctxt->pbOp, ppost, rc));
  493. ASSERT(ppost->FrameHdr.dwSig == SIG_POST);
  494. #ifdef DEBUGGER
  495. if ((gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES)) &&
  496. (rc == STATUS_SUCCESS))
  497. {
  498. PRINTF("\n" MODNAME ": EvalObject(%s)=",
  499. GetObjectPath((PNSOBJ)ppost->uipData1));
  500. DumpObject(ppost->pdataResult, NULL, 0);
  501. PRINTF("\n");
  502. }
  503. #else
  504. DEREF(ppost);
  505. #endif
  506. PopFrame(pctxt);
  507. EXIT(2, ("ProcessEvalObj=%x\n", rc));
  508. return rc;
  509. } //ProcessEvalObj
  510. /***LP TimeoutCallback - DPC callback for Mutex/Event timeout
  511. *
  512. * ENTRY
  513. * pkdpc -> DPC
  514. * pctxt -> CTXT
  515. * SysArg1 - not used
  516. * SysArg2 - not used
  517. *
  518. * EXIT
  519. * None
  520. */
  521. VOID TimeoutCallback(PKDPC pkdpc, PCTXT pctxt, PVOID SysArg1, PVOID SysArg2)
  522. {
  523. TRACENAME("TIMEOUTCALLBACK")
  524. ENTER(2, ("TimeoutCallback(pkdpc=%x,pctxt=%x,SysArg1=%x,SysArg2=%x)\n",
  525. pkdpc, pctxt, SysArg1, SysArg2));
  526. DEREF(pkdpc);
  527. DEREF(SysArg1);
  528. DEREF(SysArg2);
  529. if (pctxt->dwfCtxt & CTXTF_TIMER_PENDING)
  530. {
  531. //
  532. // Timer has timed out.
  533. //
  534. pctxt->dwfCtxt &= ~CTXTF_TIMER_PENDING;
  535. pctxt->dwfCtxt |= CTXTF_TIMEOUT;
  536. //
  537. // Remove from waiting queue.
  538. //
  539. ASSERT(pctxt->pplistCtxtQueue != NULL);
  540. ListRemoveEntry(&((PCTXT)pctxt)->listQueue,
  541. ((PCTXT)pctxt)->pplistCtxtQueue);
  542. pctxt->pplistCtxtQueue = NULL;
  543. RestartContext(pctxt,
  544. (BOOLEAN)((pctxt->dwfCtxt & CTXTF_ASYNC_EVAL) == 0));
  545. }
  546. else if (pctxt->dwfCtxt & CTXTF_TIMER_DISPATCH)
  547. {
  548. //
  549. // Timer couldn't be cancelled while queuing context. Since the
  550. // queuing was aborted, we continue the queuing here.
  551. //
  552. pctxt->dwfCtxt &= ~CTXTF_TIMER_DISPATCH;
  553. RestartContext(pctxt,
  554. (BOOLEAN)((pctxt->dwfCtxt & CTXTF_ASYNC_EVAL) == 0));
  555. }
  556. else
  557. {
  558. // Should not be here
  559. ASSERT(pctxt->dwfCtxt & (CTXTF_TIMER_PENDING | CTXTF_TIMER_DISPATCH));
  560. }
  561. EXIT(2, ("TimeoutCallback!\n"));
  562. } //TimeoutCallback
  563. /***LP QueueContext - queue control method context
  564. *
  565. * ENTRY
  566. * pctxt -> CTXT
  567. * wTimeOut - timeout in ms
  568. * pplist -> list to insert created context
  569. *
  570. * EXIT
  571. * None
  572. */
  573. VOID LOCAL QueueContext(PCTXT pctxt, USHORT wTimeout, PPLIST pplist)
  574. {
  575. TRACENAME("QUEUECONTEXT")
  576. ENTER(2, ("QueueContext(pctxt=%x,Timeout=%d,pplist=%x)\n",
  577. pctxt, wTimeout, pplist));
  578. AcquireMutex(&gReadyQueue.mutCtxtQ);
  579. //
  580. // make sure this context isn't queued somewhere else.
  581. //
  582. ASSERT(pctxt->pplistCtxtQueue == NULL);
  583. ASSERT(pplist != NULL);
  584. ASSERT(!(pctxt->dwfCtxt &
  585. (CTXTF_TIMER_PENDING | CTXTF_TIMER_DISPATCH | CTXTF_TIMEOUT |
  586. CTXTF_READY)));
  587. ListInsertTail(&pctxt->listQueue, pplist);
  588. pctxt->pplistCtxtQueue = pplist;
  589. if (wTimeout != 0xffff)
  590. {
  591. LARGE_INTEGER liTimeout;
  592. pctxt->dwfCtxt |= CTXTF_TIMER_PENDING;
  593. liTimeout.QuadPart = (INT_PTR)(-10000*(INT_PTR)wTimeout);
  594. KeSetTimer(&pctxt->Timer, liTimeout, &pctxt->Dpc);
  595. }
  596. ReleaseMutex(&gReadyQueue.mutCtxtQ);
  597. EXIT(2, ("QueueContext!\n"));
  598. } //QueueContext
  599. /***LP DequeueAndReadyContext - dequeue context and insert to ready queue
  600. *
  601. * ENTRY
  602. * pplist -> context list to dequeue from
  603. *
  604. * EXIT-SUCCESS
  605. * returns pctxt
  606. * EXIT-FAILURE
  607. * returns NULL
  608. */
  609. PCTXT LOCAL DequeueAndReadyContext(PPLIST pplist)
  610. {
  611. TRACENAME("DEQUEUEANDREADYCONTEXT")
  612. PCTXT pctxt = NULL;
  613. PLIST plist;
  614. ENTER(2, ("DequeueAndReadyContext(pplist=%x)\n", pplist));
  615. AcquireMutex(&gReadyQueue.mutCtxtQ);
  616. if ((plist = ListRemoveHead(pplist)) != NULL)
  617. {
  618. pctxt = CONTAINING_RECORD(plist, CTXT, listQueue);
  619. ASSERT(pctxt->dwSig == SIG_CTXT);
  620. ASSERT(pctxt->pplistCtxtQueue == pplist);
  621. pctxt->pplistCtxtQueue = NULL;
  622. InsertReadyQueue(pctxt, TRUE);
  623. }
  624. ReleaseMutex(&gReadyQueue.mutCtxtQ);
  625. EXIT(2, ("DequeueAndReadyContext=%x\n", pctxt));
  626. return pctxt;
  627. } //DequeueAndReadyContext
  628. /***LP AcquireASLMutex - acquire ASL mutex
  629. *
  630. * ENTRY
  631. * pctxt -> CTXT
  632. * pm -> MUTEX structure
  633. * wTimeOut - timeout in ms
  634. *
  635. * EXIT-SUCCESS
  636. * returns STATUS_SUCCESS
  637. * EXIT-FAILURE
  638. * returns AMLIERR_ code
  639. */
  640. NTSTATUS LOCAL AcquireASLMutex(PCTXT pctxt, PMUTEXOBJ pm, USHORT wTimeout)
  641. {
  642. TRACENAME("ACQUIREASLMUTEX")
  643. NTSTATUS rc = STATUS_SUCCESS;
  644. ENTER(2, ("AcquireASLMutex(pctxt=%x,pm=%x,Timeout=%d)\n",
  645. pctxt, pm, wTimeout));
  646. if (pctxt->dwfCtxt & CTXTF_TIMEOUT)
  647. {
  648. pctxt->dwfCtxt &= ~CTXTF_TIMEOUT;
  649. rc = AMLISTA_TIMEOUT;
  650. }
  651. else if (pm->dwSyncLevel < pctxt->dwSyncLevel)
  652. {
  653. rc = AMLI_LOGERR(AMLIERR_MUTEX_INVALID_LEVEL,
  654. ("AcquireASLMutex: invalid sync level"));
  655. }
  656. else if (pm->dwcOwned == 0)
  657. {
  658. PRESOURCE pres;
  659. pres = NEWCROBJ(pctxt->pheapCurrent, sizeof(RESOURCE));
  660. if (pres == NULL)
  661. {
  662. rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
  663. ("AcquireASLMutex: failed to allocate context resource"));
  664. }
  665. else
  666. {
  667. pres->dwResType = RESTYPE_MUTEX;
  668. pres->pctxtOwner = pctxt;
  669. pres->pvResObj = pm;
  670. ListInsertHead(&pres->list, &pctxt->plistResources);
  671. pm->dwcOwned = 1;
  672. pm->hOwner = (HANDLE)pres;
  673. pctxt->dwSyncLevel = pm->dwSyncLevel;
  674. }
  675. }
  676. else if (((PRESOURCE)pm->hOwner)->pctxtOwner == pctxt)
  677. {
  678. pm->dwcOwned++;
  679. }
  680. else
  681. {
  682. QueueContext(pctxt, wTimeout, &pm->plistWaiters);
  683. rc = AMLISTA_PENDING;
  684. }
  685. EXIT(2, ("AcquireASLMutex=%x (CurrentOwner=%x)\n", rc, pm->hOwner));
  686. return rc;
  687. } //AcquireASLMutex
  688. /***LP ReleaseASLMutex - release ASL mutex
  689. *
  690. * ENTRY
  691. * pctxt -> CTXT
  692. * pm -> MUTEX structure
  693. *
  694. * EXIT-SUCCESS
  695. * returns STATUS_SUCCESS
  696. * EXIT-FAILURE
  697. * returns AMLIERR_ code
  698. */
  699. NTSTATUS LOCAL ReleaseASLMutex(PCTXT pctxt, PMUTEXOBJ pm)
  700. {
  701. TRACENAME("RELEASEASLMUTEX")
  702. NTSTATUS rc = STATUS_SUCCESS;
  703. ENTER(2, ("ReleaseASLMutex(pctxt=%x,pm=%x)\n", pctxt, pm));
  704. if (pm->dwcOwned == 0)
  705. {
  706. rc = AMLI_LOGERR(AMLIERR_MUTEX_NOT_OWNED,
  707. ("ReleaseASLMutex: Mutex is not owned"));
  708. }
  709. else
  710. {
  711. PRESOURCE pres;
  712. pres = (PRESOURCE)pm->hOwner;
  713. if ((pres == NULL) || (pres->pctxtOwner != pctxt))
  714. {
  715. rc = AMLI_LOGERR(AMLIERR_MUTEX_NOT_OWNER,
  716. ("ReleaseASLMutex: Mutex is owned by a different owner"));
  717. }
  718. else if (pm->dwSyncLevel > pctxt->dwSyncLevel)
  719. {
  720. rc = AMLI_LOGERR(AMLIERR_MUTEX_INVALID_LEVEL,
  721. ("ReleaseASLMutex: invalid sync level (MutexLevel=%d,CurrentLevel=%x",
  722. pm->dwSyncLevel, pctxt->dwSyncLevel));
  723. }
  724. else
  725. {
  726. pctxt->dwSyncLevel = pm->dwSyncLevel;
  727. pm->dwcOwned--;
  728. if (pm->dwcOwned == 0)
  729. {
  730. ListRemoveEntry(&pres->list, &pctxt->plistResources);
  731. FREECROBJ(pres);
  732. pm->hOwner = NULL;
  733. DequeueAndReadyContext(&pm->plistWaiters);
  734. }
  735. }
  736. }
  737. EXIT(2, ("ReleaseASLMutex=%x\n", rc));
  738. return rc;
  739. } //ReleaseASLMutex
  740. /***LP WaitASLEvent - wait ASL event
  741. *
  742. * ENTRY
  743. * pctxt -> CTXT
  744. * pe -> EVENT structure
  745. * wTimeOut - timeout in ms
  746. *
  747. * EXIT-SUCCESS
  748. * returns STATUS_SUCCESS
  749. * EXIT-FAILURE
  750. * returns AMLIERR_ code
  751. */
  752. NTSTATUS LOCAL WaitASLEvent(PCTXT pctxt, PEVENTOBJ pe, USHORT wTimeout)
  753. {
  754. TRACENAME("WAITASLEVENT")
  755. NTSTATUS rc = STATUS_SUCCESS;
  756. ENTER(2, ("WaitASLEvent(pctxt=%x,pe=%x,Timeout=%d)\n", pctxt, pe, wTimeout));
  757. if (pctxt->dwfCtxt & CTXTF_TIMEOUT)
  758. {
  759. pctxt->dwfCtxt &= ~CTXTF_TIMEOUT;
  760. rc = AMLISTA_TIMEOUT;
  761. }
  762. else if (pe->dwcSignaled > 0)
  763. {
  764. pe->dwcSignaled--;
  765. }
  766. else
  767. {
  768. QueueContext(pctxt, wTimeout, &pe->plistWaiters);
  769. rc = AMLISTA_PENDING;
  770. }
  771. EXIT(2, ("WaitASLEvent=%x\n", rc));
  772. return rc;
  773. } //WaitASLEvent
  774. /***LP ResetASLEvent - reset ASL event
  775. *
  776. * ENTRY
  777. * pe -> EVENT structure
  778. *
  779. * EXIT
  780. * None
  781. */
  782. VOID LOCAL ResetASLEvent(PEVENTOBJ pe)
  783. {
  784. TRACENAME("RESETASLEVENT")
  785. ENTER(2, ("ResetASLEvent(pe=%x)\n", pe));
  786. pe->dwcSignaled = 0;
  787. EXIT(2, ("ResetASLEvent!\n"));
  788. } //ResetASLEvent
  789. /***LP SignalASLEvent - signal ASL event
  790. *
  791. * ENTRY
  792. * pe -> EVENT structure
  793. *
  794. * EXIT
  795. * None
  796. */
  797. VOID LOCAL SignalASLEvent(PEVENTOBJ pe)
  798. {
  799. TRACENAME("SIGNALASLEVENT")
  800. ENTER(2, ("SignalASLEvent(pe=%x)\n", pe));
  801. if (DequeueAndReadyContext(&pe->plistWaiters) == NULL)
  802. {
  803. pe->dwcSignaled++;
  804. }
  805. EXIT(2, ("SignalASLEvent!\n"));
  806. } //SignalASLEvent
  807. /***LP SyncLoadDDB - load a DDB synchronously
  808. *
  809. * ENTRY
  810. * pctxt -> CTXT
  811. *
  812. * EXIT-SUCCESS
  813. * returns STATUS_SUCCESS
  814. * EXIT-FAILURE
  815. * returns AMLIERR_ code
  816. */
  817. NTSTATUS LOCAL SyncLoadDDB(PCTXT pctxt)
  818. {
  819. TRACENAME("SYNCLOADDDB")
  820. NTSTATUS rc = STATUS_SUCCESS;
  821. ENTER(2, ("SyncLoadDDB(pctxt=%x)\n", pctxt));
  822. if (KeGetCurrentThread() == gReadyQueue.pkthCurrent)
  823. {
  824. rc = AMLI_LOGERR(AMLIERR_FATAL,
  825. ("SyncLoadDDB: cannot nest a SyncLoadDDB"));
  826. pctxt->powner = NULL;
  827. FreeContext(pctxt);
  828. }
  829. else if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
  830. {
  831. rc = AMLI_LOGERR(AMLIERR_FATAL,
  832. ("SyncLoadDDB: cannot SyncLoadDDB at IRQL >= DISPATCH_LEVEL"));
  833. pctxt->powner = NULL;
  834. FreeContext(pctxt);
  835. }
  836. else
  837. {
  838. SYNCEVENT seEvalObj;
  839. KeInitializeEvent(&seEvalObj.Event, SynchronizationEvent, FALSE);
  840. pctxt->pfnAsyncCallBack = (PFNACB)EvalMethodComplete;
  841. pctxt->pvContext = &seEvalObj;
  842. rc = RestartContext(pctxt, FALSE);
  843. while (rc == AMLISTA_PENDING)
  844. {
  845. if ((rc = KeWaitForSingleObject(&seEvalObj.Event, Executive,
  846. KernelMode, FALSE,
  847. (PLARGE_INTEGER)NULL)) ==
  848. STATUS_SUCCESS)
  849. {
  850. if (seEvalObj.rcCompleted == AMLISTA_CONTINUE)
  851. {
  852. rc = RestartContext(seEvalObj.pctxt, FALSE);
  853. }
  854. else
  855. {
  856. rc = AMLIERR(seEvalObj.rcCompleted);
  857. }
  858. }
  859. else
  860. {
  861. rc = AMLI_LOGERR(AMLIERR_FATAL,
  862. ("SyncLoadDDB: object synchronization failed (rc=%x)",
  863. rc));
  864. }
  865. }
  866. }
  867. EXIT(2, ("SyncLoadDDB=%x\n", rc));
  868. return rc;
  869. } //SyncLoadDDB