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.

1379 lines
44 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. wait.c
  5. Abstract:
  6. This module implements the generic kernel wait routines. Functions
  7. are provided to delay execution, wait for multiple objects, wait for
  8. a single object, and ot set a client event and wait for a server event.
  9. N.B. This module is written to be a fast as possible and not as small
  10. as possible. Therefore some code sequences are duplicated to avoid
  11. procedure calls. It would also be possible to combine wait for
  12. single object into wait for multiple objects at the cost of some
  13. speed. Since wait for single object is the most common case, the
  14. two routines have been separated.
  15. Author:
  16. David N. Cutler (davec) 23-Mar-89
  17. Environment:
  18. Kernel mode only.
  19. Revision History:
  20. --*/
  21. #include "ki.h"
  22. //
  23. // Test for alertable condition.
  24. //
  25. // If alertable is TRUE and the thread is alerted for a processor
  26. // mode that is equal to the wait mode, then return immediately
  27. // with a wait completion status of ALERTED.
  28. //
  29. // Else if alertable is TRUE, the wait mode is user, and the user APC
  30. // queue is not empty, then set user APC pending, and return immediately
  31. // with a wait completion status of USER_APC.
  32. //
  33. // Else if alertable is TRUE and the thread is alerted for kernel
  34. // mode, then return immediately with a wait completion status of
  35. // ALERTED.
  36. //
  37. // Else if alertable is FALSE and the wait mode is user and there is a
  38. // user APC pending, then return immediately with a wait completion
  39. // status of USER_APC.
  40. //
  41. #define TestForAlertPending(Alertable) \
  42. if (Alertable) { \
  43. if (Thread->Alerted[WaitMode] != FALSE) { \
  44. Thread->Alerted[WaitMode] = FALSE; \
  45. WaitStatus = STATUS_ALERTED; \
  46. break; \
  47. } else if ((WaitMode != KernelMode) && \
  48. (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode])) == FALSE) { \
  49. Thread->ApcState.UserApcPending = TRUE; \
  50. WaitStatus = STATUS_USER_APC; \
  51. break; \
  52. } else if (Thread->Alerted[KernelMode] != FALSE) { \
  53. Thread->Alerted[KernelMode] = FALSE; \
  54. WaitStatus = STATUS_ALERTED; \
  55. break; \
  56. } \
  57. } else if (Thread->ApcState.UserApcPending & WaitMode) { \
  58. WaitStatus = STATUS_USER_APC; \
  59. break; \
  60. }
  61. VOID
  62. KiAdjustQuantumThread (
  63. IN PKTHREAD Thread
  64. )
  65. /*++
  66. Routine Description:
  67. If the current thread is not a time critical or real time thread, then
  68. adjust its quantum in accordance with the adjustment that would have
  69. occurred if the thread had actually waited.
  70. N.B. This routine is entered at SYNCH_LEVEL and exits at the wait
  71. IRQL of the subject thread after having exited the scheduler.
  72. Arguments:
  73. Thread - Supplies a pointer to the current thread.
  74. Return Value:
  75. None.
  76. --*/
  77. {
  78. PKPRCB Prcb;
  79. PKPROCESS Process;
  80. PKTHREAD NewThread;
  81. //
  82. // Acquire the thread lock and the PRCB lock.
  83. //
  84. // If the thread is not a real time or time critical thread, then adjust
  85. // the thread quantum.
  86. //
  87. Prcb = KeGetCurrentPrcb();
  88. KiAcquireThreadLock(Thread);
  89. KiAcquirePrcbLock(Prcb);
  90. if ((Thread->Priority < LOW_REALTIME_PRIORITY) &&
  91. (Thread->BasePriority < TIME_CRITICAL_PRIORITY_BOUND)) {
  92. Thread->Quantum -= WAIT_QUANTUM_DECREMENT;
  93. if (Thread->Quantum <= 0) {
  94. //
  95. // Quantum end has occurred. Adjust the thread priority.
  96. //
  97. Process = Thread->ApcState.Process;
  98. Thread->Quantum = Process->ThreadQuantum;
  99. //
  100. // Compute the new thread priority and attempt to reschedule the
  101. // current processor as if a quantum end had occurred.
  102. //
  103. // N.B. The new priority will never be greater than the previous
  104. // priority.
  105. //
  106. Thread->Priority = KiComputeNewPriority(Thread, 1);
  107. if (Prcb->NextThread == NULL) {
  108. if ((NewThread = KiSelectReadyThread(Thread->Priority, Prcb)) != NULL) {
  109. NewThread->State = Standby;
  110. Prcb->NextThread = NewThread;
  111. }
  112. } else {
  113. Thread->Preempted = FALSE;
  114. }
  115. }
  116. }
  117. //
  118. // Release the thread lock, release the PRCB lock, exit the scheduler,
  119. // and return.
  120. //
  121. KiReleasePrcbLock(Prcb);
  122. KiReleaseThreadLock(Thread);
  123. KiExitDispatcher(Thread->WaitIrql);
  124. return;
  125. }
  126. //
  127. // The following macro initializes thread local variables for the delay
  128. // execution thread kernel service while context switching is disabled.
  129. //
  130. // N.B. IRQL must be raised to DPC level prior to the invocation of this
  131. // macro.
  132. //
  133. // N.B. Initialization is done in this manner so this code does not get
  134. // executed inside the dispatcher lock.
  135. //
  136. #define InitializeDelayExecution() \
  137. Thread->WaitBlockList = WaitBlock; \
  138. Thread->WaitStatus = 0; \
  139. WaitBlock->NextWaitBlock = WaitBlock; \
  140. Timer->Header.WaitListHead.Flink = &WaitBlock->WaitListEntry; \
  141. Timer->Header.WaitListHead.Blink = &WaitBlock->WaitListEntry; \
  142. Thread->Alertable = Alertable; \
  143. Thread->WaitMode = WaitMode; \
  144. Thread->WaitReason = DelayExecution; \
  145. Thread->WaitListEntry.Flink = NULL; \
  146. StackSwappable = KiIsKernelStackSwappable(WaitMode, Thread); \
  147. Thread->WaitTime = KiQueryLowTickCount()
  148. NTSTATUS
  149. KeDelayExecutionThread (
  150. IN KPROCESSOR_MODE WaitMode,
  151. IN BOOLEAN Alertable,
  152. IN PLARGE_INTEGER Interval
  153. )
  154. /*++
  155. Routine Description:
  156. This function delays the execution of the current thread for the specified
  157. interval of time.
  158. Arguments:
  159. WaitMode - Supplies the processor mode in which the delay is to occur.
  160. Alertable - Supplies a boolean value that specifies whether the delay
  161. is alertable.
  162. Interval - Supplies a pointer to the absolute or relative time over which
  163. the delay is to occur.
  164. Return Value:
  165. The wait completion status. A value of STATUS_SUCCESS is returned if
  166. the delay occurred. A value of STATUS_ALERTED is returned if the wait
  167. was aborted to deliver an alert to the current thread. A value of
  168. STATUS_USER_APC is returned if the wait was aborted to deliver a user
  169. APC to the current thread.
  170. --*/
  171. {
  172. LARGE_INTEGER DueTime;
  173. LARGE_INTEGER NewTime;
  174. PLARGE_INTEGER OriginalTime;
  175. PKPRCB Prcb;
  176. PRKQUEUE Queue;
  177. LOGICAL StackSwappable;
  178. PKTHREAD Thread;
  179. PRKTIMER Timer;
  180. PKWAIT_BLOCK WaitBlock;
  181. NTSTATUS WaitStatus;
  182. //
  183. // Set constant variables.
  184. //
  185. Thread = KeGetCurrentThread();
  186. OriginalTime = Interval;
  187. Timer = &Thread->Timer;
  188. WaitBlock = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
  189. //
  190. // If the dispatcher database is already held, then initialize the thread
  191. // local variables. Otherwise, raise IRQL to DPC level, initialize the
  192. // thread local variables, and lock the dispatcher database.
  193. //
  194. if (Thread->WaitNext == FALSE) {
  195. goto WaitStart;
  196. }
  197. Thread->WaitNext = FALSE;
  198. InitializeDelayExecution();
  199. //
  200. // Start of delay loop.
  201. //
  202. // Note this loop is repeated if a kernel APC is delivered in the middle
  203. // of the delay or a kernel APC is pending on the first attempt through
  204. // the loop.
  205. //
  206. do {
  207. //
  208. // Test to determine if a kernel APC is pending.
  209. //
  210. // If a kernel APC is pending, the special APC disable count is zero,
  211. // and the previous IRQL was less than APC_LEVEL, then a kernel APC
  212. // was queued by another processor just after IRQL was raised to
  213. // DISPATCH_LEVEL, but before the dispatcher database was locked.
  214. //
  215. // N.B. that this can only happen in a multiprocessor system.
  216. //
  217. if (Thread->ApcState.KernelApcPending &&
  218. (Thread->SpecialApcDisable == 0) &&
  219. (Thread->WaitIrql < APC_LEVEL)) {
  220. //
  221. // Unlock the dispatcher database and lower IRQL to its previous
  222. // value. An APC interrupt will immediately occur which will result
  223. // in the delivery of the kernel APC if possible.
  224. //
  225. KiRequestSoftwareInterrupt(APC_LEVEL);
  226. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  227. } else {
  228. //
  229. // Test for alert pending.
  230. //
  231. TestForAlertPending(Alertable);
  232. //
  233. // Insert the timer in the timer tree.
  234. //
  235. // N.B. The constant fields of the timer wait block are
  236. // initialized when the thread is initialized. The
  237. // constant fields include the wait object, wait key,
  238. // wait type, and the wait list entry link pointers.
  239. //
  240. Prcb = KeGetCurrentPrcb();
  241. if (KiInsertTreeTimer(Timer, *Interval) == FALSE) {
  242. goto NoWait;
  243. }
  244. DueTime.QuadPart = Timer->DueTime.QuadPart;
  245. //
  246. // If the current thread is processing a queue entry, then attempt
  247. // to activate another thread that is blocked on the queue object.
  248. //
  249. Queue = Thread->Queue;
  250. if (Queue != NULL) {
  251. KiActivateWaiterQueue(Queue);
  252. }
  253. //
  254. // Set the thread wait parameters, set the thread dispatcher
  255. // state to Waiting, and insert the thread in the wait list if
  256. // the kernel stack of the current thread is swappable.
  257. //
  258. Thread->State = Waiting;
  259. if (StackSwappable != FALSE) {
  260. InsertTailList(&Prcb->WaitListHead, &Thread->WaitListEntry);
  261. }
  262. //
  263. // Set swap busy for the current thread, unlock the dispatcher
  264. // database, and switch to a new thread.
  265. //
  266. // Control is returned at the original IRQL.
  267. //
  268. ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
  269. KiSetContextSwapBusy(Thread);
  270. KiUnlockDispatcherDatabaseFromSynchLevel();
  271. WaitStatus = (NTSTATUS)KiSwapThread(Thread, Prcb);
  272. //
  273. // If the thread was not awakened to deliver a kernel mode APC,
  274. // then return the wait status.
  275. //
  276. if (WaitStatus != STATUS_KERNEL_APC) {
  277. if (WaitStatus == STATUS_TIMEOUT) {
  278. WaitStatus = STATUS_SUCCESS;
  279. }
  280. return WaitStatus;
  281. }
  282. //
  283. // Reduce the time remaining before the time delay expires.
  284. //
  285. Interval = KiComputeWaitInterval(OriginalTime,
  286. &DueTime,
  287. &NewTime);
  288. }
  289. //
  290. // Raise IRQL to SYNCH level, initialize the thread local variables,
  291. // and lock the dispatcher database.
  292. //
  293. WaitStart:
  294. Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
  295. InitializeDelayExecution();
  296. KiLockDispatcherDatabaseAtSynchLevel();
  297. } while (TRUE);
  298. //
  299. // The thread is alerted or a user APC should be delivered. Unlock the
  300. // dispatcher database, lower IRQL to its previous value, and return the
  301. // wait status.
  302. //
  303. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  304. return WaitStatus;
  305. //
  306. // The wait has been satisfied without actually waiting.
  307. //
  308. // If the wait time is zero, then unlock the dispatcher database and
  309. // yield execution. Otherwise, unlock the dispatcher database, remain
  310. // at SYNCH level, adjust the thread quantum, exit the dispatcher, and
  311. // and return the wait completion status.
  312. //
  313. NoWait:
  314. if ((Interval->LowPart | Interval->HighPart) == 0) {
  315. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  316. return NtYieldExecution();
  317. } else {
  318. KiUnlockDispatcherDatabaseFromSynchLevel();
  319. KiAdjustQuantumThread(Thread);
  320. return STATUS_SUCCESS;
  321. }
  322. }
  323. //
  324. // The following macro initializes thread local variables for the wait
  325. // for multiple objects kernel service while context switching is disabled.
  326. //
  327. // N.B. IRQL must be raised to DPC level prior to the invocation of this
  328. // macro.
  329. //
  330. // N.B. Initialization is done in this manner so this code does not get
  331. // executed inside the dispatcher lock.
  332. //
  333. #define InitializeWaitMultiple() \
  334. Thread->WaitBlockList = WaitBlockArray; \
  335. Index = 0; \
  336. do { \
  337. WaitBlock = &WaitBlockArray[Index]; \
  338. WaitBlock->Object = Object[Index]; \
  339. WaitBlock->WaitKey = (CSHORT)(Index); \
  340. WaitBlock->WaitType = WaitType; \
  341. WaitBlock->Thread = Thread; \
  342. WaitBlock->NextWaitBlock = &WaitBlockArray[Index + 1]; \
  343. Index += 1; \
  344. } while (Index < Count); \
  345. WaitBlock->NextWaitBlock = &WaitBlockArray[0]; \
  346. WaitTimer->NextWaitBlock = &WaitBlockArray[0]; \
  347. Thread->WaitStatus = 0; \
  348. InitializeListHead(&Timer->Header.WaitListHead); \
  349. Thread->Alertable = Alertable; \
  350. Thread->WaitMode = WaitMode; \
  351. Thread->WaitReason = (UCHAR)WaitReason; \
  352. Thread->WaitListEntry.Flink = NULL; \
  353. StackSwappable = KiIsKernelStackSwappable(WaitMode, Thread); \
  354. Thread->WaitTime = KiQueryLowTickCount()
  355. NTSTATUS
  356. KeWaitForMultipleObjects (
  357. IN ULONG Count,
  358. IN PVOID Object[],
  359. IN WAIT_TYPE WaitType,
  360. IN KWAIT_REASON WaitReason,
  361. IN KPROCESSOR_MODE WaitMode,
  362. IN BOOLEAN Alertable,
  363. IN PLARGE_INTEGER Timeout OPTIONAL,
  364. IN PKWAIT_BLOCK WaitBlockArray OPTIONAL
  365. )
  366. /*++
  367. Routine Description:
  368. This function waits until the specified objects attain a state of
  369. Signaled. The wait can be specified to wait until all of the objects
  370. attain a state of Signaled or until one of the objects attains a state
  371. of Signaled. An optional timeout can also be specified. If a timeout
  372. is not specified, then the wait will not be satisfied until the objects
  373. attain a state of Signaled. If a timeout is specified, and the objects
  374. have not attained a state of Signaled when the timeout expires, then
  375. the wait is automatically satisfied. If an explicit timeout value of
  376. zero is specified, then no wait will occur if the wait cannot be satisfied
  377. immediately. The wait can also be specified as alertable.
  378. Arguments:
  379. Count - Supplies a count of the number of objects that are to be waited
  380. on.
  381. Object[] - Supplies an array of pointers to dispatcher objects.
  382. WaitType - Supplies the type of wait to perform (WaitAll, WaitAny).
  383. WaitReason - Supplies the reason for the wait.
  384. WaitMode - Supplies the processor mode in which the wait is to occur.
  385. Alertable - Supplies a boolean value that specifies whether the wait is
  386. alertable.
  387. Timeout - Supplies a pointer to an optional absolute of relative time over
  388. which the wait is to occur.
  389. WaitBlockArray - Supplies an optional pointer to an array of wait blocks
  390. that are to used to describe the wait operation.
  391. Return Value:
  392. The wait completion status. A value of STATUS_TIMEOUT is returned if a
  393. timeout occurred. The index of the object (zero based) in the object
  394. pointer array is returned if an object satisfied the wait. A value of
  395. STATUS_ALERTED is returned if the wait was aborted to deliver an alert
  396. to the current thread. A value of STATUS_USER_APC is returned if the
  397. wait was aborted to deliver a user APC to the current thread.
  398. --*/
  399. {
  400. PKPRCB CurrentPrcb;
  401. LARGE_INTEGER DueTime;
  402. ULONG Index;
  403. LARGE_INTEGER NewTime;
  404. PKMUTANT Objectx;
  405. PLARGE_INTEGER OriginalTime;
  406. PRKQUEUE Queue;
  407. LOGICAL StackSwappable;
  408. PRKTHREAD Thread;
  409. PRKTIMER Timer;
  410. PRKWAIT_BLOCK WaitBlock;
  411. NTSTATUS WaitStatus;
  412. PKWAIT_BLOCK WaitTimer;
  413. //
  414. // Set constant variables.
  415. //
  416. Thread = KeGetCurrentThread();
  417. OriginalTime = Timeout;
  418. Timer = &Thread->Timer;
  419. WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
  420. //
  421. // If a wait block array has been specified, then the maximum number of
  422. // objects that can be waited on is specified by MAXIMUM_WAIT_OBJECTS.
  423. // Otherwise the builtin wait blocks in the thread object are used and
  424. // the maximum number of objects that can be waited on is specified by
  425. // THREAD_WAIT_OBJECTS. If the specified number of objects is not within
  426. // limits, then bug check.
  427. //
  428. if (ARGUMENT_PRESENT(WaitBlockArray)) {
  429. if (Count > MAXIMUM_WAIT_OBJECTS) {
  430. KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
  431. }
  432. } else {
  433. if (Count > THREAD_WAIT_OBJECTS) {
  434. KeBugCheck(MAXIMUM_WAIT_OBJECTS_EXCEEDED);
  435. }
  436. WaitBlockArray = &Thread->WaitBlock[0];
  437. }
  438. ASSERT(Count != 0);
  439. //
  440. // If the dispatcher database is already held, then initialize the thread
  441. // local variables. Otherwise, raise IRQL to DPC level, initialize the
  442. // thread local variables, and lock the dispatcher database.
  443. //
  444. if (Thread->WaitNext == FALSE) {
  445. goto WaitStart;
  446. }
  447. Thread->WaitNext = FALSE;
  448. InitializeWaitMultiple();
  449. //
  450. // Start of wait loop.
  451. //
  452. // Note this loop is repeated if a kernel APC is delivered in the middle
  453. // of the wait or a kernel APC is pending on the first attempt through
  454. // the loop.
  455. //
  456. do {
  457. //
  458. // Test to determine if a kernel APC is pending.
  459. //
  460. // If a kernel APC is pending, the special APC disable count is zero,
  461. // and the previous IRQL was less than APC_LEVEL, then a kernel APC
  462. // was queued by another processor just after IRQL was raised to
  463. // DISPATCH_LEVEL, but before the dispatcher database was locked.
  464. //
  465. // N.B. that this can only happen in a multiprocessor system.
  466. //
  467. if (Thread->ApcState.KernelApcPending &&
  468. (Thread->SpecialApcDisable == 0) &&
  469. (Thread->WaitIrql < APC_LEVEL)) {
  470. //
  471. // Unlock the dispatcher database and lower IRQL to its previous
  472. // value. An APC interrupt will immediately occur which will result
  473. // in the delivery of the kernel APC if possible.
  474. //
  475. KiRequestSoftwareInterrupt(APC_LEVEL);
  476. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  477. } else {
  478. //
  479. // Construct wait blocks and check to determine if the wait is
  480. // already satisfied. If the wait is satisfied, then perform
  481. // wait completion and return. Else put current thread in a wait
  482. // state if an explicit timeout value of zero is not specified.
  483. //
  484. Index = 0;
  485. if (WaitType == WaitAny) {
  486. do {
  487. //
  488. // Test if wait can be satisfied immediately.
  489. //
  490. Objectx = (PKMUTANT)Object[Index];
  491. ASSERT(Objectx->Header.Type != QueueObject);
  492. //
  493. // If the object is a mutant object and the mutant object
  494. // has been recursively acquired MINLONG times, then raise
  495. // an exception. Otherwise if the signal state of the mutant
  496. // object is greater than zero, or the current thread is
  497. // the owner of the mutant object, then satisfy the wait.
  498. //
  499. if (Objectx->Header.Type == MutantObject) {
  500. if ((Objectx->Header.SignalState > 0) ||
  501. (Thread == Objectx->OwnerThread)) {
  502. if (Objectx->Header.SignalState != MINLONG) {
  503. KiWaitSatisfyMutant(Objectx, Thread);
  504. WaitStatus = (NTSTATUS)(Index | Thread->WaitStatus);
  505. goto NoWait;
  506. } else {
  507. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  508. ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
  509. }
  510. }
  511. //
  512. // If the signal state is greater than zero, then satisfy
  513. // the wait.
  514. //
  515. } else if (Objectx->Header.SignalState > 0) {
  516. KiWaitSatisfyOther(Objectx);
  517. WaitStatus = (NTSTATUS)(Index);
  518. goto NoWait;
  519. }
  520. Index += 1;
  521. } while(Index < Count);
  522. } else {
  523. do {
  524. //
  525. // Test if wait can be satisfied.
  526. //
  527. Objectx = (PKMUTANT)Object[Index];
  528. ASSERT(Objectx->Header.Type != QueueObject);
  529. //
  530. // If the object is a mutant object and the mutant object
  531. // has been recursively acquired MINLONG times, then raise
  532. // an exception. Otherwise if the signal state of the mutant
  533. // object is less than or equal to zero and the current
  534. // thread is not the owner of the mutant object, then the
  535. // wait cannot be satisfied.
  536. //
  537. if (Objectx->Header.Type == MutantObject) {
  538. if ((Thread == Objectx->OwnerThread) &&
  539. (Objectx->Header.SignalState == MINLONG)) {
  540. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  541. ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
  542. } else if ((Objectx->Header.SignalState <= 0) &&
  543. (Thread != Objectx->OwnerThread)) {
  544. break;
  545. }
  546. //
  547. // If the signal state is less than or equal to zero, then
  548. // the wait cannot be satisfied.
  549. //
  550. } else if (Objectx->Header.SignalState <= 0) {
  551. break;
  552. }
  553. Index += 1;
  554. } while(Index < Count);
  555. //
  556. // If all objects have been scanned, then satisfy the wait.
  557. //
  558. if (Index == Count) {
  559. WaitBlock = &WaitBlockArray[0];
  560. do {
  561. Objectx = (PKMUTANT)WaitBlock->Object;
  562. KiWaitSatisfyAny(Objectx, Thread);
  563. WaitBlock = WaitBlock->NextWaitBlock;
  564. } while (WaitBlock != &WaitBlockArray[0]);
  565. WaitStatus = (NTSTATUS)Thread->WaitStatus;
  566. goto NoWait;
  567. }
  568. }
  569. //
  570. // Test for alert pending.
  571. //
  572. TestForAlertPending(Alertable);
  573. //
  574. // Check to determine if a timeout value is specified.
  575. //
  576. if (ARGUMENT_PRESENT(Timeout)) {
  577. //
  578. // If the timeout value is zero, then return immediately without
  579. // waiting.
  580. //
  581. if (Timeout->QuadPart == 0) {
  582. WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
  583. goto NoWait;
  584. }
  585. //
  586. // Initialize a wait block for the thread specific timer,
  587. // initialize timer wait list head, insert the timer in the
  588. // timer tree, and increment the number of wait objects.
  589. //
  590. // N.B. The constant fields of the timer wait block are
  591. // initialized when the thread is initialized. The
  592. // constant fields include the wait object, wait key,
  593. // wait type, and the wait list entry link pointers.
  594. //
  595. if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
  596. WaitStatus = (NTSTATUS)STATUS_TIMEOUT;
  597. goto NoWait;
  598. }
  599. WaitBlock->NextWaitBlock = WaitTimer;
  600. DueTime.QuadPart = Timer->DueTime.QuadPart;
  601. }
  602. //
  603. // Insert wait blocks in object wait lists.
  604. //
  605. WaitBlock = &WaitBlockArray[0];
  606. do {
  607. Objectx = (PKMUTANT)WaitBlock->Object;
  608. InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry);
  609. WaitBlock = WaitBlock->NextWaitBlock;
  610. } while (WaitBlock != &WaitBlockArray[0]);
  611. //
  612. // If the current thread is processing a queue entry, then attempt
  613. // to activate another thread that is blocked on the queue object.
  614. //
  615. Queue = Thread->Queue;
  616. if (Queue != NULL) {
  617. KiActivateWaiterQueue(Queue);
  618. }
  619. //
  620. // Set the thread wait parameters, set the thread dispatcher state
  621. // to Waiting, and insert the thread in the wait list.
  622. //
  623. CurrentPrcb = KeGetCurrentPrcb();
  624. Thread->State = Waiting;
  625. if (StackSwappable != FALSE) {
  626. InsertTailList(&CurrentPrcb->WaitListHead, &Thread->WaitListEntry);
  627. }
  628. //
  629. // Set swap busy for the current thread, unlock the dispatcher
  630. // database, and switch to a new thread.
  631. //
  632. // Control is returned at the original IRQL.
  633. //
  634. ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
  635. KiSetContextSwapBusy(Thread);
  636. KiUnlockDispatcherDatabaseFromSynchLevel();
  637. WaitStatus = (NTSTATUS)KiSwapThread(Thread, CurrentPrcb);
  638. //
  639. // If the thread was not awakened to deliver a kernel mode APC,
  640. // then return the wait status.
  641. //
  642. if (WaitStatus != STATUS_KERNEL_APC) {
  643. return WaitStatus;
  644. }
  645. if (ARGUMENT_PRESENT(Timeout)) {
  646. //
  647. // Reduce the amount of time remaining before timeout occurs.
  648. //
  649. Timeout = KiComputeWaitInterval(OriginalTime,
  650. &DueTime,
  651. &NewTime);
  652. }
  653. }
  654. //
  655. // Raise IRQL to SYNCH level, initialize the thread local variables,
  656. // and lock the dispatcher database.
  657. //
  658. WaitStart:
  659. Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
  660. InitializeWaitMultiple();
  661. KiLockDispatcherDatabaseAtSynchLevel();
  662. } while (TRUE);
  663. //
  664. // The thread is alerted or a user APC should be delivered. Unlock the
  665. // dispatcher database, lower IRQL to its previous value, and return
  666. // the wait status.
  667. //
  668. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  669. return WaitStatus;
  670. //
  671. // The wait has been satisfied without actually waiting.
  672. //
  673. // Unlock the dispatcher database and remain at SYNCH level.
  674. //
  675. NoWait:
  676. KiUnlockDispatcherDatabaseFromSynchLevel();
  677. //
  678. // Adjust the thread quantum, exit the scheduler, and return the wait
  679. // completion status.
  680. //
  681. KiAdjustQuantumThread(Thread);
  682. return WaitStatus;
  683. }
  684. //
  685. // The following macro initializes thread local variables for the wait
  686. // for single object kernel service while context switching is disabled.
  687. //
  688. // N.B. IRQL must be raised to DPC level prior to the invocation of this
  689. // macro.
  690. //
  691. // N.B. Initialization is done in this manner so this code does not get
  692. // executed inside the dispatcher lock.
  693. //
  694. #define InitializeWaitSingle() \
  695. Thread->WaitBlockList = WaitBlock; \
  696. WaitBlock->Object = Object; \
  697. WaitBlock->WaitKey = (CSHORT)(STATUS_SUCCESS); \
  698. WaitBlock->WaitType = WaitAny; \
  699. Thread->WaitStatus = 0; \
  700. if (ARGUMENT_PRESENT(Timeout)) { \
  701. WaitBlock->NextWaitBlock = WaitTimer; \
  702. WaitTimer->NextWaitBlock = WaitBlock; \
  703. Timer->Header.WaitListHead.Flink = &WaitTimer->WaitListEntry; \
  704. Timer->Header.WaitListHead.Blink = &WaitTimer->WaitListEntry; \
  705. } else { \
  706. WaitBlock->NextWaitBlock = WaitBlock; \
  707. } \
  708. Thread->Alertable = Alertable; \
  709. Thread->WaitMode = WaitMode; \
  710. Thread->WaitReason = (UCHAR)WaitReason; \
  711. Thread->WaitListEntry.Flink = NULL; \
  712. StackSwappable = KiIsKernelStackSwappable(WaitMode, Thread); \
  713. Thread->WaitTime = KiQueryLowTickCount()
  714. NTSTATUS
  715. KeWaitForSingleObject (
  716. IN PVOID Object,
  717. IN KWAIT_REASON WaitReason,
  718. IN KPROCESSOR_MODE WaitMode,
  719. IN BOOLEAN Alertable,
  720. IN PLARGE_INTEGER Timeout OPTIONAL
  721. )
  722. /*++
  723. Routine Description:
  724. This function waits until the specified object attains a state of
  725. Signaled. An optional timeout can also be specified. If a timeout
  726. is not specified, then the wait will not be satisfied until the object
  727. attains a state of Signaled. If a timeout is specified, and the object
  728. has not attained a state of Signaled when the timeout expires, then
  729. the wait is automatically satisfied. If an explicit timeout value of
  730. zero is specified, then no wait will occur if the wait cannot be satisfied
  731. immediately. The wait can also be specified as alertable.
  732. Arguments:
  733. Object - Supplies a pointer to a dispatcher object.
  734. WaitReason - Supplies the reason for the wait.
  735. WaitMode - Supplies the processor mode in which the wait is to occur.
  736. Alertable - Supplies a boolean value that specifies whether the wait is
  737. alertable.
  738. Timeout - Supplies a pointer to an optional absolute of relative time over
  739. which the wait is to occur.
  740. Return Value:
  741. The wait completion status. A value of STATUS_TIMEOUT is returned if a
  742. timeout occurred. A value of STATUS_SUCCESS is returned if the specified
  743. object satisfied the wait. A value of STATUS_ALERTED is returned if the
  744. wait was aborted to deliver an alert to the current thread. A value of
  745. STATUS_USER_APC is returned if the wait was aborted to deliver a user
  746. APC to the current thread.
  747. --*/
  748. {
  749. PKPRCB CurrentPrcb;
  750. LARGE_INTEGER DueTime;
  751. LARGE_INTEGER NewTime;
  752. PKMUTANT Objectx;
  753. PLARGE_INTEGER OriginalTime;
  754. PRKQUEUE Queue;
  755. LOGICAL StackSwappable;
  756. PRKTHREAD Thread;
  757. PRKTIMER Timer;
  758. PKWAIT_BLOCK WaitBlock;
  759. NTSTATUS WaitStatus;
  760. PKWAIT_BLOCK WaitTimer;
  761. //
  762. // Collect call data.
  763. //
  764. #if defined(_COLLECT_WAIT_SINGLE_CALLDATA_)
  765. RECORD_CALL_DATA(&KiWaitSingleCallData);
  766. #endif
  767. ASSERT((PsGetCurrentThread()->StartAddress != (PVOID)(ULONG_PTR)KeBalanceSetManager) || (ARGUMENT_PRESENT(Timeout)));
  768. //
  769. // Set constant variables.
  770. //
  771. Thread = KeGetCurrentThread();
  772. Objectx = (PKMUTANT)Object;
  773. OriginalTime = Timeout;
  774. Timer = &Thread->Timer;
  775. WaitBlock = &Thread->WaitBlock[0];
  776. WaitTimer = &Thread->WaitBlock[TIMER_WAIT_BLOCK];
  777. //
  778. // If the dispatcher database is already held, then initialize the thread
  779. // local variables. Otherwise, raise IRQL to DPC level, initialize the
  780. // thread local variables, and lock the dispatcher database.
  781. //
  782. if (Thread->WaitNext == FALSE) {
  783. goto WaitStart;
  784. }
  785. Thread->WaitNext = FALSE;
  786. InitializeWaitSingle();
  787. //
  788. // Start of wait loop.
  789. //
  790. // Note this loop is repeated if a kernel APC is delivered in the middle
  791. // of the wait or a kernel APC is pending on the first attempt through
  792. // the loop.
  793. //
  794. do {
  795. //
  796. // Test to determine if a kernel APC is pending.
  797. //
  798. // If a kernel APC is pending, the special APC disable count is zero,
  799. // and the previous IRQL was less than APC_LEVEL, then a kernel APC
  800. // was queued by another processor just after IRQL was raised to
  801. // DISPATCH_LEVEL, but before the dispatcher database was locked.
  802. //
  803. // N.B. that this can only happen in a multiprocessor system.
  804. //
  805. if (Thread->ApcState.KernelApcPending &&
  806. (Thread->SpecialApcDisable == 0) &&
  807. (Thread->WaitIrql < APC_LEVEL)) {
  808. //
  809. // Unlock the dispatcher database and lower IRQL to its previous
  810. // value. An APC interrupt will immediately occur which will result
  811. // in the delivery of the kernel APC if possible.
  812. //
  813. KiRequestSoftwareInterrupt(APC_LEVEL);
  814. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  815. } else {
  816. //
  817. // If the object is a mutant object and the mutant object has been
  818. // recursively acquired MINLONG times, then raise an exception.
  819. // Otherwise if the signal state of the mutant object is greater
  820. // than zero, or the current thread is the owner of the mutant
  821. // object, then satisfy the wait.
  822. //
  823. ASSERT(Objectx->Header.Type != QueueObject);
  824. if (Objectx->Header.Type == MutantObject) {
  825. if ((Objectx->Header.SignalState > 0) ||
  826. (Thread == Objectx->OwnerThread)) {
  827. if (Objectx->Header.SignalState != MINLONG) {
  828. KiWaitSatisfyMutant(Objectx, Thread);
  829. WaitStatus = (NTSTATUS)(Thread->WaitStatus);
  830. goto NoWait;
  831. } else {
  832. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  833. ExRaiseStatus(STATUS_MUTANT_LIMIT_EXCEEDED);
  834. }
  835. }
  836. //
  837. // If the signal state is greater than zero, then satisfy the wait.
  838. //
  839. } else if (Objectx->Header.SignalState > 0) {
  840. KiWaitSatisfyOther(Objectx);
  841. WaitStatus = (NTSTATUS)(0);
  842. goto NoWait;
  843. }
  844. //
  845. // Construct a wait block for the object.
  846. //
  847. //
  848. // Test for alert pending.
  849. //
  850. TestForAlertPending(Alertable);
  851. //
  852. // The wait cannot be satisifed immediately. Check to determine if
  853. // a timeout value is specified.
  854. //
  855. if (ARGUMENT_PRESENT(Timeout)) {
  856. //
  857. // If the timeout value is zero, then return immediately without
  858. // waiting.
  859. //
  860. if (Timeout->QuadPart == 0) {
  861. WaitStatus = (NTSTATUS)(STATUS_TIMEOUT);
  862. goto NoWait;
  863. }
  864. //
  865. // Insert the timer in the timer tree.
  866. //
  867. // N.B. The constant fields of the timer wait block are
  868. // initialized when the thread is initialized. The
  869. // constant fields include the wait object, wait key,
  870. // wait type, and the wait list entry link pointers.
  871. //
  872. if (KiInsertTreeTimer(Timer, *Timeout) == FALSE) {
  873. WaitStatus = (NTSTATUS)STATUS_TIMEOUT;
  874. goto NoWait;
  875. }
  876. DueTime.QuadPart = Timer->DueTime.QuadPart;
  877. }
  878. //
  879. // Insert wait block in object wait list.
  880. //
  881. InsertTailList(&Objectx->Header.WaitListHead, &WaitBlock->WaitListEntry);
  882. //
  883. // If the current thread is processing a queue entry, then attempt
  884. // to activate another thread that is blocked on the queue object.
  885. //
  886. Queue = Thread->Queue;
  887. if (Queue != NULL) {
  888. KiActivateWaiterQueue(Queue);
  889. }
  890. //
  891. // Set the thread wait parameters, set the thread dispatcher state
  892. // to Waiting, and insert the thread in the wait list.
  893. //
  894. Thread->State = Waiting;
  895. CurrentPrcb = KeGetCurrentPrcb();
  896. if (StackSwappable != FALSE) {
  897. InsertTailList(&CurrentPrcb->WaitListHead, &Thread->WaitListEntry);
  898. }
  899. //
  900. // Set swap busy for the current thread, unlock the dispatcher
  901. // database, and switch to a new thread.
  902. //
  903. // Control is returned at the original IRQL.
  904. //
  905. ASSERT(Thread->WaitIrql <= DISPATCH_LEVEL);
  906. KiSetContextSwapBusy(Thread);
  907. KiUnlockDispatcherDatabaseFromSynchLevel();
  908. WaitStatus = (NTSTATUS)KiSwapThread(Thread, CurrentPrcb);
  909. //
  910. // If the thread was not awakened to deliver a kernel mode APC,
  911. // then return wait status.
  912. //
  913. if (WaitStatus != STATUS_KERNEL_APC) {
  914. return WaitStatus;
  915. }
  916. if (ARGUMENT_PRESENT(Timeout)) {
  917. //
  918. // Reduce the amount of time remaining before timeout occurs.
  919. //
  920. Timeout = KiComputeWaitInterval(OriginalTime,
  921. &DueTime,
  922. &NewTime);
  923. }
  924. }
  925. //
  926. // Raise IRQL to SYNCH level, initialize the thread local variables,
  927. // and lock the dispatcher database.
  928. //
  929. WaitStart:
  930. Thread->WaitIrql = KeRaiseIrqlToSynchLevel();
  931. InitializeWaitSingle();
  932. KiLockDispatcherDatabaseAtSynchLevel();
  933. } while (TRUE);
  934. //
  935. // The thread is alerted or a user APC should be delivered. Unlock the
  936. // dispatcher database, lower IRQL to its previous value, and return
  937. // the wait status.
  938. //
  939. KiUnlockDispatcherDatabase(Thread->WaitIrql);
  940. return WaitStatus;
  941. //
  942. // The wait has been satisfied without actually waiting.
  943. //
  944. // Unlock the dispatcher database and remain at SYNCH level.
  945. //
  946. NoWait:
  947. KiUnlockDispatcherDatabaseFromSynchLevel();
  948. //
  949. // Adjust the thread quantum, exit the scheduler, and return the wait
  950. // completion status.
  951. //
  952. KiAdjustQuantumThread(Thread);
  953. return WaitStatus;
  954. }
  955. NTSTATUS
  956. KiSetServerWaitClientEvent (
  957. IN PKEVENT ServerEvent,
  958. IN PKEVENT ClientEvent,
  959. IN ULONG WaitMode
  960. )
  961. /*++
  962. Routine Description:
  963. This function sets the specified server event and waits on specified
  964. client event. The wait is performed such that an optimal switch to
  965. the waiting thread occurs if possible. No timeout is associated with
  966. the wait, and thus, the issuing thread will wait until the client event
  967. is signaled or an APC is delivered.
  968. Arguments:
  969. ServerEvent - Supplies a pointer to a dispatcher object of type event.
  970. ClientEvent - Supplies a pointer to a dispatcher object of type event.
  971. WaitMode - Supplies the processor mode in which the wait is to occur.
  972. Return Value:
  973. The wait completion status. A value of STATUS_SUCCESS is returned if
  974. the specified object satisfied the wait. A value of STATUS_USER_APC is
  975. returned if the wait was aborted to deliver a user APC to the current
  976. thread.
  977. --*/
  978. {
  979. //
  980. // Set sever event and wait on client event atomically.
  981. //
  982. KeSetEvent(ServerEvent, EVENT_INCREMENT, TRUE);
  983. return KeWaitForSingleObject(ClientEvent,
  984. WrEventPair,
  985. (KPROCESSOR_MODE)WaitMode,
  986. FALSE,
  987. NULL);
  988. }
  989. PLARGE_INTEGER
  990. FASTCALL
  991. KiComputeWaitInterval (
  992. IN PLARGE_INTEGER OriginalTime,
  993. IN PLARGE_INTEGER DueTime,
  994. IN OUT PLARGE_INTEGER NewTime
  995. )
  996. /*++
  997. Routine Description:
  998. This function recomputes the wait interval after a thread has been
  999. awakened to deliver a kernel APC.
  1000. Arguments:
  1001. OriginalTime - Supplies a pointer to the original timeout value.
  1002. DueTime - Supplies a pointer to the previous due time.
  1003. NewTime - Supplies a pointer to a variable that receives the
  1004. recomputed wait interval.
  1005. Return Value:
  1006. A pointer to the new time is returned as the function value.
  1007. --*/
  1008. {
  1009. //
  1010. // If the original wait time was absolute, then return the same
  1011. // absolute time. Otherwise, reduce the wait time remaining before
  1012. // the time delay expires.
  1013. //
  1014. if (OriginalTime->HighPart >= 0) {
  1015. return OriginalTime;
  1016. } else {
  1017. KiQueryInterruptTime(NewTime);
  1018. NewTime->QuadPart -= DueTime->QuadPart;
  1019. return NewTime;
  1020. }
  1021. }
  1022. VOID
  1023. FASTCALL
  1024. KiWaitForFastMutexEvent (
  1025. IN PFAST_MUTEX Mutex
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. This function increments the fast mutex contention count and waits on
  1030. the event assocated with the fast mutex.
  1031. Arguments:
  1032. Mutex - Supplies a pointer to a fast mutex.
  1033. Return Value:
  1034. None.
  1035. --*/
  1036. {
  1037. //
  1038. // Increment contention count and wait for ownership to be granted.
  1039. //
  1040. Mutex->Contention += 1;
  1041. KeWaitForSingleObject(&Mutex->Event, WrMutex, KernelMode, FALSE, NULL);
  1042. return;
  1043. }
  1044. VOID
  1045. FASTCALL
  1046. KiWaitForGuardedMutexEvent (
  1047. IN PKGUARDED_MUTEX Mutex
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. This function increments the guarded mutex contention count and waits on
  1052. the event assocated with the guarded mutex.
  1053. Arguments:
  1054. Mutex - Supplies a pointer to a guarded mutex.
  1055. Return Value:
  1056. None.
  1057. --*/
  1058. {
  1059. //
  1060. // Increment contention count and wait for ownership to be granted.
  1061. //
  1062. Mutex->Contention += 1;
  1063. KeWaitForSingleObject(&Mutex->Event, WrMutex, KernelMode, FALSE, NULL);
  1064. return;
  1065. }