Leaked source code of windows server 2003
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.

988 lines
29 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. //
  220. // Log the start of a method
  221. //
  222. ACPIWMILOGEVENT((1,
  223. EVENT_TRACE_TYPE_START,
  224. GUID_List[AMLI_LOG_GUID],
  225. "Object = %s",
  226. GetObjectPath(pctxt->pnsObj)
  227. ));
  228. if (fAsync)
  229. {
  230. pctxt->dwfCtxt |= CTXTF_ASYNC_EVAL;
  231. }
  232. if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
  233. {
  234. if ((rc = PushCall(pctxt, pns, &pctxt->Result)) == STATUS_SUCCESS)
  235. {
  236. PCALL pcall;
  237. ASSERT(((PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd)->dwSig ==
  238. SIG_CALL);
  239. pcall = (PCALL)pctxt->LocalHeap.pbHeapEnd;
  240. if (icArgs != pcall->icArgs)
  241. {
  242. rc = AMLI_LOGERR(AMLIERR_INCORRECT_NUMARG,
  243. ("AsyncEvalObject: incorrect number of arguments (NumArg=%d,Expected=%d)",
  244. icArgs, pcall->icArgs));
  245. }
  246. else
  247. {
  248. #ifdef DEBUGGER
  249. if (gDebugger.dwfDebugger &
  250. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  251. {
  252. PRINTF("\n" MODNAME ": %p: %s(",
  253. KeGetCurrentThread(), GetObjectPath(pns));
  254. }
  255. #endif
  256. //
  257. // Copying arguments to the call frame manually will skip
  258. // the argument parsing stage.
  259. //
  260. for (pcall->iArg = 0; pcall->iArg < icArgs; ++pcall->iArg)
  261. {
  262. if ((rc = DupObjData(pctxt->pheapCurrent,
  263. &pcall->pdataArgs[pcall->iArg],
  264. &pdataArgs[pcall->iArg])) !=
  265. STATUS_SUCCESS)
  266. {
  267. break;
  268. }
  269. #ifdef DEBUGGER
  270. if (gDebugger.dwfDebugger &
  271. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  272. {
  273. PrintObject(&pdataArgs[pcall->iArg]);
  274. if (pcall->iArg + 1 < icArgs)
  275. {
  276. PRINTF(",");
  277. }
  278. }
  279. #endif
  280. }
  281. if (rc == STATUS_SUCCESS)
  282. {
  283. #ifdef DEBUGGER
  284. if (gDebugger.dwfDebugger &
  285. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  286. {
  287. PRINTF(")\n");
  288. }
  289. #endif
  290. //
  291. // Skip the argument parsing stage.
  292. //
  293. pcall->FrameHdr.dwfFrame = 2;
  294. fQueueContext = TRUE;
  295. }
  296. }
  297. }
  298. }
  299. else if (((rc = PushPost(pctxt, ProcessEvalObj, (ULONG_PTR)pns, 0,
  300. &pctxt->Result)) == STATUS_SUCCESS) &&
  301. ((rc = ReadObject(pctxt, &pns->ObjData, &pctxt->Result)) !=
  302. AMLISTA_PENDING))
  303. {
  304. fQueueContext = TRUE;
  305. }
  306. if (fQueueContext)
  307. {
  308. rc = RestartContext(pctxt, FALSE);
  309. }
  310. else
  311. {
  312. //
  313. // If we never queue the context because we bailed,
  314. // we must free it.
  315. //
  316. FreeContext(pctxt);
  317. }
  318. }
  319. EXIT(2, ("AsyncEvalObject=%x\n", rc));
  320. return rc;
  321. } //AsyncEvalObject
  322. /***LP NestAsyncEvalObject - evaluate an object asynchronously using the
  323. * current context
  324. *
  325. * ENTRY
  326. * pns -> object
  327. * pdataResult -> to hold result data
  328. * icArgs - number of arguments to the method object
  329. * pdataArgs -> argument array
  330. * pfnAsyncCallBack -> completion callback function
  331. * pvContext -> context data
  332. * fAsync - TRUE if this is from an AsyncEval call
  333. *
  334. * EXIT-SUCCESS
  335. * returns STATUS_SUCCESS
  336. * EXIT-FAILURE
  337. * returns AMLIERR_ code
  338. */
  339. NTSTATUS LOCAL NestAsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult,
  340. int icArgs, POBJDATA pdataArgs,
  341. PFNACB pfnAsyncCallBack, PVOID pvContext,
  342. BOOLEAN fAsync)
  343. {
  344. TRACENAME("NESTASYNCEVALOBJECT")
  345. NTSTATUS rc = STATUS_SUCCESS;
  346. PCTXT pctxt = NULL;
  347. ENTER(2, ("NestAsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x,pvContext=%x,fAsync=%x)\n",
  348. GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
  349. pfnAsyncCallBack, pvContext, fAsync));
  350. //
  351. // Context must be the current one in progress.
  352. //
  353. ASSERT(gReadyQueue.pkthCurrent == KeGetCurrentThread());
  354. pctxt = gReadyQueue.pctxtCurrent;
  355. LOGSCHEDEVENT('NASY', (ULONG_PTR)pns, (ULONG_PTR)pfnAsyncCallBack,
  356. (ULONG_PTR)pctxt);
  357. if ((pctxt != NULL) &&
  358. (gReadyQueue.pkthCurrent == KeGetCurrentThread()))
  359. {
  360. PNESTEDCTXT pnctxt;
  361. rc = PushFrame(pctxt, SIG_NESTEDCTXT, sizeof(NESTEDCTXT),
  362. ParseNestedContext, &pnctxt);
  363. if (rc == STATUS_SUCCESS)
  364. {
  365. pnctxt->pnsObj = pns;
  366. pnctxt->pnsScope = pns;
  367. pnctxt->pfnAsyncCallBack = pfnAsyncCallBack;
  368. pnctxt->pdataCallBack = pdataResult;
  369. pnctxt->pvContext = pvContext;
  370. pnctxt->pnctxtPrev = pctxt->pnctxt;
  371. pnctxt->dwfPrevCtxt = pctxt->dwfCtxt;
  372. pctxt->pnctxt = pnctxt;
  373. pctxt->dwfCtxt |= CTXTF_NEST_EVAL;
  374. if (fAsync)
  375. {
  376. pctxt->dwfCtxt |= CTXTF_ASYNC_EVAL;
  377. }
  378. else
  379. {
  380. pctxt->dwfCtxt &= ~CTXTF_ASYNC_EVAL;
  381. }
  382. if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
  383. {
  384. if ((rc = PushCall(pctxt, pns, &pnctxt->Result)) ==
  385. STATUS_SUCCESS)
  386. {
  387. PCALL pcall;
  388. ASSERT(((PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd)->dwSig ==
  389. SIG_CALL);
  390. pcall = (PCALL)pctxt->LocalHeap.pbHeapEnd;
  391. if (icArgs != pcall->icArgs)
  392. {
  393. rc = AMLI_LOGERR(AMLIERR_INCORRECT_NUMARG,
  394. ("NestAsyncEvalObject: incorrect number of arguments (NumArg=%d,Expected=%d)",
  395. icArgs, pcall->icArgs));
  396. }
  397. else
  398. {
  399. #ifdef DEBUGGER
  400. if (gDebugger.dwfDebugger &
  401. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  402. {
  403. PRINTF("\n" MODNAME ": %s(", GetObjectPath(pns));
  404. }
  405. #endif
  406. //
  407. // Copying arguments to the call frame manually will
  408. // skip the argument parsing stage.
  409. //
  410. for (pcall->iArg = 0;
  411. pcall->iArg < icArgs;
  412. ++pcall->iArg)
  413. {
  414. if ((rc = DupObjData(pctxt->pheapCurrent,
  415. &pcall->pdataArgs[pcall->iArg],
  416. &pdataArgs[pcall->iArg])) !=
  417. STATUS_SUCCESS)
  418. {
  419. break;
  420. }
  421. #ifdef DEBUGGER
  422. if (gDebugger.dwfDebugger &
  423. (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  424. {
  425. PrintObject(&pdataArgs[pcall->iArg]);
  426. if (pcall->iArg + 1 < icArgs)
  427. {
  428. PRINTF(",");
  429. }
  430. }
  431. #endif
  432. }
  433. if (rc == STATUS_SUCCESS)
  434. {
  435. #ifdef DEBUGGER
  436. if (gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
  437. {
  438. PRINTF(")\n");
  439. }
  440. #endif
  441. //
  442. // Skip the argument parsing stage.
  443. //
  444. pcall->FrameHdr.dwfFrame = 2;
  445. }
  446. }
  447. }
  448. }
  449. else
  450. {
  451. //
  452. // Delay the evaluate the object.
  453. //
  454. rc = PushPost(pctxt, ProcessEvalObj, (ULONG_PTR)pns, 0,
  455. &pnctxt->Result);
  456. if (rc == STATUS_SUCCESS)
  457. {
  458. ReadObject(pctxt, &pns->ObjData, &pnctxt->Result);
  459. }
  460. }
  461. //
  462. // Always return AMLISTA_PENDING.
  463. //
  464. rc = AMLISTA_PENDING;
  465. }
  466. }
  467. else
  468. {
  469. //
  470. // We cannot use the nested version --- fail the call
  471. //
  472. rc = AMLI_LOGERR(AMLIERR_FATAL,
  473. ("NestAsyncEvalObject: pns=%08x No current context\n",
  474. pns));
  475. }
  476. EXIT(2, ("NestAsyncEvalObject=%x\n", rc));
  477. return rc;
  478. } //NestAsyncEvalObject
  479. /***LP ProcessEvalObj - post process of EvalObj
  480. *
  481. * ENTRY
  482. * pctxt -> CTXT
  483. * ppost -> POST
  484. * rc - status code
  485. *
  486. * EXIT-SUCCESS
  487. * returns STATUS_SUCCESS
  488. * EXIT-FAILURE
  489. * returns AMLIERR_ code
  490. */
  491. NTSTATUS LOCAL ProcessEvalObj(PCTXT pctxt, PPOST ppost, NTSTATUS rc)
  492. {
  493. TRACENAME("PROCESSEVALOBJ")
  494. ENTER(2, ("ProcessEvalObj(pctxt=%x,pbOp=%x,ppost=%x,rc=%x)\n",
  495. pctxt, pctxt->pbOp, ppost, rc));
  496. ASSERT(ppost->FrameHdr.dwSig == SIG_POST);
  497. #ifdef DEBUGGER
  498. if ((gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES)) &&
  499. (rc == STATUS_SUCCESS))
  500. {
  501. PRINTF("\n" MODNAME ": EvalObject(%s)=",
  502. GetObjectPath((PNSOBJ)ppost->uipData1));
  503. DumpObject(ppost->pdataResult, NULL, 0);
  504. PRINTF("\n");
  505. }
  506. #else
  507. DEREF(ppost);
  508. #endif
  509. PopFrame(pctxt);
  510. EXIT(2, ("ProcessEvalObj=%x\n", rc));
  511. return rc;
  512. } //ProcessEvalObj
  513. /***LP TimeoutCallback - DPC callback for Mutex/Event timeout
  514. *
  515. * ENTRY
  516. * pkdpc -> DPC
  517. * pctxt -> CTXT
  518. * SysArg1 - not used
  519. * SysArg2 - not used
  520. *
  521. * EXIT
  522. * None
  523. */
  524. VOID TimeoutCallback(PKDPC pkdpc, PCTXT pctxt, PVOID SysArg1, PVOID SysArg2)
  525. {
  526. TRACENAME("TIMEOUTCALLBACK")
  527. ENTER(2, ("TimeoutCallback(pkdpc=%x,pctxt=%x,SysArg1=%x,SysArg2=%x)\n",
  528. pkdpc, pctxt, SysArg1, SysArg2));
  529. DEREF(pkdpc);
  530. DEREF(SysArg1);
  531. DEREF(SysArg2);
  532. if (pctxt->dwfCtxt & CTXTF_TIMER_PENDING)
  533. {
  534. //
  535. // Timer has timed out.
  536. //
  537. pctxt->dwfCtxt &= ~CTXTF_TIMER_PENDING;
  538. pctxt->dwfCtxt |= CTXTF_TIMEOUT;
  539. //
  540. // Remove from waiting queue.
  541. //
  542. ASSERT(pctxt->pplistCtxtQueue != NULL);
  543. ListRemoveEntry(&((PCTXT)pctxt)->listQueue,
  544. ((PCTXT)pctxt)->pplistCtxtQueue);
  545. pctxt->pplistCtxtQueue = NULL;
  546. RestartContext(pctxt,
  547. (BOOLEAN)((pctxt->dwfCtxt & CTXTF_ASYNC_EVAL) == 0));
  548. }
  549. else if (pctxt->dwfCtxt & CTXTF_TIMER_DISPATCH)
  550. {
  551. //
  552. // Timer couldn't be cancelled while queuing context. Since the
  553. // queuing was aborted, we continue the queuing here.
  554. //
  555. pctxt->dwfCtxt &= ~CTXTF_TIMER_DISPATCH;
  556. RestartContext(pctxt,
  557. (BOOLEAN)((pctxt->dwfCtxt & CTXTF_ASYNC_EVAL) == 0));
  558. }
  559. else
  560. {
  561. // Should not be here
  562. ASSERT(pctxt->dwfCtxt & (CTXTF_TIMER_PENDING | CTXTF_TIMER_DISPATCH));
  563. }
  564. EXIT(2, ("TimeoutCallback!\n"));
  565. } //TimeoutCallback
  566. /***LP QueueContext - queue control method context
  567. *
  568. * ENTRY
  569. * pctxt -> CTXT
  570. * wTimeOut - timeout in ms
  571. * pplist -> list to insert created context
  572. *
  573. * EXIT
  574. * None
  575. */
  576. VOID LOCAL QueueContext(PCTXT pctxt, USHORT wTimeout, PPLIST pplist)
  577. {
  578. TRACENAME("QUEUECONTEXT")
  579. ENTER(2, ("QueueContext(pctxt=%x,Timeout=%d,pplist=%x)\n",
  580. pctxt, wTimeout, pplist));
  581. AcquireMutex(&gReadyQueue.mutCtxtQ);
  582. //
  583. // make sure this context isn't queued somewhere else.
  584. //
  585. ASSERT(pctxt->pplistCtxtQueue == NULL);
  586. ASSERT(pplist != NULL);
  587. ASSERT(!(pctxt->dwfCtxt &
  588. (CTXTF_TIMER_PENDING | CTXTF_TIMER_DISPATCH | CTXTF_TIMEOUT |
  589. CTXTF_READY)));
  590. ListInsertTail(&pctxt->listQueue, pplist);
  591. pctxt->pplistCtxtQueue = pplist;
  592. if (wTimeout != 0xffff)
  593. {
  594. LARGE_INTEGER liTimeout;
  595. pctxt->dwfCtxt |= CTXTF_TIMER_PENDING;
  596. liTimeout.QuadPart = (INT_PTR)(-10000*(INT_PTR)wTimeout);
  597. KeSetTimer(&pctxt->Timer, liTimeout, &pctxt->Dpc);
  598. }
  599. ReleaseMutex(&gReadyQueue.mutCtxtQ);
  600. EXIT(2, ("QueueContext!\n"));
  601. } //QueueContext
  602. /***LP DequeueAndReadyContext - dequeue context and insert to ready queue
  603. *
  604. * ENTRY
  605. * pplist -> context list to dequeue from
  606. *
  607. * EXIT-SUCCESS
  608. * returns pctxt
  609. * EXIT-FAILURE
  610. * returns NULL
  611. */
  612. PCTXT LOCAL DequeueAndReadyContext(PPLIST pplist)
  613. {
  614. TRACENAME("DEQUEUEANDREADYCONTEXT")
  615. PCTXT pctxt = NULL;
  616. PLIST plist;
  617. ENTER(2, ("DequeueAndReadyContext(pplist=%x)\n", pplist));
  618. AcquireMutex(&gReadyQueue.mutCtxtQ);
  619. if ((plist = ListRemoveHead(pplist)) != NULL)
  620. {
  621. pctxt = CONTAINING_RECORD(plist, CTXT, listQueue);
  622. ASSERT(pctxt->dwSig == SIG_CTXT);
  623. ASSERT(pctxt->pplistCtxtQueue == pplist);
  624. pctxt->pplistCtxtQueue = NULL;
  625. InsertReadyQueue(pctxt, TRUE);
  626. }
  627. ReleaseMutex(&gReadyQueue.mutCtxtQ);
  628. EXIT(2, ("DequeueAndReadyContext=%x\n", pctxt));
  629. return pctxt;
  630. } //DequeueAndReadyContext
  631. /***LP AcquireASLMutex - acquire ASL mutex
  632. *
  633. * ENTRY
  634. * pctxt -> CTXT
  635. * pm -> MUTEX structure
  636. * wTimeOut - timeout in ms
  637. *
  638. * EXIT-SUCCESS
  639. * returns STATUS_SUCCESS
  640. * EXIT-FAILURE
  641. * returns AMLIERR_ code
  642. */
  643. NTSTATUS LOCAL AcquireASLMutex(PCTXT pctxt, PMUTEXOBJ pm, USHORT wTimeout)
  644. {
  645. TRACENAME("ACQUIREASLMUTEX")
  646. NTSTATUS rc = STATUS_SUCCESS;
  647. ENTER(2, ("AcquireASLMutex(pctxt=%x,pm=%x,Timeout=%d)\n",
  648. pctxt, pm, wTimeout));
  649. if (pctxt->dwfCtxt & CTXTF_TIMEOUT)
  650. {
  651. pctxt->dwfCtxt &= ~CTXTF_TIMEOUT;
  652. rc = AMLISTA_TIMEOUT;
  653. }
  654. else if (pm->dwSyncLevel < pctxt->dwSyncLevel)
  655. {
  656. rc = AMLI_LOGERR(AMLIERR_MUTEX_INVALID_LEVEL,
  657. ("AcquireASLMutex: invalid sync level"));
  658. }
  659. else if (pm->dwcOwned == 0)
  660. {
  661. PRESOURCE pres;
  662. pres = NEWCROBJ(pctxt->pheapCurrent, sizeof(RESOURCE));
  663. if (pres == NULL)
  664. {
  665. rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
  666. ("AcquireASLMutex: failed to allocate context resource"));
  667. }
  668. else
  669. {
  670. pres->dwResType = RESTYPE_MUTEX;
  671. pres->pctxtOwner = pctxt;
  672. pres->pvResObj = pm;
  673. ListInsertHead(&pres->list, &pctxt->plistResources);
  674. pm->dwcOwned = 1;
  675. pm->hOwner = (HANDLE)pres;
  676. pctxt->dwSyncLevel = pm->dwSyncLevel;
  677. }
  678. }
  679. else if (((PRESOURCE)pm->hOwner)->pctxtOwner == pctxt)
  680. {
  681. pm->dwcOwned++;
  682. }
  683. else
  684. {
  685. QueueContext(pctxt, wTimeout, &pm->plistWaiters);
  686. rc = AMLISTA_PENDING;
  687. }
  688. EXIT(2, ("AcquireASLMutex=%x (CurrentOwner=%x)\n", rc, pm->hOwner));
  689. return rc;
  690. } //AcquireASLMutex
  691. /***LP ReleaseASLMutex - release ASL mutex
  692. *
  693. * ENTRY
  694. * pctxt -> CTXT
  695. * pm -> MUTEX structure
  696. *
  697. * EXIT-SUCCESS
  698. * returns STATUS_SUCCESS
  699. * EXIT-FAILURE
  700. * returns AMLIERR_ code
  701. */
  702. NTSTATUS LOCAL ReleaseASLMutex(PCTXT pctxt, PMUTEXOBJ pm)
  703. {
  704. TRACENAME("RELEASEASLMUTEX")
  705. NTSTATUS rc = STATUS_SUCCESS;
  706. ENTER(2, ("ReleaseASLMutex(pctxt=%x,pm=%x)\n", pctxt, pm));
  707. if (pm->dwcOwned == 0)
  708. {
  709. rc = AMLI_LOGERR(AMLIERR_MUTEX_NOT_OWNED,
  710. ("ReleaseASLMutex: Mutex is not owned"));
  711. }
  712. else
  713. {
  714. PRESOURCE pres;
  715. pres = (PRESOURCE)pm->hOwner;
  716. if ((pres == NULL) || (pres->pctxtOwner != pctxt))
  717. {
  718. rc = AMLI_LOGERR(AMLIERR_MUTEX_NOT_OWNER,
  719. ("ReleaseASLMutex: Mutex is owned by a different owner"));
  720. }
  721. else if (pm->dwSyncLevel > pctxt->dwSyncLevel)
  722. {
  723. rc = AMLI_LOGERR(AMLIERR_MUTEX_INVALID_LEVEL,
  724. ("ReleaseASLMutex: invalid sync level (MutexLevel=%d,CurrentLevel=%x",
  725. pm->dwSyncLevel, pctxt->dwSyncLevel));
  726. }
  727. else
  728. {
  729. pctxt->dwSyncLevel = pm->dwSyncLevel;
  730. pm->dwcOwned--;
  731. if (pm->dwcOwned == 0)
  732. {
  733. ListRemoveEntry(&pres->list, &pctxt->plistResources);
  734. FREECROBJ(pres);
  735. pm->hOwner = NULL;
  736. DequeueAndReadyContext(&pm->plistWaiters);
  737. }
  738. }
  739. }
  740. EXIT(2, ("ReleaseASLMutex=%x\n", rc));
  741. return rc;
  742. } //ReleaseASLMutex
  743. /***LP WaitASLEvent - wait ASL event
  744. *
  745. * ENTRY
  746. * pctxt -> CTXT
  747. * pe -> EVENT structure
  748. * wTimeOut - timeout in ms
  749. *
  750. * EXIT-SUCCESS
  751. * returns STATUS_SUCCESS
  752. * EXIT-FAILURE
  753. * returns AMLIERR_ code
  754. */
  755. NTSTATUS LOCAL WaitASLEvent(PCTXT pctxt, PEVENTOBJ pe, USHORT wTimeout)
  756. {
  757. TRACENAME("WAITASLEVENT")
  758. NTSTATUS rc = STATUS_SUCCESS;
  759. ENTER(2, ("WaitASLEvent(pctxt=%x,pe=%x,Timeout=%d)\n", pctxt, pe, wTimeout));
  760. if (pctxt->dwfCtxt & CTXTF_TIMEOUT)
  761. {
  762. pctxt->dwfCtxt &= ~CTXTF_TIMEOUT;
  763. rc = AMLISTA_TIMEOUT;
  764. }
  765. else if (pe->dwcSignaled > 0)
  766. {
  767. pe->dwcSignaled--;
  768. }
  769. else
  770. {
  771. QueueContext(pctxt, wTimeout, &pe->plistWaiters);
  772. rc = AMLISTA_PENDING;
  773. }
  774. EXIT(2, ("WaitASLEvent=%x\n", rc));
  775. return rc;
  776. } //WaitASLEvent
  777. /***LP ResetASLEvent - reset ASL event
  778. *
  779. * ENTRY
  780. * pe -> EVENT structure
  781. *
  782. * EXIT
  783. * None
  784. */
  785. VOID LOCAL ResetASLEvent(PEVENTOBJ pe)
  786. {
  787. TRACENAME("RESETASLEVENT")
  788. ENTER(2, ("ResetASLEvent(pe=%x)\n", pe));
  789. pe->dwcSignaled = 0;
  790. EXIT(2, ("ResetASLEvent!\n"));
  791. } //ResetASLEvent
  792. /***LP SignalASLEvent - signal ASL event
  793. *
  794. * ENTRY
  795. * pe -> EVENT structure
  796. *
  797. * EXIT
  798. * None
  799. */
  800. VOID LOCAL SignalASLEvent(PEVENTOBJ pe)
  801. {
  802. TRACENAME("SIGNALASLEVENT")
  803. ENTER(2, ("SignalASLEvent(pe=%x)\n", pe));
  804. if (DequeueAndReadyContext(&pe->plistWaiters) == NULL)
  805. {
  806. pe->dwcSignaled++;
  807. }
  808. EXIT(2, ("SignalASLEvent!\n"));
  809. } //SignalASLEvent
  810. /***LP SyncLoadDDB - load a DDB synchronously
  811. *
  812. * ENTRY
  813. * pctxt -> CTXT
  814. *
  815. * EXIT-SUCCESS
  816. * returns STATUS_SUCCESS
  817. * EXIT-FAILURE
  818. * returns AMLIERR_ code
  819. */
  820. NTSTATUS LOCAL SyncLoadDDB(PCTXT pctxt)
  821. {
  822. TRACENAME("SYNCLOADDDB")
  823. NTSTATUS rc = STATUS_SUCCESS;
  824. ENTER(2, ("SyncLoadDDB(pctxt=%x)\n", pctxt));
  825. if (KeGetCurrentThread() == gReadyQueue.pkthCurrent)
  826. {
  827. rc = AMLI_LOGERR(AMLIERR_FATAL,
  828. ("SyncLoadDDB: cannot nest a SyncLoadDDB"));
  829. pctxt->powner = NULL;
  830. FreeContext(pctxt);
  831. }
  832. else if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
  833. {
  834. rc = AMLI_LOGERR(AMLIERR_FATAL,
  835. ("SyncLoadDDB: cannot SyncLoadDDB at IRQL >= DISPATCH_LEVEL"));
  836. pctxt->powner = NULL;
  837. FreeContext(pctxt);
  838. }
  839. else
  840. {
  841. SYNCEVENT seEvalObj;
  842. KeInitializeEvent(&seEvalObj.Event, SynchronizationEvent, FALSE);
  843. pctxt->pfnAsyncCallBack = (PFNACB)EvalMethodComplete;
  844. pctxt->pvContext = &seEvalObj;
  845. rc = RestartContext(pctxt, FALSE);
  846. while (rc == AMLISTA_PENDING)
  847. {
  848. if ((rc = KeWaitForSingleObject(&seEvalObj.Event, Executive,
  849. KernelMode, FALSE,
  850. (PLARGE_INTEGER)NULL)) ==
  851. STATUS_SUCCESS)
  852. {
  853. if (seEvalObj.rcCompleted == AMLISTA_CONTINUE)
  854. {
  855. rc = RestartContext(seEvalObj.pctxt, FALSE);
  856. }
  857. else
  858. {
  859. rc = AMLIERR(seEvalObj.rcCompleted);
  860. }
  861. }
  862. else
  863. {
  864. rc = AMLI_LOGERR(AMLIERR_FATAL,
  865. ("SyncLoadDDB: object synchronization failed (rc=%x)",
  866. rc));
  867. }
  868. }
  869. }
  870. EXIT(2, ("SyncLoadDDB=%x\n", rc));
  871. return rc;
  872. } //SyncLoadDDB