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.

3068 lines
70 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. queue.c
  5. Abstract:
  6. Generic efficient queue package.
  7. Author:
  8. John Vert (jvert) 12-Jan-1996
  9. Revision History:
  10. David Orbits (davidor) 23-Apr-1997
  11. Added command packet routines.
  12. Added interlocked list routines.
  13. Introduction
  14. A striped queue is really just a list of queues that are managed as a single
  15. queue. When a caller request a queue entry, the first entry for the queue at
  16. the head of the list is returned and that queue is moved to the tail of the
  17. list to prevent starvation of the other queues on the list. Callers sleep when
  18. none of the queues have entries. The caller must be ready to accept an entry
  19. from any queue. Striped queues allow a caller to serialize access to a
  20. sub-queue.
  21. Structures
  22. The same structure is used for both the queue and the controlling queue.
  23. A controlling queue plus its component queues are termed a striped queue.
  24. There is no striped queue structure. The struct contains the following:
  25. - critical section for locking
  26. - List head for entries
  27. - Address of the controlling queue
  28. - List head for Full queues
  29. - List head for Empty queues
  30. - List head for Idled queues
  31. - Count of the number of entries on a queue
  32. - Count of the number of entries on all controlled queues
  33. Initializing
  34. A non-striped (regular) queue is created with:
  35. FrsRtlInitializeQueue(Queue, Queue)
  36. A striped queue controlled by ControlQueue and composed of QueueA and QueueB
  37. is created with:
  38. FrsRtlInitializeQueue(ControlQueue, ControlQueue)
  39. FrsRtlInitializeQueue(QueueA, ControlQueue)
  40. FrsRtlInitializeQueue(QueueB, ControlQueue)
  41. Queues can be added and deleted from the stripe at any time.
  42. Idling Queues
  43. The controlling queue for a striped queue maintains a list of Full queues,
  44. Empty queues, and Idled queues. A striped queue allows a caller to serialize
  45. access to a queue by "idling" the queue. No other thread is allowed to pull
  46. an entry from the queue until the caller "UnIdles" the queue:
  47. Entry = FrsRtlRemoveHeadTimeoutIdled(Queue, 0, &IdledQueue)
  48. Process Entry
  49. FrsRtlUnIdledQueue(IdledQueue);
  50. Entries can be inserted to an idled queue and they can be removed with
  51. FrsRtlRemoveQueueEntry().
  52. Non-Striped queues do not support the serializing "idling" feature. The
  53. IdledQueue parameter is ignored.
  54. Inserting Entries
  55. Use the normal queue insertion routines for queues, striped queues, and idled
  56. queues. DO NOT insert into the controlling queue if this is a striped queue.
  57. Removing Entries
  58. Use the normal queue removal routines for queues, striped queues, and idled
  59. queues. Removals from a striped queue will return an entry from any of the
  60. sub-queues except for idled sub-queues. The FrsRtlRemoveQueueEntry() function
  61. will remove an entry from even an idled queue.
  62. Functions
  63. DbgCheckLinkage - Checks all of the linkage in a queue
  64. FrsRtlInitializeQueue - Initializes any queue
  65. FrsRtlDeleteQueue - Cleans up any queue
  66. FrsRtlRundownQueue - Aborts the queue and returns a list of entries
  67. FrsRtlUnIdledQueue - Moves a queue from the idle to one of the active lists
  68. FrsRtlRemoveHeadQueue - Remove the head of the queue
  69. FrsRtlRemoveHeadQueueTimeout - Remove the head of the queue
  70. FrsRtlRemoveHeadQueueTimeoutIdled - Remove the head of the queue
  71. FrsRtlRemoveEntryQueueLock - Remove entry from locked queue
  72. FrsRtlInsertTailQueue - Insert entry into queue at tail
  73. FrsRtlInsertTailQueueLock - Insert entry into locked queue at head
  74. FrsRtlInsertHeadQueue - Insert entry into queue at tail
  75. FrsRtlInsertHeadQueueLock - Insert entry into locked queue at head
  76. FrsRtlWaitForQueueFull - wait for an entry to appear on the queue
  77. Rundown
  78. Calling rundown on the controlling queue is NOT supported. Don't do that
  79. Running down a component queue does not rundown the controlling queue.
  80. The abort event is set in the controlling queue when the last component
  81. queue is rundown.
  82. --*/
  83. #include <ntreppch.h>
  84. #pragma hdrstop
  85. #include <frs.h>
  86. VOID
  87. FrsCompleteSynchronousCmdPkt(
  88. IN PCOMMAND_PACKET CmdPkt,
  89. IN PVOID CompletionArg
  90. );
  91. //
  92. // This is the command packet schedule queue. It is used when you need to
  93. // queue a command packet to be processed in the future.
  94. //
  95. FRS_QUEUE FrsScheduleQueue;
  96. // #define PRINT_QUEUE(_S_, _Q_) PrintQueue(_S_, _Q_)
  97. #define PRINT_QUEUE(_S_, _Q_)
  98. VOID
  99. PrintQueue(
  100. IN ULONG Sev,
  101. IN PFRS_QUEUE Queue
  102. )
  103. /*++
  104. Routine Description:
  105. Print the queue
  106. Arguments:
  107. Sev - dprint severity
  108. Queue - Supplies a pointer to a queue structure to check
  109. Return Value:
  110. None.
  111. --*/
  112. {
  113. #undef DEBSUB
  114. #define DEBSUB "PrintQueue:"
  115. DWORD Count;
  116. DWORD ControlCount;
  117. BOOL FoundFull;
  118. BOOL FoundEmpty;
  119. BOOL FoundIdled;
  120. PLIST_ENTRY Entry;
  121. PLIST_ENTRY OtherEntry;
  122. PFRS_QUEUE OtherQueue;
  123. PFRS_QUEUE Control;
  124. DPRINT1(0, "***** Print Queue %08x *****\n", Queue);
  125. Control = Queue->Control;
  126. if (Queue == Control) {
  127. DPRINT1(Sev, "\tQueue : %08x\n", Queue);
  128. DPRINT1(Sev, "\tCount : %8d\n", Queue->Count);
  129. DPRINT1(Sev, "\tControlCount: %8d\n", Queue->ControlCount);
  130. DPRINT1(Sev, "\tRundown : %s\n", (Queue->IsRunDown) ? "TRUE" : "FALSE");
  131. DPRINT1(Sev, "\tIdled : %s\n", (Queue->IsIdled) ? "TRUE" : "FALSE");
  132. return;
  133. }
  134. DPRINT2(Sev, "\tControl : %08x for %08x\n", Control, Queue);
  135. DPRINT1(Sev, "\tCount : %8d\n", Control->Count);
  136. DPRINT1(Sev, "\tControlCount: %8d\n", Control->ControlCount);
  137. DPRINT1(Sev, "\tRundown : %s\n", (Control->IsRunDown) ? "TRUE" : "FALSE");
  138. DPRINT1(Sev, "\tIdled : %s\n", (Control->IsIdled) ? "TRUE" : "FALSE");
  139. //
  140. // Full list
  141. //
  142. DPRINT(Sev, "\tFULL\n");
  143. for (Entry = GetListNext(&Control->Full);
  144. Entry != &Control->Full;
  145. Entry = GetListNext(Entry)) {
  146. OtherQueue = CONTAINING_RECORD(Entry, FRS_QUEUE, Full);
  147. if (OtherQueue == Queue) {
  148. DPRINT(Sev, "\t\tTHIS QUEUE\n");
  149. }
  150. DPRINT1(Sev, "\t\tQueue : %08x\n", OtherQueue);
  151. DPRINT1(Sev, "\t\tCount : %8d\n", OtherQueue->Count);
  152. DPRINT1(Sev, "\t\tControlCount: %8d\n", OtherQueue->ControlCount);
  153. DPRINT1(Sev, "\t\tRundown : %s\n", (OtherQueue->IsRunDown) ? "TRUE" : "FALSE");
  154. DPRINT1(Sev, "\t\tIdled : %s\n", (OtherQueue->IsIdled) ? "TRUE" : "FALSE");
  155. }
  156. //
  157. // Empty list
  158. //
  159. DPRINT(Sev, "\tEMPTY\n");
  160. for (Entry = GetListNext(&Control->Empty);
  161. Entry != &Control->Empty;
  162. Entry = GetListNext(Entry)) {
  163. OtherQueue = CONTAINING_RECORD(Entry, FRS_QUEUE, Empty);
  164. if (OtherQueue == Queue) {
  165. DPRINT(Sev, "\t\tTHIS QUEUE\n");
  166. }
  167. DPRINT1(Sev, "\t\tQueue : %08x\n", OtherQueue);
  168. DPRINT1(Sev, "\t\tCount : %8d\n", OtherQueue->Count);
  169. DPRINT1(Sev, "\t\tControlCount: %8d\n", OtherQueue->ControlCount);
  170. DPRINT1(Sev, "\t\tRundown : %s\n", (OtherQueue->IsRunDown) ? "TRUE" : "FALSE");
  171. DPRINT1(Sev, "\t\tIdled : %s\n", (OtherQueue->IsIdled) ? "TRUE" : "FALSE");
  172. }
  173. //
  174. // Idle list
  175. //
  176. DPRINT(Sev, "\tIDLE\n");
  177. for (Entry = GetListNext(&Control->Idled);
  178. Entry != &Control->Idled;
  179. Entry = GetListNext(Entry)) {
  180. OtherQueue = CONTAINING_RECORD(Entry, FRS_QUEUE, Idled);
  181. if (OtherQueue == Queue) {
  182. DPRINT(Sev, "\t\tTHIS QUEUE\n");
  183. }
  184. DPRINT1(Sev, "\t\tQueue : %08x\n", OtherQueue);
  185. DPRINT1(Sev, "\t\tCount : %8d\n", OtherQueue->Count);
  186. DPRINT1(Sev, "\t\tControlCount: %8d\n", OtherQueue->ControlCount);
  187. DPRINT1(Sev, "\t\tRundown : %s\n", (OtherQueue->IsRunDown) ? "TRUE" : "FALSE");
  188. DPRINT1(Sev, "\t\tIdled : %s\n", (OtherQueue->IsIdled) ? "TRUE" : "FALSE");
  189. }
  190. }
  191. BOOL
  192. DbgCheckQueue(
  193. PFRS_QUEUE Queue
  194. )
  195. /*++
  196. Routine Description:
  197. Check the consistency of the queue
  198. Arguments:
  199. Queue - Supplies a pointer to a queue structure to check
  200. Return Value:
  201. TRUE - everything is okay
  202. Assert - assert error
  203. --*/
  204. {
  205. #undef DEBSUB
  206. #define DEBSUB "DbgCheckQueue:"
  207. DWORD Count;
  208. DWORD ControlCount;
  209. BOOL FoundFull;
  210. BOOL FoundEmpty;
  211. BOOL FoundIdled;
  212. PLIST_ENTRY Entry;
  213. PLIST_ENTRY OtherEntry;
  214. PFRS_QUEUE OtherQueue;
  215. PFRS_QUEUE Control;
  216. if (!DebugInfo.Queues) {
  217. return TRUE;
  218. }
  219. FRS_ASSERT(Queue);
  220. Control = Queue->Control;
  221. FRS_ASSERT(Control);
  222. if (Control->IsRunDown) {
  223. FRS_ASSERT(Control->ControlCount == 0);
  224. FRS_ASSERT(Queue->IsRunDown);
  225. FRS_ASSERT(IsListEmpty(&Control->Full));
  226. FRS_ASSERT(IsListEmpty(&Control->Empty));
  227. FRS_ASSERT(IsListEmpty(&Control->Idled));
  228. }
  229. if (Queue->IsRunDown) {
  230. FRS_ASSERT(Queue->Count == 0);
  231. FRS_ASSERT(IsListEmpty(&Queue->Full));
  232. FRS_ASSERT(IsListEmpty(&Queue->Empty));
  233. FRS_ASSERT(IsListEmpty(&Queue->Idled));
  234. }
  235. FRS_ASSERT(!Control->IsIdled);
  236. //
  237. // Check Full list
  238. //
  239. ControlCount = 0;
  240. FoundFull = FALSE;
  241. Entry = &Control->Full;
  242. do {
  243. Entry = GetListNext(Entry);
  244. OtherQueue = CONTAINING_RECORD(Entry, FRS_QUEUE, Full);
  245. if (OtherQueue == Queue) {
  246. FoundFull = TRUE;
  247. }
  248. FRS_ASSERT(Control == OtherQueue ||
  249. (!OtherQueue->IsRunDown && !OtherQueue->IsIdled));
  250. Count = 0;
  251. if (!IsListEmpty(&OtherQueue->ListHead)) {
  252. OtherEntry = GetListNext(&OtherQueue->ListHead);
  253. do {
  254. ++Count;
  255. ++ControlCount;
  256. OtherEntry = GetListNext(OtherEntry);
  257. } while (OtherEntry != &OtherQueue->ListHead);
  258. }
  259. FRS_ASSERT(Count == OtherQueue->Count);
  260. } while (OtherQueue != Control);
  261. FRS_ASSERT(ControlCount == Control->ControlCount ||
  262. (Control == Queue && Control->ControlCount == 0));
  263. //
  264. // Check Empty list
  265. //
  266. ControlCount = 0;
  267. FoundEmpty = FALSE;
  268. Entry = &Control->Empty;
  269. do {
  270. Entry = GetListNext(Entry);
  271. OtherQueue = CONTAINING_RECORD(Entry, FRS_QUEUE, Empty);
  272. if (OtherQueue == Queue) {
  273. FoundEmpty = TRUE;
  274. }
  275. FRS_ASSERT(Control == OtherQueue ||
  276. (!OtherQueue->IsRunDown && !OtherQueue->IsIdled));
  277. Count = 0;
  278. if (!IsListEmpty(&OtherQueue->ListHead)) {
  279. OtherEntry = GetListNext(&OtherQueue->ListHead);
  280. do {
  281. ++Count;
  282. ++ControlCount;
  283. OtherEntry = GetListNext(OtherEntry);
  284. } while (OtherEntry != &OtherQueue->ListHead);
  285. }
  286. FRS_ASSERT(Count == OtherQueue->Count);
  287. } while (OtherQueue != Control);
  288. //
  289. // Check Idled list
  290. //
  291. FoundIdled = FALSE;
  292. Entry = &Control->Idled;
  293. do {
  294. Entry = GetListNext(Entry);
  295. OtherQueue = CONTAINING_RECORD(Entry, FRS_QUEUE, Idled);
  296. if (OtherQueue == Queue) {
  297. FoundIdled = TRUE;
  298. }
  299. FRS_ASSERT(Control == OtherQueue || OtherQueue->IsIdled);
  300. Count = 0;
  301. if (!IsListEmpty(&OtherQueue->ListHead)) {
  302. OtherEntry = GetListNext(&OtherQueue->ListHead);
  303. do {
  304. ++Count;
  305. OtherEntry = GetListNext(OtherEntry);
  306. } while (OtherEntry != &OtherQueue->ListHead);
  307. }
  308. FRS_ASSERT(Count == OtherQueue->Count);
  309. } while (OtherQueue != Control);
  310. //
  311. // Verify state
  312. //
  313. FRS_ASSERT((Queue->Count && !IsListEmpty(&Queue->ListHead)) ||
  314. (!Queue->Count && IsListEmpty(&Queue->ListHead)));
  315. if (Control == Queue) {
  316. //
  317. // We are our own controlling queue
  318. //
  319. FRS_ASSERT(FoundFull && FoundEmpty && FoundIdled);
  320. } else {
  321. //
  322. // Controlled by a separate queue
  323. //
  324. if (Queue->IsRunDown) {
  325. FRS_ASSERT(!FoundFull && !FoundEmpty && !FoundIdled && !Queue->Count);
  326. } else {
  327. FRS_ASSERT(FoundFull || FoundEmpty || FoundIdled);
  328. }
  329. if (FoundFull) {
  330. FRS_ASSERT(!FoundEmpty && !FoundIdled && Queue->Count);
  331. } else if (FoundEmpty) {
  332. FRS_ASSERT(!FoundFull && !FoundIdled && !Queue->Count);
  333. } else if (FoundIdled) {
  334. FRS_ASSERT(!FoundFull && !FoundEmpty);
  335. }
  336. }
  337. return TRUE;
  338. }
  339. VOID
  340. FrsInitializeQueue(
  341. PFRS_QUEUE Queue,
  342. PFRS_QUEUE Control
  343. )
  344. /*++
  345. Routine Description:
  346. Initializes a queue for use.
  347. Arguments:
  348. Queue - Supplies a pointer to a queue structure to initialize
  349. Return Value:
  350. ERROR_SUCCESS if successful
  351. Win32 error code otherwise.
  352. --*/
  353. {
  354. #undef DEBSUB
  355. #define DEBSUB "FrsInitializeQueue:"
  356. ZeroMemory(Queue, sizeof(FRS_QUEUE));
  357. InitializeListHead(&Queue->ListHead);
  358. InitializeListHead(&Queue->Full);
  359. InitializeListHead(&Queue->Empty);
  360. InitializeListHead(&Queue->Idled);
  361. INITIALIZE_CRITICAL_SECTION(&Queue->Lock);
  362. Queue->IsRunDown = FALSE;
  363. Queue->IsIdled = FALSE;
  364. Queue->Control = Control;
  365. Queue->InitTime = GetTickCount();
  366. if (Control->IsRunDown) {
  367. Queue->IsRunDown = TRUE;
  368. return;
  369. }
  370. //
  371. // Begin life on the empty queue
  372. //
  373. FrsRtlAcquireQueueLock(Queue);
  374. InsertTailList(&Control->Empty, &Queue->Empty);
  375. FRS_ASSERT(DbgCheckQueue(Queue));
  376. FrsRtlReleaseQueueLock(Queue);
  377. //
  378. // The controlling queue supplies the events so there is no
  379. // need to create extraneous events.
  380. //
  381. if (Queue == Control) {
  382. Queue->Event = FrsCreateEvent(TRUE, FALSE);
  383. Queue->RunDown = FrsCreateEvent(TRUE, FALSE);
  384. }
  385. }
  386. VOID
  387. FrsRtlDeleteQueue(
  388. IN PFRS_QUEUE Queue
  389. )
  390. /*++
  391. Routine Description:
  392. Releases all resources used by a queue.
  393. Arguments:
  394. Queue - supplies the queue to be deleted
  395. Return Value:
  396. None.
  397. --*/
  398. {
  399. #undef DEBSUB
  400. #define DEBSUB "FrsRtlDeleteQueue:"
  401. PFRS_QUEUE Control;
  402. Control = Queue->Control;
  403. if (Queue == Control) {
  404. FRS_ASSERT(IsListEmpty(&Queue->Full) &&
  405. IsListEmpty(&Queue->Empty) &&
  406. IsListEmpty(&Queue->Idled));
  407. } else {
  408. FRS_ASSERT(IsListEmpty(&Queue->ListHead));
  409. }
  410. EnterCriticalSection(&Control->Lock);
  411. FRS_ASSERT(DbgCheckQueue(Queue));
  412. RemoveEntryListB(&Queue->Full);
  413. RemoveEntryListB(&Queue->Empty);
  414. RemoveEntryListB(&Queue->Idled);
  415. Control->ControlCount -= Queue->Count;
  416. FRS_ASSERT(DbgCheckQueue(Queue));
  417. LeaveCriticalSection(&Control->Lock);
  418. DeleteCriticalSection(&Queue->Lock);
  419. //
  420. // Only the controlling queue has valid handles
  421. //
  422. if (Queue == Control) {
  423. FRS_CLOSE(Queue->Event);
  424. FRS_CLOSE(Queue->RunDown);
  425. }
  426. //
  427. // Zero the memory in order to cause grief for those who
  428. // use a deleted queue.
  429. //
  430. ZeroMemory(Queue, sizeof(FRS_QUEUE));
  431. }
  432. VOID
  433. FrsRtlRunDownQueue(
  434. IN PFRS_QUEUE Queue,
  435. OUT PLIST_ENTRY ListHead
  436. )
  437. /*++
  438. Routine Description:
  439. Runs down a queue that is about to be destroyed. Any threads currently
  440. waiting on the queue are unwaited (FrsRtlRemoveHeadQueue will return NULL)
  441. and the contents of the queue (if any) are returned to the caller for
  442. cleanup.
  443. Arguments:
  444. Queue - supplies the queue to be rundown
  445. ListHead - returns the list of items currently in the queue.
  446. Return Value:
  447. None.
  448. --*/
  449. {
  450. #undef DEBSUB
  451. #define DEBSUB "FrsRtlRunDownQueue:"
  452. PFRS_QUEUE Control = Queue->Control;
  453. PLIST_ENTRY Entry;
  454. PLIST_ENTRY First;
  455. PLIST_ENTRY Last;
  456. EnterCriticalSection(&Control->Lock);
  457. //
  458. // Running down a controlling queue is not allowed unless they
  459. // are the same queue.
  460. //
  461. if (Control == Queue) {
  462. FRS_ASSERT(IsListEmpty(&Control->Full) &&
  463. IsListEmpty(&Control->Empty) &&
  464. IsListEmpty(&Control->Idled));
  465. } else {
  466. FRS_ASSERT(!IsListEmpty(&Control->Full) ||
  467. !IsListEmpty(&Control->Empty) ||
  468. !IsListEmpty(&Control->Idled) ||
  469. Control->IsRunDown);
  470. }
  471. /*
  472. FRS_ASSERT((Control == Queue &&
  473. IsListEmpty(&Control->Full) &&
  474. IsListEmpty(&Control->Empty) &&
  475. IsListEmpty(&Control->Idled)
  476. )
  477. ||
  478. (Control != Queue &&
  479. (!IsListEmpty(&Control->Full) ||
  480. !IsListEmpty(&Control->Empty) ||
  481. !IsListEmpty(&Control->Idled) ||
  482. Control->IsRunDown
  483. )
  484. )
  485. )
  486. */
  487. FRS_ASSERT(DbgCheckQueue(Queue));
  488. Queue->IsRunDown = TRUE;
  489. //
  490. // return the list of entries
  491. //
  492. if (IsListEmpty(&Queue->ListHead)) {
  493. InitializeListHead(ListHead);
  494. } else {
  495. *ListHead = Queue->ListHead;
  496. ListHead->Flink->Blink = ListHead;
  497. ListHead->Blink->Flink = ListHead;
  498. }
  499. InitializeListHead(&Queue->ListHead);
  500. //
  501. // Don't update counters if the queue is idled
  502. //
  503. if (!Queue->IsIdled) {
  504. Control->ControlCount -= Queue->Count;
  505. if (Control->ControlCount == 0) {
  506. ResetEvent(Control->Event);
  507. }
  508. }
  509. Queue->Count = 0;
  510. RemoveEntryListB(&Queue->Full);
  511. RemoveEntryListB(&Queue->Empty);
  512. RemoveEntryListB(&Queue->Idled);
  513. FRS_ASSERT(DbgCheckQueue(Queue));
  514. //
  515. // Set the aborted event to awaken any threads currently
  516. // blocked on the queue if the controlling queue has no
  517. // more queues.
  518. //
  519. DPRINT2(4, "Rundown for queue - %08x, Control - %08x\n", Queue, Control);
  520. DPRINT1(4, "Control->Full queue %s empty.\n",
  521. IsListEmpty(&Control->Full) ? "is" : "is not");
  522. DPRINT1(4, "Control->Empty queue %s empty.\n",
  523. IsListEmpty(&Control->Empty) ? "is" : "is not");
  524. DPRINT1(4, "Control->Idled queue %s empty.\n",
  525. IsListEmpty(&Control->Idled) ? "is" : "is not");
  526. if (IsListEmpty(&Control->Full) &&
  527. IsListEmpty(&Control->Empty) &&
  528. IsListEmpty(&Control->Idled)) {
  529. Control->IsRunDown = TRUE;
  530. SetEvent(Control->RunDown);
  531. DPRINT(4, "Setting Control->RunDown event.\n");
  532. }
  533. FRS_ASSERT(DbgCheckQueue(Control));
  534. LeaveCriticalSection(&Control->Lock);
  535. }
  536. VOID
  537. FrsRtlCancelQueue(
  538. IN PFRS_QUEUE Queue,
  539. OUT PLIST_ENTRY ListHead
  540. )
  541. /*++
  542. Routine Description:
  543. Returns the entries on Queue for cancelling.
  544. Arguments:
  545. Queue - supplies the queue to be rundown
  546. ListHead - returns the list of items currently in the queue.
  547. Return Value:
  548. None.
  549. --*/
  550. {
  551. #undef DEBSUB
  552. #define DEBSUB "FrsRtlCancelQueue:"
  553. PFRS_QUEUE Control = Queue->Control;
  554. PLIST_ENTRY Entry;
  555. PLIST_ENTRY First;
  556. PLIST_ENTRY Last;
  557. EnterCriticalSection(&Control->Lock);
  558. FRS_ASSERT(DbgCheckQueue(Queue));
  559. //
  560. // return the list of entries
  561. //
  562. if (IsListEmpty(&Queue->ListHead)) {
  563. InitializeListHead(ListHead);
  564. } else {
  565. *ListHead = Queue->ListHead;
  566. ListHead->Flink->Blink = ListHead;
  567. ListHead->Blink->Flink = ListHead;
  568. }
  569. InitializeListHead(&Queue->ListHead);
  570. //
  571. // Don't update counters if the queue is idled
  572. //
  573. if (!Queue->IsIdled) {
  574. Control->ControlCount -= Queue->Count;
  575. if (Control->ControlCount == 0) {
  576. ResetEvent(Control->Event);
  577. }
  578. }
  579. Queue->Count = 0;
  580. RemoveEntryListB(&Queue->Full);
  581. RemoveEntryListB(&Queue->Empty);
  582. RemoveEntryListB(&Queue->Idled);
  583. FRS_ASSERT(DbgCheckQueue(Queue));
  584. FRS_ASSERT(DbgCheckQueue(Control));
  585. LeaveCriticalSection(&Control->Lock);
  586. }
  587. VOID
  588. FrsRtlIdleQueue(
  589. IN PFRS_QUEUE Queue
  590. )
  591. {
  592. #undef DEBSUB
  593. #define DEBSUB "FrsRtlIdleQueue:"
  594. /*++
  595. Routine Description:
  596. Idle a queue
  597. Arguments:
  598. Queue - queue to idle
  599. Return Value:
  600. None.
  601. --*/
  602. PFRS_QUEUE Control = Queue->Control;
  603. //
  604. // Queues that don't have a separate controlling queue can't
  605. // support "idling" themselves
  606. //
  607. if (Control == Queue) {
  608. return;
  609. }
  610. //
  611. // Lock the controlling queue
  612. //
  613. EnterCriticalSection(&Control->Lock);
  614. FrsRtlIdleQueueLock(Queue);
  615. LeaveCriticalSection(&Control->Lock);
  616. }
  617. VOID
  618. FrsRtlIdleQueueLock(
  619. IN PFRS_QUEUE Queue
  620. )
  621. {
  622. #undef DEBSUB
  623. #define DEBSUB "FrsRtlIdleQueueLock:"
  624. /*++
  625. Routine Description:
  626. Idle a queue. Caller has the lock already.
  627. Arguments:
  628. Queue - queue to idle
  629. Return Value:
  630. None.
  631. --*/
  632. PFRS_QUEUE Control = Queue->Control;
  633. //
  634. // Queues that don't have a separate controlling queue can't
  635. // support "idling" themselves
  636. //
  637. if (Control == Queue) {
  638. return;
  639. }
  640. PRINT_QUEUE(5, Queue);
  641. FRS_ASSERT(DbgCheckQueue(Queue));
  642. //
  643. // Stop, this queue has been aborted (rundown)
  644. //
  645. if (Queue->IsRunDown || Queue->IsIdled) {
  646. goto out;
  647. }
  648. if (Queue->Count == 0) {
  649. RemoveEntryListB(&Queue->Empty);
  650. } else {
  651. RemoveEntryListB(&Queue->Full);
  652. }
  653. FRS_ASSERT(IsListEmpty(&Queue->Idled));
  654. InsertTailList(&Control->Idled, &Queue->Idled);
  655. Queue->IsIdled = TRUE;
  656. Control->ControlCount -= Queue->Count;
  657. FRS_ASSERT(DbgCheckQueue(Queue));
  658. if (Control->ControlCount == 0) {
  659. ResetEvent(Control->Event);
  660. }
  661. out:
  662. //
  663. // Done
  664. //
  665. FRS_ASSERT(DbgCheckQueue(Queue));
  666. }
  667. VOID
  668. FrsRtlUnIdledQueue(
  669. IN PFRS_QUEUE IdledQueue
  670. )
  671. {
  672. #undef DEBSUB
  673. #define DEBSUB "FrsRtlUnIdledQueue:"
  674. /*++
  675. Routine Description:
  676. Removes the queue from the "idled" list and puts it back on the
  677. full or empty lists. The controlling queue is updated accordingly.
  678. Arguments:
  679. IdledQueue - Supplies the queue to remove an item from.
  680. Return Value:
  681. None.
  682. --*/
  683. DWORD OldControlCount;
  684. PFRS_QUEUE Control = IdledQueue->Control;
  685. //
  686. // Queues that don't have a separate controlling queue can't
  687. // support "idling" themselves
  688. //
  689. if (Control == IdledQueue) {
  690. return;
  691. }
  692. //
  693. // Lock the controlling queue
  694. //
  695. EnterCriticalSection(&Control->Lock);
  696. FrsRtlUnIdledQueueLock(IdledQueue);
  697. LeaveCriticalSection(&Control->Lock);
  698. }
  699. VOID
  700. FrsRtlUnIdledQueueLock(
  701. IN PFRS_QUEUE IdledQueue
  702. )
  703. {
  704. #undef DEBSUB
  705. #define DEBSUB "FrsRtlUnIdledQueueLock:"
  706. /*++
  707. Routine Description:
  708. Removes the queue from the "idled" list and puts it back on the
  709. full or empty lists. The controlling queue is updated accordingly.
  710. Caller has lock on controlling queue.
  711. Arguments:
  712. IdledQueue - Supplies the queue to remove an item from.
  713. Return Value:
  714. None.
  715. --*/
  716. DWORD OldControlCount;
  717. PFRS_QUEUE Control = IdledQueue->Control;
  718. //
  719. // Queues that don't have a separate controlling queue can't
  720. // support "idling" themselves
  721. //
  722. if (Control == IdledQueue) {
  723. return;
  724. }
  725. PRINT_QUEUE(5, IdledQueue);
  726. FRS_ASSERT(DbgCheckQueue(IdledQueue));
  727. //
  728. // Stop, this queue has been aborted (rundown)
  729. //
  730. if (IdledQueue->IsRunDown) {
  731. goto out;
  732. }
  733. //
  734. // Remove from idled list
  735. //
  736. FRS_ASSERT(IdledQueue->IsIdled);
  737. RemoveEntryListB(&IdledQueue->Idled);
  738. IdledQueue->IsIdled = FALSE;
  739. //
  740. // Put onto full or empty list
  741. //
  742. if (IdledQueue->Count) {
  743. InsertTailList(&Control->Full, &IdledQueue->Full);
  744. } else {
  745. InsertTailList(&Control->Empty, &IdledQueue->Empty);
  746. }
  747. //
  748. // Wakeup sleepers if count is now > 0
  749. //
  750. OldControlCount = Control->ControlCount;
  751. Control->ControlCount += IdledQueue->Count;
  752. if (Control->ControlCount && OldControlCount == 0) {
  753. SetEvent(Control->Event);
  754. }
  755. //
  756. // Done
  757. //
  758. out:
  759. FRS_ASSERT(DbgCheckQueue(IdledQueue));
  760. }
  761. PLIST_ENTRY
  762. FrsRtlRemoveHeadQueueTimeoutIdled(
  763. IN PFRS_QUEUE Queue,
  764. IN DWORD dwMilliseconds,
  765. OUT PFRS_QUEUE *IdledQueue
  766. )
  767. /*++
  768. Routine Description:
  769. Removes the item at the head of the queue. If the queue is empty,
  770. blocks until an item is inserted into the queue.
  771. Arguments:
  772. Queue - Supplies the queue to remove an item from.
  773. Timeout - Supplies a timeout value that specifies the relative
  774. time, in milliseconds, over which the wait is to be completed.
  775. IdledQueue - If non-NULL then on return this will be the address
  776. of the queue from which the entry was retrieved. Or NULL if
  777. the returned entry is NULL. No other thread will be allowed
  778. to pull an entry from the returned queue until that queue is
  779. released with FrsRtlUnIdledQueue(*IdledQueue).
  780. Return Value:
  781. Pointer to list entry removed from the head of the queue.
  782. NULL if the wait times out or the queue is run down. If this
  783. routine returns NULL, GetLastError will return either
  784. ERROR_INVALID_HANDLE (if the queue has been rundown) or
  785. WAIT_TIMEOUT (to indicate a timeout has occurred)
  786. IdledQueue - If non-NULL then on return this will be the address
  787. of the queue from which the entry was retrieved. Or NULL if
  788. the returned entry is NULL. No other thread will be allowed
  789. to pull an entry from the returned queue until that queue is
  790. released with FrsRtlUnIdledQueue(*IdledQueue).
  791. --*/
  792. {
  793. #undef DEBSUB
  794. #define DEBSUB "FrsRtlRemoveHeadQueueTimeoutIdled:"
  795. DWORD Status;
  796. PLIST_ENTRY Entry;
  797. HANDLE WaitArray[2];
  798. PFRS_QUEUE Control = Queue->Control;
  799. //
  800. // No idled queue at this time
  801. //
  802. if (IdledQueue) {
  803. *IdledQueue = NULL;
  804. }
  805. Retry:
  806. if (Control->ControlCount == 0) {
  807. //
  808. // Block until something is inserted on the queue
  809. //
  810. WaitArray[0] = Control->RunDown;
  811. WaitArray[1] = Control->Event;
  812. Status = WaitForMultipleObjects(2, WaitArray, FALSE, dwMilliseconds);
  813. if (Status == 0) {
  814. //
  815. // The queue has been rundown, return NULL immediately.
  816. //
  817. SetLastError(ERROR_INVALID_HANDLE);
  818. return(NULL);
  819. } else if (Status == WAIT_TIMEOUT) {
  820. SetLastError(WAIT_TIMEOUT);
  821. return(NULL);
  822. }
  823. FRS_ASSERT(Status == 1);
  824. }
  825. //
  826. // Lock the queue and try to remove something
  827. //
  828. EnterCriticalSection(&Control->Lock);
  829. PRINT_QUEUE(5, Queue);
  830. if (Control->ControlCount == 0) {
  831. //
  832. // Somebody got here before we did, drop the lock and retry
  833. //
  834. LeaveCriticalSection(&Control->Lock);
  835. goto Retry;
  836. }
  837. FRS_ASSERT(DbgCheckQueue(Queue));
  838. Entry = GetListNext(&Control->Full);
  839. RemoveEntryListB(Entry);
  840. Queue = CONTAINING_RECORD(Entry, FRS_QUEUE, Full);
  841. Entry = RemoveHeadList(&Queue->ListHead);
  842. //
  843. // update counters
  844. //
  845. --Queue->Count;
  846. --Control->ControlCount;
  847. //
  848. // A separate controlling queue is required for idling
  849. //
  850. if (IdledQueue && Queue != Control) {
  851. //
  852. // Idle the queue
  853. //
  854. FRS_ASSERT(IsListEmpty(&Queue->Idled));
  855. FRS_ASSERT(!Queue->IsIdled);
  856. InsertTailList(&Control->Idled, &Queue->Idled);
  857. Queue->IsIdled = TRUE;
  858. Control->ControlCount -= Queue->Count;
  859. *IdledQueue = Queue;
  860. } else if (Queue->Count) {
  861. //
  862. // Queue still has entries
  863. //
  864. InsertTailList(&Control->Full, &Queue->Full);
  865. } else {
  866. //
  867. // Queue is empty
  868. //
  869. InsertTailList(&Control->Empty, &Queue->Empty);
  870. }
  871. //
  872. // Queues are empty (or idled)
  873. //
  874. if (Control->ControlCount == 0) {
  875. ResetEvent(Control->Event);
  876. }
  877. PRINT_QUEUE(5, Queue);
  878. FRS_ASSERT(DbgCheckQueue(Queue));
  879. LeaveCriticalSection(&Control->Lock);
  880. return(Entry);
  881. }
  882. PLIST_ENTRY
  883. FrsRtlRemoveHeadQueue(
  884. IN PFRS_QUEUE Queue
  885. )
  886. /*++
  887. Routine Description:
  888. Removes the item at the head of the queue. If the queue is empty,
  889. blocks until an item is inserted into the queue.
  890. Arguments:
  891. Queue - Supplies the queue to remove an item from.
  892. Return Value:
  893. Pointer to list entry removed from the head of the queue.
  894. --*/
  895. {
  896. return(FrsRtlRemoveHeadQueueTimeoutIdled(Queue, INFINITE, NULL));
  897. }
  898. PLIST_ENTRY
  899. FrsRtlRemoveHeadQueueTimeout(
  900. IN PFRS_QUEUE Queue,
  901. IN DWORD dwMilliseconds
  902. )
  903. /*++
  904. Routine Description:
  905. Removes the item at the head of the queue. If the queue is empty,
  906. blocks until an item is inserted into the queue.
  907. Arguments:
  908. Queue - Supplies the queue to remove an item from.
  909. Timeout - Supplies a timeout value that specifies the relative
  910. time, in milliseconds, over which the wait is to be completed.
  911. Return Value:
  912. Pointer to list entry removed from the head of the queue.
  913. NULL if the wait times out or the queue is run down. If this
  914. routine returns NULL, GetLastError will return either
  915. ERROR_INVALID_HANDLE (if the queue has been rundown) or
  916. WAIT_TIMEOUT (to indicate a timeout has occurred)
  917. --*/
  918. {
  919. return(FrsRtlRemoveHeadQueueTimeoutIdled(Queue, dwMilliseconds, NULL));
  920. }
  921. VOID
  922. FrsRtlRemoveEntryQueue(
  923. IN PFRS_QUEUE Queue,
  924. IN PLIST_ENTRY Entry
  925. )
  926. /*++
  927. Routine Description:
  928. Removes the entry from the queue. The entry is assumed to be on the
  929. queue since we derement the queue count.
  930. Arguments:
  931. Queue - Supplies the queue to remove an item from.
  932. Entry - pointer to the entry to remove.
  933. Return Value:
  934. none.
  935. --*/
  936. {
  937. FrsRtlAcquireQueueLock(Queue);
  938. FrsRtlRemoveEntryQueueLock(Queue, Entry);
  939. FrsRtlReleaseQueueLock(Queue);
  940. }
  941. VOID
  942. FrsRtlRemoveEntryQueueLock(
  943. IN PFRS_QUEUE Queue,
  944. IN PLIST_ENTRY Entry
  945. )
  946. /*++
  947. Routine Description:
  948. Removes the entry from the queue. The entry is assumed to be on the
  949. queue since we derement the queue count. We also assume the caller
  950. has acquired the queue lock since this was needed to scan the queue
  951. in the first place to find the entry in question.
  952. The LOCK suffix means the caller has already acquired the lock.
  953. Arguments:
  954. Queue - Supplies the queue to remove an item from.
  955. Entry - pointer to the entry to remove.
  956. Return Value:
  957. none.
  958. --*/
  959. {
  960. #undef DEBSUB
  961. #define DEBSUB "FrsRtlRemoveEntryQueueLock:"
  962. PFRS_QUEUE Control = Queue->Control;
  963. FRS_ASSERT(Queue->Count != 0);
  964. FRS_ASSERT(!IsListEmpty(&Queue->ListHead));
  965. PRINT_QUEUE(5, Queue);
  966. FRS_ASSERT(DbgCheckQueue(Queue));
  967. RemoveEntryListB(Entry);
  968. //
  969. // If the queue is idled then just update the count
  970. //
  971. --Queue->Count;
  972. if (!Queue->IsIdled) {
  973. //
  974. // Queue is empty; remove from full list
  975. //
  976. if (Queue->Count == 0) {
  977. RemoveEntryListB(&Queue->Full);
  978. InsertTailList(&Control->Empty, &Queue->Empty);
  979. }
  980. //
  981. // Control queue is empty
  982. //
  983. if (--Control->ControlCount == 0) {
  984. ResetEvent(Control->Event);
  985. }
  986. }
  987. PRINT_QUEUE(5, Queue);
  988. FRS_ASSERT(DbgCheckQueue(Queue));
  989. return;
  990. }
  991. DWORD
  992. FrsRtlInsertTailQueue(
  993. IN PFRS_QUEUE Queue,
  994. IN PLIST_ENTRY Item
  995. )
  996. /*++
  997. Routine Description:
  998. Inserts a new entry on the tail of the queue.
  999. Arguments:
  1000. Queue - Supplies the queue to add the entry to.
  1001. Item - Supplies the entry to be added to the queue.
  1002. Return Value:
  1003. ERROR_SUCCESS and the item is queueed. Otherwise, the item
  1004. is not queued.
  1005. --*/
  1006. {
  1007. DWORD Status;
  1008. FrsRtlAcquireQueueLock(Queue);
  1009. Status = FrsRtlInsertTailQueueLock(Queue, Item);
  1010. FrsRtlReleaseQueueLock(Queue);
  1011. return Status;
  1012. }
  1013. DWORD
  1014. FrsRtlInsertTailQueueLock(
  1015. IN PFRS_QUEUE Queue,
  1016. IN PLIST_ENTRY Item
  1017. )
  1018. /*++
  1019. Routine Description:
  1020. Inserts a new entry on the tail of the queue. Caller already has the
  1021. queue lock.
  1022. Arguments:
  1023. Queue - Supplies the queue to add the entry to.
  1024. Item - Supplies the entry to be added to the queue.
  1025. Return Value:
  1026. ERROR_SUCCESS and the item is queueed. Otherwise, the item
  1027. is not queued.
  1028. --*/
  1029. {
  1030. #undef DEBSUB
  1031. #define DEBSUB "FrsRtlInsertTailQueueLock:"
  1032. PFRS_QUEUE Control = Queue->Control;
  1033. PRINT_QUEUE(5, Queue);
  1034. FRS_ASSERT(DbgCheckQueue(Queue));
  1035. if (Queue->IsRunDown) {
  1036. return ERROR_ACCESS_DENIED;
  1037. }
  1038. InsertTailList(&Queue->ListHead, Item);
  1039. //
  1040. // If the queue is idled then just update the count
  1041. //
  1042. if (Queue->IsIdled) {
  1043. ++Queue->Count;
  1044. } else {
  1045. //
  1046. // Queue is transitioning from empty to full
  1047. //
  1048. if (++Queue->Count == 1) {
  1049. RemoveEntryListB(&Queue->Empty);
  1050. InsertTailList(&Control->Full, &Queue->Full);
  1051. }
  1052. //
  1053. // Controlling queue is transitioning from empty to full
  1054. //
  1055. if (++Control->ControlCount == 1) {
  1056. SetEvent(Control->Event);
  1057. }
  1058. }
  1059. PRINT_QUEUE(5, Queue);
  1060. FRS_ASSERT(DbgCheckQueue(Queue));
  1061. return ERROR_SUCCESS;
  1062. }
  1063. DWORD
  1064. FrsRtlInsertHeadQueue(
  1065. IN PFRS_QUEUE Queue,
  1066. IN PLIST_ENTRY Item
  1067. )
  1068. /*++
  1069. Routine Description:
  1070. Inserts a new entry on the tail of the queue.
  1071. Arguments:
  1072. Queue - Supplies the queue to add the entry to.
  1073. Item - Supplies the entry to be added to the queue.
  1074. Return Value:
  1075. ERROR_SUCCESS and the item is queueed. Otherwise, the item
  1076. is not queued.
  1077. --*/
  1078. {
  1079. DWORD Status;
  1080. FrsRtlAcquireQueueLock(Queue);
  1081. Status = FrsRtlInsertHeadQueueLock(Queue, Item);
  1082. FrsRtlReleaseQueueLock(Queue);
  1083. return Status;
  1084. }
  1085. DWORD
  1086. FrsRtlInsertHeadQueueLock(
  1087. IN PFRS_QUEUE Queue,
  1088. IN PLIST_ENTRY Item
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. Inserts a new entry on the head of the queue.
  1093. Caller already has the queue lock.
  1094. Arguments:
  1095. Queue - Supplies the queue to add the entry to.
  1096. Item - Supplies the entry to be added to the queue.
  1097. Return Value:
  1098. ERROR_SUCCESS and the item is queueed. Otherwise, the item
  1099. is not queued.
  1100. --*/
  1101. {
  1102. #undef DEBSUB
  1103. #define DEBSUB "FrsRtlInsertHeadQueueLock:"
  1104. PFRS_QUEUE Control = Queue->Control;
  1105. PRINT_QUEUE(5, Queue);
  1106. FRS_ASSERT(DbgCheckQueue(Queue));
  1107. if (Queue->IsRunDown) {
  1108. return ERROR_ACCESS_DENIED;
  1109. }
  1110. InsertHeadList(&Queue->ListHead, Item);
  1111. //
  1112. // If the queue is idled then just update the count
  1113. //
  1114. if (Queue->IsIdled) {
  1115. ++Queue->Count;
  1116. } else {
  1117. //
  1118. // Queue is transitioning from empty to full
  1119. //
  1120. if (++Queue->Count == 1) {
  1121. RemoveEntryListB(&Queue->Empty);
  1122. InsertTailList(&Control->Full, &Queue->Full);
  1123. }
  1124. //
  1125. // Controlling queue is transitioning from empty to full
  1126. //
  1127. if (++Control->ControlCount == 1) {
  1128. SetEvent(Control->Event);
  1129. }
  1130. }
  1131. PRINT_QUEUE(5, Queue);
  1132. FRS_ASSERT(DbgCheckQueue(Queue));
  1133. return ERROR_SUCCESS;
  1134. }
  1135. DWORD
  1136. FrsRtlWaitForQueueFull(
  1137. IN PFRS_QUEUE Queue,
  1138. IN DWORD dwMilliseconds
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. Waits until the queue is non-empty. Returns immediately if queue is
  1143. non-empty else wait on insert or timeout.
  1144. Arguments:
  1145. Queue - Supplies the queue to wait on.
  1146. Timeout - Supplies a timeout value that specifies the relative
  1147. time, in milliseconds, over which the wait is to be completed.
  1148. Return Value:
  1149. Win32 Status:
  1150. ERROR_SUCCESS if queue is now non-empty.
  1151. ERROR_INVALID_HANDLE if the queue has been rundown.
  1152. WAIT_TIMEOUT to indicate a timeout has occurred.
  1153. --*/
  1154. {
  1155. #undef DEBSUB
  1156. #define DEBSUB "FrsRtlWaitForQueueFull:"
  1157. DWORD Status;
  1158. HANDLE WaitArray[2];
  1159. PFRS_QUEUE Control = Queue->Control;
  1160. Retry:
  1161. if (Control->ControlCount == 0) {
  1162. //
  1163. // Block until something is inserted on the queue
  1164. //
  1165. WaitArray[0] = Control->RunDown;
  1166. WaitArray[1] = Control->Event;
  1167. Status = WaitForMultipleObjects(2, WaitArray, FALSE, dwMilliseconds);
  1168. if (Status == 0) {
  1169. //
  1170. // The queue has been rundown, return immediately.
  1171. //
  1172. return(ERROR_INVALID_HANDLE);
  1173. }
  1174. if (Status == WAIT_TIMEOUT) {
  1175. return(WAIT_TIMEOUT);
  1176. }
  1177. FRS_ASSERT(Status == 1);
  1178. }
  1179. //
  1180. // Lock the queue and check again.
  1181. //
  1182. EnterCriticalSection(&Control->Lock);
  1183. if (Control->ControlCount == 0) {
  1184. //
  1185. // Somebody got here before we did, drop the lock and retry
  1186. //
  1187. LeaveCriticalSection(&Control->Lock);
  1188. goto Retry;
  1189. }
  1190. LeaveCriticalSection(&Control->Lock);
  1191. return(ERROR_SUCCESS);
  1192. }
  1193. VOID
  1194. FrsSubmitCommand(
  1195. IN PCOMMAND_PACKET CmdPkt,
  1196. IN BOOL Headwise
  1197. )
  1198. /*++
  1199. Routine Description:
  1200. Insert the command packet on the command's target queue.
  1201. If the time delay parameter is non-zero the command is instead
  1202. queued to the scheduler thread to initiate at the specified time.
  1203. FrsCompleteCommand(Status) is called if the packet could not be
  1204. queued.
  1205. Arguments:
  1206. CmdPkt
  1207. Headwise - Queue at the head (high priority)
  1208. Return Value:
  1209. None.
  1210. --*/
  1211. {
  1212. #undef DEBSUB
  1213. #define DEBSUB "FrsSubmitCommand:"
  1214. DWORD WStatus;
  1215. //
  1216. // Queue to the target
  1217. //
  1218. if (Headwise) {
  1219. WStatus = FrsRtlInsertHeadQueue(CmdPkt->TargetQueue, &CmdPkt->ListEntry);
  1220. } else {
  1221. WStatus = FrsRtlInsertTailQueue(CmdPkt->TargetQueue, &CmdPkt->ListEntry);
  1222. }
  1223. if (!WIN_SUCCESS(WStatus)) {
  1224. FrsCompleteCommand(CmdPkt, WStatus);
  1225. }
  1226. }
  1227. ULONG
  1228. FrsSubmitCommandAndWait(
  1229. IN PCOMMAND_PACKET Cmd,
  1230. IN BOOL Headwise,
  1231. IN ULONG Timeout
  1232. )
  1233. /*++
  1234. Routine Description:
  1235. Create or Reset the event, Submit the command and wait for the return.
  1236. Arguments:
  1237. Cmd - command packet to queue
  1238. Timeout - Wait Timeout
  1239. Headwise - if True, insert to head.
  1240. Return Value:
  1241. Win32 status
  1242. --*/
  1243. {
  1244. #undef DEBSUB
  1245. #define DEBSUB "FrsSubmitCommandAndWait:"
  1246. DWORD WStatus;
  1247. //
  1248. // Set the synchronous flag in the command packet.
  1249. //
  1250. FrsSetCommandSynchronous(Cmd);
  1251. if (!HANDLE_IS_VALID(Cmd->WaitEvent)){
  1252. Cmd->WaitEvent = FrsCreateEvent(TRUE, FALSE);
  1253. } else {
  1254. ResetEvent(Cmd->WaitEvent);
  1255. }
  1256. //
  1257. // Save the callers completion routine and replace it with a function
  1258. // that signals the event. It does not delete the packet so we can
  1259. // return the command status to the caller.
  1260. //
  1261. Cmd->SavedCompletionRoutine = Cmd->CompletionRoutine;
  1262. Cmd->CompletionRoutine = FrsCompleteSynchronousCmdPkt;
  1263. //
  1264. // Queue the command and create a thread if needed.
  1265. //
  1266. FrsSubmitCommand(Cmd, Headwise);
  1267. //
  1268. // Wait for the command to complete.
  1269. //
  1270. WStatus = WaitForSingleObject(Cmd->WaitEvent, Timeout);
  1271. CHECK_WAIT_ERRORS(3, WStatus, 1, ACTION_RETURN);
  1272. //
  1273. // Return the command error status.
  1274. //
  1275. WStatus = Cmd->ErrorStatus;
  1276. //
  1277. // Restore and call the caller's completion routine. This may free the
  1278. // the packet. We don't call FrsCompleteCommand() here because it was
  1279. // already called when the server finished the packet and there is no
  1280. // point in setting the wait event twice.
  1281. //
  1282. Cmd->CompletionRoutine = Cmd->SavedCompletionRoutine;
  1283. FRS_ASSERT(Cmd->CompletionRoutine != NULL);
  1284. (Cmd->CompletionRoutine)(Cmd, Cmd->CompletionArg);
  1285. return WStatus;
  1286. }
  1287. #define HEADWISE TRUE
  1288. VOID
  1289. FrsUnSubmitCommand(
  1290. IN PCOMMAND_PACKET Cmd
  1291. )
  1292. /*++
  1293. Routine Description:
  1294. Put the entry back on the head of the queue.
  1295. Arguments:
  1296. Cmd
  1297. Return Value:
  1298. None.
  1299. --*/
  1300. {
  1301. FrsSubmitCommand(Cmd, HEADWISE);
  1302. }
  1303. VOID
  1304. FrsCompleteCommand(
  1305. IN PCOMMAND_PACKET CmdPkt,
  1306. IN DWORD ErrorStatus
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. Retire the command packet based on what the original requestor specified
  1311. in the packet. The ErrorStatus is returned in the packet.
  1312. The completion routine is called for clean up and propagation.
  1313. Arguments:
  1314. CmdPkt -- A ptr to the command packet.
  1315. ErrorStatus -- Status to store in returned command packet.
  1316. Return Value:
  1317. None.
  1318. --*/
  1319. {
  1320. //
  1321. // Set the error status and call the completion routine
  1322. //
  1323. CmdPkt->ErrorStatus = ErrorStatus;
  1324. FRS_ASSERT(CmdPkt->CompletionRoutine != NULL);
  1325. (CmdPkt->CompletionRoutine)(CmdPkt, CmdPkt->CompletionArg);
  1326. }
  1327. VOID
  1328. FrsInitializeCommandServer(
  1329. IN PCOMMAND_SERVER Cs,
  1330. IN DWORD MaxThreads,
  1331. IN PWCHAR Name,
  1332. IN DWORD (*Main)(PVOID)
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. Initialize a command server
  1337. Arguments:
  1338. Cs - command server
  1339. MaxThreads - Max # of threads to kick off
  1340. Name - Printable name for thread
  1341. Main - Thread starts here
  1342. Return Value:
  1343. None.
  1344. --*/
  1345. {
  1346. ZeroMemory(Cs, sizeof(COMMAND_SERVER));
  1347. FrsInitializeQueue(&Cs->Control, &Cs->Control);
  1348. FrsInitializeQueue(&Cs->Queue, &Cs->Control);
  1349. Cs->Main = Main;
  1350. Cs->Name = Name;
  1351. Cs->MaxThreads = MaxThreads;
  1352. Cs->Idle = FrsCreateEvent(TRUE, TRUE);
  1353. }
  1354. VOID
  1355. FrsDeleteCommandServer(
  1356. IN PCOMMAND_SERVER Cs
  1357. )
  1358. /*++
  1359. Routine Description:
  1360. Undo the work of FrsInitializeCommandServer(). This function
  1361. assumes the queue and its control queue are inactive (whatever
  1362. that means). Queues and command servers are normally only
  1363. deleted at the very end of MainFrsShutDown() when all other threads
  1364. have exited and the RPC servers aren't listening for new requests.
  1365. The caller is responsible for handling all of the other queues
  1366. that may be being controlled by the control queue in the command
  1367. server struct, Cs.
  1368. Arguments:
  1369. Cs - command server
  1370. Return Value:
  1371. None.
  1372. --*/
  1373. {
  1374. if (Cs) {
  1375. FrsRtlDeleteQueue(&Cs->Queue);
  1376. FrsRtlDeleteQueue(&Cs->Control);
  1377. ZeroMemory(Cs, sizeof(COMMAND_SERVER));
  1378. }
  1379. }
  1380. PCOMMAND_PACKET
  1381. FrsAllocCommand(
  1382. IN PFRS_QUEUE TargetQueue,
  1383. IN USHORT Command
  1384. )
  1385. /*++
  1386. Routine Description:
  1387. Allocate a command packet and initialize the most common fields.
  1388. Arguments:
  1389. TargetQueue
  1390. Command
  1391. Return Value:
  1392. Address of allocated, initialized COMMAND_PACKET. Call
  1393. FrsCompleteCommand() when done.
  1394. --*/
  1395. {
  1396. PCOMMAND_PACKET Cmd;
  1397. Cmd = FrsAllocType(COMMAND_PACKET_TYPE);
  1398. Cmd->TargetQueue = TargetQueue;
  1399. FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL);
  1400. Cmd->Command = Command;
  1401. return Cmd;
  1402. }
  1403. PCOMMAND_PACKET
  1404. FrsAllocCommandEx(
  1405. IN PFRS_QUEUE TargetQueue,
  1406. IN USHORT Command,
  1407. IN ULONG Size
  1408. )
  1409. /*++
  1410. Routine Description:
  1411. Allocate a command packet with some extra space
  1412. and initialize the most common fields.
  1413. Arguments:
  1414. TargetQueue
  1415. Command
  1416. Return Value:
  1417. Address of allocated, initialized COMMAND_PACKET. Call
  1418. FrsCompleteCommand() when done.
  1419. --*/
  1420. {
  1421. PCOMMAND_PACKET Cmd;
  1422. Cmd = FrsAllocTypeSize(COMMAND_PACKET_TYPE, Size);
  1423. Cmd->TargetQueue = TargetQueue;
  1424. Cmd->CompletionRoutine = FrsFreeCommand;
  1425. Cmd->Command = Command;
  1426. return Cmd;
  1427. }
  1428. VOID
  1429. FrsFreeCommand(
  1430. IN PCOMMAND_PACKET Cmd,
  1431. IN PVOID CompletionArg
  1432. )
  1433. /*++
  1434. Routine Description:
  1435. Free a command packet
  1436. Arguments:
  1437. Cmd - command packet allocated with FrsAllocCommand().
  1438. Return Value:
  1439. NULL
  1440. --*/
  1441. {
  1442. ULONG WStatus;
  1443. if (((Cmd->Flags & CMD_PKT_FLAGS_SYNC) != 0) &&
  1444. (HANDLE_IS_VALID(Cmd->WaitEvent))){
  1445. //
  1446. // Close the event handle. The command complete function should have
  1447. // already set the event.
  1448. //
  1449. if (!CloseHandle(Cmd->WaitEvent)) {
  1450. WStatus = GetLastError();
  1451. DPRINT_WS(0, "ERROR: Close event handle failed", WStatus);
  1452. // Don't free the packet if the close handle failed.
  1453. return;
  1454. }
  1455. Cmd->WaitEvent = NULL;
  1456. }
  1457. FrsFreeType(Cmd);
  1458. }
  1459. VOID
  1460. FrsExitCommandServer(
  1461. IN PCOMMAND_SERVER Cs,
  1462. IN PFRS_THREAD FrsThread
  1463. )
  1464. /*++
  1465. Routine Description:
  1466. Exit the calling command server thread.
  1467. Arguments:
  1468. Cs - command server
  1469. Thread - calling thread
  1470. Return Value:
  1471. None.
  1472. --*/
  1473. {
  1474. #undef DEBSUB
  1475. #define DEBSUB "FrsExitCommandServer:"
  1476. PFRS_QUEUE Queue = &Cs->Queue;
  1477. //
  1478. // If there is work to be done
  1479. //
  1480. FrsRtlAcquireQueueLock(Queue);
  1481. --Cs->FrsThreads;
  1482. if (FrsRtlCountQueue(Queue) && Cs->Waiters == 0 && Cs->FrsThreads == 0) {
  1483. //
  1484. // and no one to do it; don't exit
  1485. //
  1486. ++Cs->FrsThreads;
  1487. FrsRtlReleaseQueueLock(Queue);
  1488. return;
  1489. }
  1490. //
  1491. // Set the idle event if all threads are waiting, there are no entries
  1492. // on the queue, and there are no idled queues
  1493. //
  1494. if (Cs->Waiters == Cs->FrsThreads) {
  1495. if (FrsRtlCountQueue(&Cs->Queue) == 0) {
  1496. if (FrsRtlNoIdledQueues(&Cs->Queue)) {
  1497. SetEvent(Cs->Idle);
  1498. }
  1499. }
  1500. }
  1501. FrsRtlReleaseQueueLock(Queue);
  1502. //
  1503. // The thread command server (ThQs) will "wait" on this thread's exit
  1504. // and drop the reference on its thread struct.
  1505. //
  1506. ThSupSubmitThreadExitCleanup(FrsThread);
  1507. //
  1508. // Exit
  1509. //
  1510. ExitThread(ERROR_SUCCESS);
  1511. }
  1512. #define TAILWISE FALSE
  1513. VOID
  1514. FrsSubmitCommandServer(
  1515. IN PCOMMAND_SERVER Cs,
  1516. IN PCOMMAND_PACKET Cmd
  1517. )
  1518. /*++
  1519. Routine Description:
  1520. If needed, create a thread for the command queue
  1521. Arguments:
  1522. Cs - command server
  1523. Return Value:
  1524. None.
  1525. --*/
  1526. {
  1527. #undef DEBSUB
  1528. #define DEBSUB "FrsSubmitCommandServer:"
  1529. //
  1530. // Enqueue the command and make sure there are threads running
  1531. //
  1532. FRS_ASSERT(Cmd && Cmd->TargetQueue && Cs &&
  1533. Cmd->TargetQueue->Control == &Cs->Control);
  1534. FrsSubmitCommand(Cmd, TAILWISE);
  1535. FrsKickCommandServer(Cs);
  1536. }
  1537. ULONG
  1538. FrsSubmitCommandServerAndWait(
  1539. IN PCOMMAND_SERVER Cs,
  1540. IN PCOMMAND_PACKET Cmd,
  1541. IN ULONG Timeout
  1542. )
  1543. /*++
  1544. Routine Description:
  1545. Create or Reset the event, Submit the command and wait for the return.
  1546. If needed, create a thread for the command queue.
  1547. Arguments:
  1548. Cs - command server
  1549. Cmd - command packet to queue
  1550. Timeout - Wait Timeout
  1551. Return Value:
  1552. Win32 status
  1553. --*/
  1554. {
  1555. #undef DEBSUB
  1556. #define DEBSUB "FrsSubmitCommandServerAndWait:"
  1557. DWORD WStatus;
  1558. //
  1559. // Enqueue the command and make sure there are threads running
  1560. //
  1561. FRS_ASSERT(Cmd && Cmd->TargetQueue && Cs &&
  1562. Cmd->TargetQueue->Control == &Cs->Control);
  1563. //
  1564. // Set the synchronous flag in the command packet.
  1565. //
  1566. FrsSetCommandSynchronous(Cmd);
  1567. if (!HANDLE_IS_VALID(Cmd->WaitEvent)){
  1568. Cmd->WaitEvent = FrsCreateEvent(TRUE, FALSE);
  1569. } else {
  1570. ResetEvent(Cmd->WaitEvent);
  1571. }
  1572. //
  1573. // Save the callers completion routine and replace it with a function
  1574. // that signals the event. It does not delete the packet so we can
  1575. // return the command status to the caller.
  1576. //
  1577. Cmd->SavedCompletionRoutine = Cmd->CompletionRoutine;
  1578. Cmd->CompletionRoutine = FrsCompleteSynchronousCmdPkt;
  1579. //
  1580. // Queue the command and create a thread if needed.
  1581. //
  1582. FrsSubmitCommand(Cmd, TAILWISE);
  1583. FrsKickCommandServer(Cs);
  1584. //
  1585. // Wait for the command to complete.
  1586. //
  1587. WStatus = WaitForSingleObject(Cmd->WaitEvent, Timeout);
  1588. CHECK_WAIT_ERRORS(3, WStatus, 1, ACTION_RETURN);
  1589. //
  1590. // Return the command error status.
  1591. //
  1592. WStatus = Cmd->ErrorStatus;
  1593. //
  1594. // Restore and call the caller's completion routine. This may free the
  1595. // the packet. We don't call FrsCompleteCommand() here because it was
  1596. // already called when the server finished the packet and there is no
  1597. // point in setting the wait event twice.
  1598. //
  1599. Cmd->CompletionRoutine = Cmd->SavedCompletionRoutine;
  1600. FRS_ASSERT(Cmd->CompletionRoutine != NULL);
  1601. (Cmd->CompletionRoutine)(Cmd, Cmd->CompletionArg);
  1602. return WStatus;
  1603. }
  1604. #define THREAD_CREATE_RETRY (10 * 1000) // 10 seconds
  1605. VOID
  1606. FrsKickCommandServer(
  1607. IN PCOMMAND_SERVER Cs
  1608. )
  1609. /*++
  1610. Routine Description:
  1611. If needed, create a thread for the command queue
  1612. Arguments:
  1613. Cs - command server
  1614. Return Value:
  1615. None.
  1616. --*/
  1617. {
  1618. #undef DEBSUB
  1619. #define DEBSUB "FrsKickCommandServer:"
  1620. PFRS_QUEUE Queue = &Cs->Queue;
  1621. //
  1622. // Kick off more threads if no one is waiting for this command
  1623. // and the number of threads serving this command queue is less
  1624. // than the maximum.
  1625. //
  1626. // If the thread cannot be created and there are no threads
  1627. // processing the command queue then put this command on the
  1628. // delayed queue and try again later
  1629. //
  1630. FrsRtlAcquireQueueLock(Queue);
  1631. //
  1632. // There are entries on the queue
  1633. //
  1634. if (FrsRtlCountQueue(Queue)) {
  1635. //
  1636. // But there are no threads to process the entries
  1637. //
  1638. if (Cs->Waiters == 0 && Cs->FrsThreads < Cs->MaxThreads) {
  1639. //
  1640. // First thread; reset idle
  1641. //
  1642. if (Cs->FrsThreads == 0) {
  1643. ResetEvent(Cs->Idle);
  1644. }
  1645. if (ThSupCreateThread(Cs->Name, Cs, Cs->Main, ThSupExitThreadNOP)) {
  1646. //
  1647. // Created a new thread
  1648. //
  1649. ++Cs->FrsThreads;
  1650. } else if (Cs->FrsThreads == 0) {
  1651. //
  1652. // Thread could not be created and there are no other
  1653. // threads to process this entry. Put it on the delayed
  1654. // queue and try again in a few seconds.
  1655. //
  1656. FrsDelCsSubmitKick(Cs, &Cs->Queue, THREAD_CREATE_RETRY);
  1657. }
  1658. }
  1659. }
  1660. FrsRtlReleaseQueueLock(Queue);
  1661. }
  1662. PCOMMAND_PACKET
  1663. FrsGetCommandIdled(
  1664. IN PFRS_QUEUE Queue,
  1665. IN DWORD MilliSeconds,
  1666. IN PFRS_QUEUE *IdledQueue
  1667. )
  1668. /*++
  1669. Routine Description:
  1670. Get the next command from the queue; idling the queue if requested.
  1671. Arguments:
  1672. Queue
  1673. MilliSeconds
  1674. IdledQueue
  1675. Return Value:
  1676. COMMAND_PACKET or NULL.
  1677. If non-NULL, IdledQueue is set
  1678. --*/
  1679. {
  1680. PLIST_ENTRY Entry;
  1681. Entry = FrsRtlRemoveHeadQueueTimeoutIdled(Queue, MilliSeconds, IdledQueue);
  1682. if (Entry == NULL) {
  1683. return NULL;
  1684. }
  1685. //
  1686. // Return the command packet
  1687. //
  1688. return CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  1689. }
  1690. PCOMMAND_PACKET
  1691. FrsGetCommand(
  1692. IN PFRS_QUEUE Queue,
  1693. IN DWORD MilliSeconds
  1694. )
  1695. /*++
  1696. Routine Description:
  1697. Get the next command from the queue.
  1698. Arguments:
  1699. Queue
  1700. MilliSeconds
  1701. Return Value:
  1702. COMMAND_PACKET or NULL.
  1703. --*/
  1704. {
  1705. return FrsGetCommandIdled(Queue, MilliSeconds, NULL);
  1706. }
  1707. PCOMMAND_PACKET
  1708. FrsGetCommandServerTimeoutIdled(
  1709. IN PCOMMAND_SERVER Cs,
  1710. IN ULONG Timeout,
  1711. OUT PFRS_QUEUE *IdledQueue,
  1712. OUT PBOOL IsRunDown
  1713. )
  1714. /*++
  1715. Routine Description:
  1716. Get the next command from the queue for the command server.
  1717. If nothing appears on the queue in the specified time, then
  1718. return NULL and set IsRunDown.
  1719. Arguments:
  1720. Cs - command server
  1721. Timeout
  1722. IdledQueue - Idled queue
  1723. IsRunDown
  1724. Return Value:
  1725. COMMAND_PACKET or NULL. If NULL, IsRunDown indicates whether
  1726. the NULL was caused by a rundown queue or a simple timeout.
  1727. --*/
  1728. {
  1729. #undef DEBSUB
  1730. #define DEBSUB "FrsGetCommandServerTimeoutIdled:"
  1731. PCOMMAND_PACKET Cmd;
  1732. //
  1733. // Pull off the next entry (wait at most 5 minutes)
  1734. //
  1735. FrsRtlAcquireQueueLock(&Cs->Queue);
  1736. ++Cs->Waiters;
  1737. //
  1738. // Set the idle event if all threads are waiting, there are no entries
  1739. // on the queue, and there are no idled queues
  1740. //
  1741. if (Cs->Waiters == Cs->FrsThreads) {
  1742. if (FrsRtlCountQueue(&Cs->Queue) == 0) {
  1743. if (FrsRtlNoIdledQueues(&Cs->Queue)) {
  1744. SetEvent(Cs->Idle);
  1745. }
  1746. }
  1747. }
  1748. FrsRtlReleaseQueueLock(&Cs->Queue);
  1749. //
  1750. // Get the next command
  1751. //
  1752. Cmd = FrsGetCommandIdled(&Cs->Control, Timeout, IdledQueue);
  1753. FrsRtlAcquireQueueLock(&Cs->Queue);
  1754. //
  1755. // Reset the Idle event if there is any chance it might have been set
  1756. //
  1757. if (Cs->Waiters == Cs->FrsThreads) {
  1758. ResetEvent(Cs->Idle);
  1759. }
  1760. --Cs->Waiters;
  1761. if (IsRunDown) {
  1762. *IsRunDown = Cs->Queue.IsRunDown;
  1763. }
  1764. FrsRtlReleaseQueueLock(&Cs->Queue);
  1765. return Cmd;
  1766. }
  1767. #define COMMAND_SERVER_TIMEOUT (5 * 60 * 1000) // 5 minutes
  1768. DWORD FrsCommandServerTimeout = COMMAND_SERVER_TIMEOUT;
  1769. PCOMMAND_PACKET
  1770. FrsGetCommandServerIdled(
  1771. IN PCOMMAND_SERVER Cs,
  1772. IN PFRS_QUEUE *IdledQueue
  1773. )
  1774. /*++
  1775. Routine Description:
  1776. Get the next command from the queue. If nothing appears on the queue
  1777. for 5 minutes, return NULL. The caller will exit. Idle the queue.
  1778. Arguments:
  1779. Cs - command server
  1780. IdledQueue - Idled queue
  1781. Return Value:
  1782. COMMAND_PACKET or NULL. Caller should exit on NULL.
  1783. If non-NULL, IdledQueue is set
  1784. --*/
  1785. {
  1786. return FrsGetCommandServerTimeoutIdled(Cs,
  1787. FrsCommandServerTimeout,
  1788. IdledQueue,
  1789. NULL);
  1790. }
  1791. PCOMMAND_PACKET
  1792. FrsGetCommandServerTimeout(
  1793. IN PCOMMAND_SERVER Cs,
  1794. IN ULONG Timeout,
  1795. OUT PBOOL IsRunDown
  1796. )
  1797. /*++
  1798. Routine Description:
  1799. Get the next command from the queue. If nothing appears on the queue
  1800. in the specified timeout, return NULL and an indication of the
  1801. queue's rundown status.
  1802. Arguments:
  1803. Cs - command server
  1804. Timeout
  1805. IsRunDown
  1806. Return Value:
  1807. COMMAND_PACKET or NULL. IsRunDown is only valid if COMMAND_PACKET
  1808. is NULL. Use IsRunDown to check if the NULL return is because of
  1809. a rundown'ed queue or simply a timeout.
  1810. --*/
  1811. {
  1812. return FrsGetCommandServerTimeoutIdled(Cs, Timeout, NULL, IsRunDown);
  1813. }
  1814. DWORD
  1815. FrsWaitForCommandServer(
  1816. IN PCOMMAND_SERVER Cs,
  1817. IN DWORD MilliSeconds
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. Wait until all of the threads are idle, there are no entries on the
  1822. queue, and there are no idled queues.
  1823. Arguments:
  1824. Cs - command server
  1825. MilliSeconds - Timeout
  1826. Return Value:
  1827. Status from WaitForSingleObject()
  1828. --*/
  1829. {
  1830. return WaitForSingleObject(Cs->Idle, MilliSeconds);
  1831. }
  1832. PCOMMAND_PACKET
  1833. FrsGetCommandServer(
  1834. IN PCOMMAND_SERVER Cs
  1835. )
  1836. /*++
  1837. Routine Description:
  1838. Get the next command from the queue. If nothing appears on the queue
  1839. for 5 minutes, return NULL. The caller will exit.
  1840. Arguments:
  1841. Cs - command server
  1842. Return Value:
  1843. COMMAND_PACKET or NULL. Caller should exit on NULL.
  1844. --*/
  1845. {
  1846. //
  1847. // Pull off the next entry (wait at most 5 minutes)
  1848. //
  1849. return FrsGetCommandServerIdled(Cs, NULL);
  1850. }
  1851. VOID
  1852. FrsRunDownCommand(
  1853. IN PFRS_QUEUE Queue
  1854. )
  1855. /*++
  1856. Routine Description:
  1857. Rundown a queue of command packets
  1858. Arguments:
  1859. Queue - queue to rundown
  1860. Return Value:
  1861. None.
  1862. --*/
  1863. {
  1864. LIST_ENTRY RunDown;
  1865. PLIST_ENTRY Entry;
  1866. PCOMMAND_PACKET Cmd;
  1867. if (!Queue) {
  1868. return;
  1869. }
  1870. //
  1871. // RunDown the queue and retrieve the current entries
  1872. //
  1873. FrsRtlRunDownQueue(Queue, &RunDown);
  1874. //
  1875. // Free up the commands
  1876. //
  1877. while (!IsListEmpty(&RunDown)) {
  1878. Entry = RemoveHeadList(&RunDown);
  1879. Cmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  1880. FrsCompleteCommand(Cmd, ERROR_ACCESS_DENIED);
  1881. }
  1882. }
  1883. VOID
  1884. FrsRunDownCommandServer(
  1885. IN PCOMMAND_SERVER Cs,
  1886. IN PFRS_QUEUE Queue
  1887. )
  1888. /*++
  1889. Routine Description:
  1890. Rundown a queue of a command server
  1891. Arguments:
  1892. Cs - command server
  1893. Queue - queue to abort
  1894. Return Value:
  1895. None.
  1896. --*/
  1897. {
  1898. FrsRunDownCommand(Queue);
  1899. }
  1900. VOID
  1901. FrsCancelCommandServer(
  1902. IN PCOMMAND_SERVER Cs,
  1903. IN PFRS_QUEUE Queue
  1904. )
  1905. /*++
  1906. Routine Description:
  1907. Cancels the current commands on Queue.
  1908. Arguments:
  1909. Cs - command server
  1910. Queue - queue to abort
  1911. Return Value:
  1912. None.
  1913. --*/
  1914. {
  1915. LIST_ENTRY Cancel;
  1916. PLIST_ENTRY Entry;
  1917. PCOMMAND_PACKET Cmd;
  1918. //
  1919. // RunDown the queue and retrieve the current entries
  1920. //
  1921. FrsRtlCancelQueue(Queue, &Cancel);
  1922. //
  1923. // Free up the commands
  1924. //
  1925. while (!IsListEmpty(&Cancel)) {
  1926. Entry = RemoveHeadList(&Cancel);
  1927. Cmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  1928. FrsCompleteCommand(Cmd, ERROR_CANCELLED);
  1929. }
  1930. }
  1931. VOID
  1932. FrsCompleteRequestCount(
  1933. IN PCOMMAND_PACKET CmdPkt,
  1934. IN PFRS_REQUEST_COUNT RequestCount
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. This is an Frs Command packet completion routine that takes
  1939. an FRS_REQUEST_COUNT struct. It decrements the count and signals
  1940. the event when the count goes to zero. The ErrorStatus is
  1941. merged into the Status field of the request count struct.
  1942. It then frees the command packet.
  1943. Arguments:
  1944. CmdPkt -- A ptr to the command packet.
  1945. RequestCount - Supplies a pointer to a RequestCount structure to initialize
  1946. Return Value:
  1947. None.
  1948. --*/
  1949. {
  1950. //
  1951. // Decrement count and signal waiter. merge error status from packet
  1952. // into RequestCount->Status.
  1953. //
  1954. FrsDecrementRequestCount(RequestCount, CmdPkt->ErrorStatus);
  1955. FrsSetCompletionRoutine(CmdPkt, FrsFreeCommand, NULL);
  1956. FrsCompleteCommand(CmdPkt, CmdPkt->ErrorStatus);
  1957. }
  1958. VOID
  1959. FrsCompleteRequestCountKeepPkt(
  1960. IN PCOMMAND_PACKET CmdPkt,
  1961. IN PFRS_REQUEST_COUNT RequestCount
  1962. )
  1963. /*++
  1964. Routine Description:
  1965. This is an Frs Command packet completion routine that takes
  1966. an FRS_REQUEST_COUNT struct. It decrements the count and signals
  1967. the event when the count goes to zero. The ErrorStatus is
  1968. merged into the Status field of the request count struct.
  1969. It does not free the command packet so the caller can retreive results
  1970. or reuse it.
  1971. Arguments:
  1972. CmdPkt -- A ptr to the command packet.
  1973. RequestCount - Supplies a pointer to a RequestCount structure to initialize
  1974. Return Value:
  1975. None.
  1976. --*/
  1977. {
  1978. // Decrement count and signal waiter. merge error status from packet
  1979. // into RequestCount->Status.
  1980. //
  1981. FrsDecrementRequestCount(RequestCount, CmdPkt->ErrorStatus);
  1982. }
  1983. VOID
  1984. FrsCompleteKeepPkt(
  1985. IN PCOMMAND_PACKET CmdPkt,
  1986. IN PVOID CompletionArg
  1987. )
  1988. /*++
  1989. Routine Description:
  1990. This is an Frs Command packet completion routine that
  1991. leaves the CmdPkt alone so the caller can reuse it.
  1992. Arguments:
  1993. CmdPkt -- A ptr to the command packet.
  1994. CompletionArg - Unused.
  1995. Return Value:
  1996. None.
  1997. --*/
  1998. {
  1999. return;
  2000. }
  2001. VOID
  2002. FrsCompleteSynchronousCmdPkt(
  2003. IN PCOMMAND_PACKET CmdPkt,
  2004. IN PVOID CompletionArg
  2005. )
  2006. /*++
  2007. Routine Description:
  2008. This is an Frs Command packet completion routine that
  2009. Signals the Wait Event for a synchronous cmd request.
  2010. It leaves the CmdPkt alone so the caller can reuse it.
  2011. Arguments:
  2012. CmdPkt -- A ptr to the command packet.
  2013. CompletionArg - Unused.
  2014. Return Value:
  2015. None.
  2016. --*/
  2017. {
  2018. FRS_ASSERT(HANDLE_IS_VALID(CmdPkt->WaitEvent));
  2019. SetEvent(CmdPkt->WaitEvent);
  2020. //
  2021. // A ctx switch to the waiter could occur at this point. The waiter could
  2022. // free the packet. So no further refs to the packet are allowed.
  2023. //
  2024. return;
  2025. }
  2026. VOID
  2027. FrsInitializeRequestCount(
  2028. IN PFRS_REQUEST_COUNT RequestCount
  2029. )
  2030. /*++
  2031. Routine Description:
  2032. Initializes a RequestCount for use.
  2033. Arguments:
  2034. RequestCount - Supplies a pointer to a RequestCount structure to initialize
  2035. Return Value:
  2036. ERROR_SUCCESS if successful
  2037. Win32 error code otherwise.
  2038. --*/
  2039. {
  2040. ULONG Status;
  2041. RequestCount->Count = 0;
  2042. RequestCount->Status = 0;
  2043. INITIALIZE_CRITICAL_SECTION(&RequestCount->Lock);
  2044. RequestCount->Event = FrsCreateEvent(TRUE, FALSE);
  2045. }
  2046. VOID
  2047. FrsDeleteRequestCount(
  2048. IN PFRS_REQUEST_COUNT RequestCount
  2049. )
  2050. /*++
  2051. Routine Description:
  2052. Releases resources used by a RequestCount.
  2053. Arguments:
  2054. RequestCount - Supplies a pointer to a RequestCount structure to delete
  2055. Return Value:
  2056. None.
  2057. --*/
  2058. {
  2059. ULONG WStatus;
  2060. if (RequestCount != NULL) {
  2061. if (HANDLE_IS_VALID(RequestCount->Event)) {
  2062. if (!CloseHandle(RequestCount->Event)) {
  2063. WStatus = GetLastError();
  2064. DPRINT_WS(0, "ERROR: Close event handle failed", WStatus);
  2065. DeleteCriticalSection(&RequestCount->Lock);
  2066. return;
  2067. }
  2068. DeleteCriticalSection(&RequestCount->Lock);
  2069. }
  2070. //
  2071. // Zero memory to catch errors.
  2072. //
  2073. ZeroMemory(RequestCount, sizeof(FRS_REQUEST_COUNT));
  2074. }
  2075. }
  2076. ULONG
  2077. FrsWaitOnRequestCount(
  2078. IN PFRS_REQUEST_COUNT RequestCount,
  2079. IN ULONG Timeout
  2080. )
  2081. {
  2082. DWORD WStatus;
  2083. Retry:
  2084. if (RequestCount->Count > 0) {
  2085. WStatus = WaitForSingleObject(RequestCount->Event, Timeout);
  2086. CHECK_WAIT_ERRORS(3, WStatus, 1, ACTION_RETURN);
  2087. }
  2088. //
  2089. // Lock the queue and check again.
  2090. //
  2091. EnterCriticalSection(&RequestCount->Lock);
  2092. if (RequestCount->Count > 0) {
  2093. //
  2094. // Somebody got here before we did, drop the lock and retry
  2095. //
  2096. LeaveCriticalSection(&RequestCount->Lock);
  2097. goto Retry;
  2098. }
  2099. LeaveCriticalSection(&RequestCount->Lock);
  2100. return(ERROR_SUCCESS);
  2101. }
  2102. DWORD
  2103. FrsRtlInitializeList(
  2104. PFRS_LIST List
  2105. )
  2106. /*++
  2107. Routine Description:
  2108. Initializes an interlocked list for use.
  2109. Arguments:
  2110. List - Supplies a pointer to an FRS_LIST structure to initialize
  2111. Return Value:
  2112. ERROR_SUCCESS if successful
  2113. --*/
  2114. {
  2115. DWORD Status;
  2116. InitializeListHead(&List->ListHead);
  2117. INITIALIZE_CRITICAL_SECTION(&List->Lock);
  2118. List->Count = 0;
  2119. List->ControlCount = 0;
  2120. List->Control = List;
  2121. return(ERROR_SUCCESS);
  2122. }
  2123. VOID
  2124. FrsRtlDeleteList(
  2125. PFRS_LIST List
  2126. )
  2127. /*++
  2128. Routine Description:
  2129. Releases all resources used by an interlocked list.
  2130. Arguments:
  2131. List - supplies the List to be deleted
  2132. Return Value:
  2133. None.
  2134. --*/
  2135. {
  2136. DeleteCriticalSection(&List->Lock);
  2137. //
  2138. // Zero the memory in order to cause grief to people who try
  2139. // and use a deleted list.
  2140. //
  2141. ZeroMemory(List, sizeof(FRS_LIST));
  2142. }
  2143. PLIST_ENTRY
  2144. FrsRtlRemoveHeadList(
  2145. IN PFRS_LIST List
  2146. )
  2147. /*++
  2148. Routine Description:
  2149. Removes the item at the head of the interlocked list.
  2150. Arguments:
  2151. List - Supplies the list to remove an item from.
  2152. Return Value:
  2153. Pointer to list entry removed from the head of the list.
  2154. NULL if the list is empty.
  2155. --*/
  2156. {
  2157. #undef DEBSUB
  2158. #define DEBSUB "FrsRtlRemoveHeadList:"
  2159. PLIST_ENTRY Entry;
  2160. PFRS_LIST Control = List->Control;
  2161. if (List->ControlCount == 0) {
  2162. return NULL;
  2163. }
  2164. //
  2165. // Lock the list and try to remove something
  2166. //
  2167. EnterCriticalSection(&Control->Lock);
  2168. if (Control->ControlCount == 0) {
  2169. //
  2170. // Somebody got here before we did, drop the lock and return null
  2171. //
  2172. LeaveCriticalSection(&Control->Lock);
  2173. return NULL;
  2174. }
  2175. FRS_ASSERT(!IsListEmpty(&List->ListHead));
  2176. Entry = RemoveHeadList(&List->ListHead);
  2177. //
  2178. // Decrement count.
  2179. //
  2180. List->Count--;
  2181. Control->ControlCount--;
  2182. LeaveCriticalSection(&Control->Lock);
  2183. return(Entry);
  2184. }
  2185. VOID
  2186. FrsRtlInsertHeadList(
  2187. IN PFRS_LIST List,
  2188. IN PLIST_ENTRY Entry
  2189. )
  2190. /*++
  2191. Routine Description:
  2192. Inserts the item at the head of the interlocked list.
  2193. Arguments:
  2194. List - Supplies the list to insert the item on.
  2195. Entry - The entry to insert.
  2196. Return Value:
  2197. None.
  2198. --*/
  2199. {
  2200. PFRS_LIST Control = List->Control;
  2201. //
  2202. // Lock the list and insert at head.
  2203. //
  2204. EnterCriticalSection(&Control->Lock);
  2205. FrsRtlInsertHeadListLock(List, Entry);
  2206. LeaveCriticalSection(&Control->Lock);
  2207. return;
  2208. }
  2209. PLIST_ENTRY
  2210. FrsRtlRemoveTailList(
  2211. IN PFRS_LIST List
  2212. )
  2213. /*++
  2214. Routine Description:
  2215. Removes the item at the tail of the interlocked list.
  2216. Arguments:
  2217. List - Supplies the list to remove an item from.
  2218. Return Value:
  2219. Pointer to list entry removed from the tail of the list.
  2220. NULL if the list is empty.
  2221. --*/
  2222. {
  2223. #undef DEBSUB
  2224. #define DEBSUB "FrsRtlRemoveTailList:"
  2225. PLIST_ENTRY Entry;
  2226. PFRS_LIST Control = List->Control;
  2227. if (Control->ControlCount == 0) {
  2228. return NULL;
  2229. }
  2230. //
  2231. // Lock the list and try to remove something
  2232. //
  2233. EnterCriticalSection(&Control->Lock);
  2234. if (Control->ControlCount == 0) {
  2235. //
  2236. // Somebody got here before we did, drop the lock and return null
  2237. //
  2238. LeaveCriticalSection(&Control->Lock);
  2239. return NULL;
  2240. }
  2241. FRS_ASSERT(!IsListEmpty(&List->ListHead));
  2242. Entry = RemoveTailList(&List->ListHead);
  2243. //
  2244. // Decrement count.
  2245. //
  2246. List->Count--;
  2247. Control->ControlCount--;
  2248. LeaveCriticalSection(&Control->Lock);
  2249. return(Entry);
  2250. }
  2251. VOID
  2252. FrsRtlInsertTailList(
  2253. IN PFRS_LIST List,
  2254. IN PLIST_ENTRY Entry
  2255. )
  2256. /*++
  2257. Routine Description:
  2258. Inserts the item at the tail of the interlocked list.
  2259. Arguments:
  2260. List - Supplies the list to insert the item on.
  2261. Entry - The entry to insert.
  2262. Return Value:
  2263. None.
  2264. --*/
  2265. {
  2266. PFRS_LIST Control = List->Control;
  2267. //
  2268. // Lock the list and insert at tail.
  2269. //
  2270. EnterCriticalSection(&Control->Lock);
  2271. FrsRtlInsertTailListLock(List, Entry);
  2272. LeaveCriticalSection(&Control->Lock);
  2273. return;
  2274. }
  2275. VOID
  2276. FrsRtlRemoveEntryList(
  2277. IN PFRS_LIST List,
  2278. IN PLIST_ENTRY Entry
  2279. )
  2280. /*++
  2281. Routine Description:
  2282. Removes the entry from the interlocked list. The entry must be on the
  2283. given list since we use the lock in the FRS_LIST to synchronize access.
  2284. Arguments:
  2285. List - Supplies the list to remove an item from.
  2286. Entry - The entry to remove.
  2287. Return Value:
  2288. None.
  2289. --*/
  2290. {
  2291. PFRS_LIST Control = List->Control;
  2292. //
  2293. // Lock the list and try to remove entry
  2294. //
  2295. EnterCriticalSection(&Control->Lock);
  2296. FrsRtlRemoveEntryListLock(List, Entry);
  2297. LeaveCriticalSection(&Control->Lock);
  2298. return;
  2299. }
  2300. VOID
  2301. FrsRtlRemoveEntryListLock(
  2302. IN PFRS_LIST List,
  2303. IN PLIST_ENTRY Entry
  2304. )
  2305. /*++
  2306. Routine Description:
  2307. Removes the entry from the interlocked list. The entry must be on the
  2308. given list.
  2309. The caller already has the list lock.
  2310. Arguments:
  2311. List - Supplies the list to remove an item from.
  2312. Entry - The entry to remove.
  2313. Return Value:
  2314. None.
  2315. --*/
  2316. {
  2317. PFRS_LIST Control = List->Control;
  2318. //
  2319. // List better not be empty.
  2320. //
  2321. FRS_ASSERT(!IsListEmpty(&List->ListHead));
  2322. RemoveEntryListB(Entry);
  2323. //
  2324. // Decrement count.
  2325. //
  2326. List->Count--;
  2327. Control->ControlCount--;
  2328. return;
  2329. }
  2330. VOID
  2331. FrsRtlInsertHeadListLock(
  2332. IN PFRS_LIST List,
  2333. IN PLIST_ENTRY Entry
  2334. )
  2335. /*++
  2336. Routine Description:
  2337. Inserts the item at the head of the interlocked list.
  2338. The caller has acquired the lock.
  2339. Arguments:
  2340. List - Supplies the list to insert the item on.
  2341. Entry - The entry to insert.
  2342. Return Value:
  2343. None.
  2344. --*/
  2345. {
  2346. PFRS_LIST Control = List->Control;
  2347. InsertHeadList(&List->ListHead, Entry);
  2348. List->Count++;
  2349. Control->ControlCount++;
  2350. return;
  2351. }
  2352. VOID
  2353. FrsRtlInsertTailListLock(
  2354. IN PFRS_LIST List,
  2355. IN PLIST_ENTRY Entry
  2356. )
  2357. /*++
  2358. Routine Description:
  2359. Inserts the item at the tail of the interlocked list.
  2360. The caller has acquired the lock.
  2361. Arguments:
  2362. List - Supplies the list to insert the item on.
  2363. Entry - The entry to insert.
  2364. Return Value:
  2365. None.
  2366. --*/
  2367. {
  2368. PFRS_LIST Control = List->Control;
  2369. InsertTailList(&List->ListHead, Entry);
  2370. List->Count++;
  2371. Control->ControlCount++;
  2372. return;
  2373. }