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.

647 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. frsdelcs.c
  5. Abstract:
  6. This command server delays a command packet
  7. Author:
  8. Billy J. Fuller 01-Jun-1997
  9. Environment
  10. User mode winnt
  11. --*/
  12. #include <ntreppch.h>
  13. #pragma hdrstop
  14. #define DEBSUB "FRSDELCS:"
  15. #include <frs.h>
  16. //
  17. // Struct for the Delayed Command Server
  18. // Contains info about the queues and the threads
  19. //
  20. #define DELCS_MAXTHREADS (1) // MUST BE 1; there are no locks on globals.
  21. COMMAND_SERVER DelCs;
  22. HANDLE DelCsEvent;
  23. //
  24. // List of delayed commands
  25. //
  26. LIST_ENTRY TimeoutList;
  27. VOID
  28. FrsDelCsInsertCmd(
  29. IN PCOMMAND_PACKET Cmd
  30. )
  31. /*++
  32. Routine Description:
  33. Insert the new command packet into the sorted, timeout list
  34. Arguments:
  35. Cmd
  36. Return Value:
  37. None.
  38. --*/
  39. {
  40. #undef DEBSUB
  41. #define DEBSUB "FrsDelCsInsertCmd:"
  42. PLIST_ENTRY Entry;
  43. PCOMMAND_PACKET OldCmd;
  44. if (Cmd == NULL) {
  45. return;
  46. }
  47. //
  48. // Insert into empty list
  49. //
  50. if (IsListEmpty(&TimeoutList)) {
  51. InsertHeadList(&TimeoutList, &Cmd->ListEntry);
  52. return;
  53. }
  54. //
  55. // Insert at tail
  56. //
  57. Entry = GetListTail(&TimeoutList);
  58. OldCmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  59. if (DsTimeout(OldCmd) <= DsTimeout(Cmd)) {
  60. InsertTailList(&TimeoutList, &Cmd->ListEntry);
  61. return;
  62. }
  63. //
  64. // Insert into list
  65. //
  66. for (Entry = GetListHead(&TimeoutList);
  67. Entry != &TimeoutList;
  68. Entry = GetListNext(Entry)) {
  69. OldCmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  70. if (DsTimeout(Cmd) <= DsTimeout(OldCmd)) {
  71. InsertTailList(Entry, &Cmd->ListEntry);
  72. return;
  73. }
  74. }
  75. FRS_ASSERT(!"FrsDelCsInsertCmd failed.");
  76. }
  77. VOID
  78. ProcessCmd(
  79. IN PCOMMAND_PACKET Cmd
  80. )
  81. /*++
  82. Routine Description:
  83. Process the expired command packet
  84. Arguments:
  85. Cmd
  86. Return Value:
  87. None.
  88. --*/
  89. {
  90. #undef DEBSUB
  91. #define DEBSUB "ProcessCmd:"
  92. ULONG WStatus = ERROR_SUCCESS;
  93. switch (Cmd->Command) {
  94. //
  95. // Submit a command to a command server
  96. //
  97. case CMD_DELAYED_SUBMIT:
  98. DPRINT3(5, "Del: submit Cmd %08x DsCmd %08x DsCs %08x\n",
  99. Cmd, DsCmd(Cmd), DsCs(Cmd));
  100. FrsSubmitCommandServer(DsCs(Cmd), DsCmd(Cmd));
  101. DsCmd(Cmd) = NULL;
  102. break;
  103. //
  104. // Submit a command to an FRS queue.
  105. //
  106. case CMD_DELAYED_QUEUE_SUBMIT:
  107. DPRINT2(5, "DelQueue: submit Cmd %08x DsCmd %08x\n", Cmd, DsCmd(Cmd));
  108. FrsSubmitCommand(DsCmd(Cmd), FALSE);
  109. DsCmd(Cmd) = NULL;
  110. break;
  111. //
  112. // UnIdle a queue and kick its command server
  113. //
  114. case CMD_DELAYED_UNIDLED:
  115. DPRINT2(5, "Del: unidle Cmd %08x DsQueue %08x\n", Cmd, DsQueue(Cmd));
  116. FrsRtlUnIdledQueue(DsQueue(Cmd));
  117. FrsKickCommandServer(DsCs(Cmd));
  118. DsQueue(Cmd) = NULL;
  119. break;
  120. //
  121. // Kick a command server
  122. //
  123. case CMD_DELAYED_KICK:
  124. DPRINT2(5, "Del: kick Cmd %08x DsCs %08x\n", Cmd, DsCs(Cmd));
  125. FrsKickCommandServer(DsCs(Cmd));
  126. break;
  127. //
  128. // Complete the command (work is done in the completion routine)
  129. // Command may be resubmitted to this delayed command server.
  130. //
  131. case CMD_DELAYED_COMPLETE:
  132. DPRINT2(5, "Del: Complete Cmd %08x DsCmd %08x\n", Cmd, DsCmd(Cmd));
  133. FrsCompleteCommand(DsCmd(Cmd), ERROR_SUCCESS);
  134. DsCmd(Cmd) = NULL;
  135. break;
  136. //
  137. // Unknown command
  138. //
  139. default:
  140. DPRINT1(0, "Delayed: unknown command 0x%x\n", Cmd->Command);
  141. WStatus = ERROR_INVALID_FUNCTION;
  142. break;
  143. }
  144. //
  145. // All done
  146. //
  147. FrsCompleteCommand(Cmd, WStatus);
  148. }
  149. VOID
  150. ExpelCmds(
  151. IN ULONGLONG CurrentTime
  152. )
  153. /*++
  154. Routine Description:
  155. Expel the commands whose timeouts have passed.
  156. Arguments:
  157. CurrentTime
  158. Return Value:
  159. None.
  160. --*/
  161. {
  162. #undef DEBSUB
  163. #define DEBSUB "ExpelCmds:"
  164. PLIST_ENTRY Entry;
  165. PCOMMAND_PACKET Cmd;
  166. //
  167. // Expel expired commands
  168. //
  169. while (!IsListEmpty(&TimeoutList)) {
  170. Entry = GetListHead(&TimeoutList);
  171. Cmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  172. //
  173. // Hasn't expired; stop
  174. //
  175. if (DsTimeout(Cmd) > CurrentTime) {
  176. break;
  177. }
  178. FrsRemoveEntryList(Entry);
  179. ProcessCmd(Cmd);
  180. }
  181. }
  182. VOID
  183. RunDownCmds(
  184. VOID
  185. )
  186. /*++
  187. Routine Description:
  188. Error off the commands in the timeout list
  189. Arguments:
  190. None.
  191. Return Value:
  192. None.
  193. --*/
  194. {
  195. #undef DEBSUB
  196. #define DEBSUB "RunDownCmds:"
  197. PLIST_ENTRY Entry;
  198. PCOMMAND_PACKET Cmd;
  199. //
  200. // Expel expired commands
  201. //
  202. while (!IsListEmpty(&TimeoutList)) {
  203. Entry = RemoveHeadList(&TimeoutList);
  204. Cmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  205. FrsCompleteCommand(Cmd, ERROR_ACCESS_DENIED);
  206. }
  207. }
  208. DWORD
  209. MainDelCs(
  210. PVOID Arg
  211. )
  212. /*++
  213. Routine Description:
  214. Entry point for a thread serving the Delayed command Command Server.
  215. Arguments:
  216. Arg - thread
  217. Return Value:
  218. None.
  219. --*/
  220. {
  221. #undef DEBSUB
  222. #define DEBSUB "MainDelCs:"
  223. ULONGLONG CurrentTime;
  224. ULONG WStatus = ERROR_SUCCESS;
  225. BOOL IsRunDown;
  226. PCOMMAND_PACKET Cmd;
  227. PLIST_ENTRY Entry;
  228. ULONG Timeout = INFINITE;
  229. PFRS_THREAD FrsThread = (PFRS_THREAD)Arg;
  230. //
  231. // Thread is pointing at the correct command server
  232. //
  233. FRS_ASSERT(FrsThread->Data == &DelCs);
  234. DPRINT(0, "Delayed command server has started.\n");
  235. //
  236. // Try-Finally
  237. //
  238. try {
  239. //
  240. // Capture exception.
  241. //
  242. try {
  243. while(TRUE) {
  244. //
  245. // Pull entries off the "delayed" queue and put them on the timeout list
  246. //
  247. Cmd = FrsGetCommandServerTimeout(&DelCs, Timeout, &IsRunDown);
  248. //
  249. // Nothing to do; exit
  250. //
  251. if (Cmd == NULL && !IsRunDown && IsListEmpty(&TimeoutList)) {
  252. DPRINT(0, "Delayed command server is exiting.\n");
  253. FrsExitCommandServer(&DelCs, FrsThread);
  254. }
  255. //
  256. // Rundown the timeout list and exit the thread
  257. //
  258. if (IsRunDown) {
  259. RunDownCmds();
  260. DPRINT(0, "Delayed command server is exiting.\n");
  261. FrsExitCommandServer(&DelCs, FrsThread);
  262. }
  263. //
  264. // Insert the new command, if any
  265. //
  266. FrsDelCsInsertCmd(Cmd);
  267. //
  268. // Expel expired commands
  269. //
  270. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  271. CurrentTime /= (ULONGLONG)(10 * 1000);
  272. ExpelCmds(CurrentTime);
  273. //
  274. // Reset our timeout
  275. //
  276. if (IsListEmpty(&TimeoutList)) {
  277. Timeout = INFINITE;
  278. } else {
  279. Entry = GetListHead(&TimeoutList);
  280. Cmd = CONTAINING_RECORD(Entry, COMMAND_PACKET, ListEntry);
  281. Timeout = (ULONG)(DsTimeout(Cmd) - CurrentTime);
  282. }
  283. }
  284. //
  285. // Get exception status.
  286. //
  287. } except (EXCEPTION_EXECUTE_HANDLER) {
  288. GET_EXCEPTION_CODE(WStatus);
  289. }
  290. } finally {
  291. if (WIN_SUCCESS(WStatus)) {
  292. if (AbnormalTermination()) {
  293. WStatus = ERROR_OPERATION_ABORTED;
  294. }
  295. }
  296. DPRINT_WS(0, "DelCs finally.", WStatus);
  297. //
  298. // Trigger FRS shutdown if we terminated abnormally.
  299. //
  300. if (!WIN_SUCCESS(WStatus) && (WStatus != ERROR_PROCESS_ABORTED)) {
  301. DPRINT(0, "DelCs terminated abnormally, forcing service shutdown.\n");
  302. FrsIsShuttingDown = TRUE;
  303. SetEvent(ShutDownEvent);
  304. } else {
  305. WStatus = ERROR_SUCCESS;
  306. }
  307. }
  308. return WStatus;
  309. }
  310. VOID
  311. FrsDelCsInitialize(
  312. VOID
  313. )
  314. /*++
  315. Routine Description:
  316. Initialize the delayed command server subsystem.
  317. Arguments:
  318. None.
  319. Return Value:
  320. ERROR_SUCCESS
  321. --*/
  322. {
  323. #undef DEBSUB
  324. #define DEBSUB "FrsDelCsInitialize:"
  325. //
  326. // Must be 1 because there are no locks on delayed-cmd lists
  327. // Also, there is no benefit to having more than 1.
  328. //
  329. FRS_ASSERT(DELCS_MAXTHREADS == 1);
  330. InitializeListHead(&TimeoutList);
  331. FrsInitializeCommandServer(&DelCs, DELCS_MAXTHREADS, L"DelCs", MainDelCs);
  332. DelCsEvent = FrsCreateEvent(FALSE, FALSE);
  333. //DelCsEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  334. }
  335. VOID
  336. DelCsCompletionRoutine(
  337. IN PCOMMAND_PACKET Cmd,
  338. IN PVOID Arg
  339. )
  340. /*++
  341. Routine Description:
  342. Completion routine for delayed command server
  343. Arguments:
  344. Cmd
  345. Return Value:
  346. None.
  347. --*/
  348. {
  349. #undef DEBSUB
  350. #define DEBSUB "DelCsCompletionRoutine:"
  351. DPRINT1(5, "DelRs: completion 0x%x\n", Cmd);
  352. if (DsCmd(Cmd)) {
  353. FrsCompleteCommand(DsCmd(Cmd), DsCmd(Cmd)->ErrorStatus);
  354. DsCmd(Cmd) = NULL;
  355. }
  356. FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL);
  357. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  358. }
  359. ULONGLONG
  360. ComputeTimeout(
  361. IN ULONG TimeoutInMilliSeconds
  362. )
  363. /*++
  364. Routine Description:
  365. Compute the absolute timeout in milliseconds.
  366. Arguments:
  367. TimeoutInMilliSeconds
  368. Return Value:
  369. None.
  370. --*/
  371. {
  372. #undef DEBSUB
  373. #define DEBSUB "ComputeTimeout:"
  374. ULONGLONG CurrentTime;
  375. //
  376. // 100-nanoseconds to milliseconds
  377. //
  378. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  379. CurrentTime /= (ULONGLONG)(10 * 1000);
  380. CurrentTime += (ULONGLONG)(TimeoutInMilliSeconds);
  381. return CurrentTime;
  382. }
  383. VOID
  384. FrsDelCsSubmitSubmit(
  385. IN PCOMMAND_SERVER Cs,
  386. IN PCOMMAND_PACKET DelCmd,
  387. IN ULONG Timeout
  388. )
  389. /*++
  390. Routine Description:
  391. Submit a delayed command to a command server
  392. Arguments:
  393. Cs
  394. DelCmd
  395. Timeout - in milliseconds
  396. Return Value:
  397. None.
  398. --*/
  399. {
  400. #undef DEBSUB
  401. #define DEBSUB "FrsDelCsSubmitSubmit:"
  402. PCOMMAND_PACKET Cmd;
  403. Cmd = FrsAllocCommand(&DelCs.Queue, CMD_DELAYED_SUBMIT);
  404. FrsSetCompletionRoutine(Cmd, DelCsCompletionRoutine, NULL);
  405. DsCs(Cmd) = Cs;
  406. DsCmd(Cmd) = DelCmd;
  407. DsTimeout(Cmd) = ComputeTimeout(Timeout);
  408. DPRINT3(5, "Del: submit Cmd %x DelCmd %x Cs %x\n", Cmd, DsCmd(Cmd), DsCs(Cmd));
  409. FrsSubmitCommandServer(&DelCs, Cmd);
  410. }
  411. VOID
  412. FrsDelQueueSubmit(
  413. IN PCOMMAND_PACKET DelCmd,
  414. IN ULONG Timeout
  415. )
  416. /*++
  417. Routine Description:
  418. Submit a delayed command to an Frs Queue.
  419. Arguments:
  420. DelCmd
  421. Timeout - in milliseconds
  422. Return Value:
  423. None.
  424. --*/
  425. {
  426. #undef DEBSUB
  427. #define DEBSUB "FrsDelQueueSubmit:"
  428. PCOMMAND_PACKET Cmd;
  429. Cmd = FrsAllocCommand(&DelCs.Queue, CMD_DELAYED_QUEUE_SUBMIT);
  430. FrsSetCompletionRoutine(Cmd, DelCsCompletionRoutine, NULL);
  431. DsCs(Cmd) = NULL;
  432. DsCmd(Cmd) = DelCmd;
  433. DsTimeout(Cmd) = ComputeTimeout(Timeout);
  434. DPRINT2(5, "DelQueue: submit Cmd %x DelCmd %x\n", Cmd, DsCmd(Cmd));
  435. FrsSubmitCommandServer(&DelCs, Cmd);
  436. }
  437. VOID
  438. FrsDelCsCompleteSubmit(
  439. IN PCOMMAND_PACKET DelCmd,
  440. IN ULONG Timeout
  441. )
  442. /*++
  443. Routine Description:
  444. Submit a delayed complete-command to the DelCs
  445. Arguments:
  446. DelCmd
  447. Timeout - in milliseconds
  448. Return Value:
  449. None.
  450. --*/
  451. {
  452. #undef DEBSUB
  453. #define DEBSUB "FrsDelCsCompleteSubmit:"
  454. PCOMMAND_PACKET Cmd;
  455. Cmd = FrsAllocCommand(&DelCs.Queue, CMD_DELAYED_COMPLETE);
  456. FrsSetCompletionRoutine(Cmd, DelCsCompletionRoutine, NULL);
  457. DsCs(Cmd) = NULL;
  458. DsCmd(Cmd) = DelCmd;
  459. DsTimeout(Cmd) = ComputeTimeout(Timeout);
  460. COMMAND_TRACE(4, Cmd, "Del Complete");
  461. COMMAND_TRACE(4, DelCmd, "Del Complete Cmd");
  462. FrsSubmitCommandServer(&DelCs, Cmd);
  463. }
  464. VOID
  465. FrsDelCsSubmitUnIdled(
  466. IN PCOMMAND_SERVER Cs,
  467. IN PFRS_QUEUE IdledQueue,
  468. IN ULONG Timeout
  469. )
  470. /*++
  471. Routine Description:
  472. Submit a delayed "FrsRtlUnIdledQueue" command.
  473. Arguments:
  474. Cs
  475. IdledQueue
  476. Timeout - In milliSeconds
  477. Return Value:
  478. None.
  479. --*/
  480. {
  481. #undef DEBSUB
  482. #define DEBSUB "FrsDelCsSubmitUnIdled:"
  483. PCOMMAND_PACKET Cmd;
  484. Cmd = FrsAllocCommand(&DelCs.Queue, CMD_DELAYED_UNIDLED);
  485. FrsSetCompletionRoutine(Cmd, DelCsCompletionRoutine, NULL);
  486. DsCs(Cmd) = Cs;
  487. DsQueue(Cmd) = IdledQueue;
  488. DsTimeout(Cmd) = ComputeTimeout(Timeout);
  489. DPRINT2(5, "Del: submit Cmd 0x%x IdledQueue 0x%x\n", Cmd, DsQueue(Cmd));
  490. FrsSubmitCommandServer(&DelCs, Cmd);
  491. }
  492. VOID
  493. FrsDelCsSubmitKick(
  494. IN PCOMMAND_SERVER Cs,
  495. IN PFRS_QUEUE Queue,
  496. IN ULONG Timeout
  497. )
  498. /*++
  499. Routine Description:
  500. Submit a delayed "FrsKickCommandServer" command.
  501. Arguments:
  502. Cs
  503. Queue
  504. Timeout - In milliSeconds
  505. Return Value:
  506. None.
  507. --*/
  508. {
  509. #undef DEBSUB
  510. #define DEBSUB "FrsDelCsSubmitKick:"
  511. PCOMMAND_PACKET Cmd;
  512. Cmd = FrsAllocCommand(&DelCs.Queue, CMD_DELAYED_KICK);
  513. FrsSetCompletionRoutine(Cmd, DelCsCompletionRoutine, NULL);
  514. DsCs(Cmd) = Cs;
  515. DsQueue(Cmd) = Queue;
  516. DsTimeout(Cmd) = ComputeTimeout(Timeout);
  517. DPRINT2(5, "Del: submit Cmd 0x%x kick 0x%x\n", Cmd, DsCs(Cmd));
  518. FrsSubmitCommandServer(&DelCs, Cmd);
  519. }
  520. VOID
  521. ShutDownDelCs(
  522. VOID
  523. )
  524. /*++
  525. Routine Description:
  526. Shutdown the send command server
  527. Arguments:
  528. None.
  529. Return Value:
  530. None.
  531. --*/
  532. {
  533. #undef DEBSUB
  534. #define DEBSUB "ShutDownDelCs:"
  535. INT i;
  536. FrsRunDownCommandServer(&DelCs, &DelCs.Queue);
  537. for (i = 0; i < DELCS_MAXTHREADS; ++i) {
  538. SetEvent(DelCsEvent);
  539. }
  540. }