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.

638 lines
11 KiB

  1. //
  2. // Test/simulation program for the extended device queue
  3. //
  4. #include "raidport.h"
  5. #include "exqueue.h"
  6. #define SECONDS (1000)
  7. typedef struct _TQ_ITEM {
  8. ULONG Thread;
  9. ULONG64 Data;
  10. ULONG64 Sequence;
  11. KDEVICE_QUEUE_ENTRY DeviceEntry;
  12. LIST_ENTRY DpcEntry;
  13. } TQ_ITEM, *PTQ_ITEM;
  14. typedef struct _DPC_QUEUE {
  15. HANDLE Available;
  16. HANDLE Mutex;
  17. LIST_ENTRY Queue;
  18. ULONG Count;
  19. } DPC_QUEUE, *PDPC_QUEUE;
  20. BOOL Verbose = FALSE;
  21. BOOL Cerbose = TRUE;
  22. DPC_QUEUE DpcQueue;
  23. EXTENDED_DEVICE_QUEUE DeviceQueue;
  24. BOOLEAN Pause = FALSE;
  25. BOOLEAN PauseProducer = FALSE;
  26. ULONG64 GlobalSequence = 0;
  27. DWORD Owner = 0;
  28. BOOL Available = FALSE;
  29. VOID
  30. GetNext(
  31. OUT PULONG64 Sequence,
  32. OUT PULONG Data
  33. )
  34. {
  35. *Sequence = ++GlobalSequence;
  36. *Data = (ULONG)rand();
  37. }
  38. #pragma warning (disable:4715)
  39. BOOL
  40. WINAPI
  41. UpdateThread(
  42. PVOID Unused
  43. )
  44. {
  45. for (;;) {
  46. while (Pause) {
  47. Sleep (500);
  48. }
  49. printf ("Seq: %I64d, dev %d bypass %d dpc %d \r",
  50. GlobalSequence,
  51. DeviceQueue.DeviceRequests,
  52. DeviceQueue.ByPassRequests,
  53. DpcQueue.Count);
  54. Sleep (2000);
  55. }
  56. return FALSE;
  57. }
  58. VOID
  59. CreateDpcQueue(
  60. PDPC_QUEUE DpcQueue
  61. )
  62. {
  63. DpcQueue->Available = CreateEvent (NULL, FALSE, FALSE, NULL);
  64. DpcQueue->Mutex = CreateMutex (NULL, FALSE, NULL);
  65. InitializeListHead (&DpcQueue->Queue);
  66. DpcQueue->Count = 0;
  67. }
  68. VOID
  69. InsertDpcItem(
  70. IN PDPC_QUEUE DpcQueue,
  71. IN PLIST_ENTRY Entry
  72. )
  73. {
  74. WaitForSingleObject (DpcQueue->Mutex, INFINITE);
  75. InsertTailList (&DpcQueue->Queue, Entry);
  76. DpcQueue->Count++;
  77. Owner = GetCurrentThreadId ();
  78. Available = TRUE;
  79. SetEvent (DpcQueue->Available);
  80. ReleaseMutex (DpcQueue->Mutex);
  81. }
  82. PLIST_ENTRY
  83. RemoveDpcItem(
  84. IN PDPC_QUEUE DpcQueue
  85. )
  86. {
  87. PLIST_ENTRY Entry;
  88. HANDLE Tuple[2];
  89. Tuple[0] = DpcQueue->Mutex;
  90. Tuple[1] = DpcQueue->Available;
  91. WaitForMultipleObjects (2, Tuple, TRUE, INFINITE);
  92. Available = FALSE;
  93. Owner = GetCurrentThreadId ();
  94. ASSERT (!IsListEmpty (&DpcQueue->Queue));
  95. Entry = RemoveHeadList (&DpcQueue->Queue);
  96. DpcQueue->Count--;
  97. if (!IsListEmpty (&DpcQueue->Queue)) {
  98. Available = TRUE;
  99. SetEvent (DpcQueue->Available);
  100. }
  101. ReleaseMutex (DpcQueue->Mutex);
  102. return Entry;
  103. }
  104. BOOL
  105. WINAPI
  106. ProducerThread(
  107. PVOID Unused
  108. )
  109. {
  110. BOOLEAN Inserted;
  111. PTQ_ITEM Item;
  112. ULONG Data;
  113. ULONG64 Sequence;
  114. srand (GetCurrentThreadId());
  115. for (;;) {
  116. Sleep (10);
  117. while (Pause) {
  118. Sleep (100);
  119. }
  120. while (PauseProducer) {
  121. Sleep (100);
  122. }
  123. Item = malloc (sizeof (TQ_ITEM));
  124. ZeroMemory (Item, sizeof (*Item));
  125. GetNext (&Sequence, &Data);
  126. Item->Thread = GetCurrentThreadId ();
  127. Item->Sequence = Sequence;
  128. Item->Data = Data;
  129. Inserted = RaidInsertExDeviceQueue (&DeviceQueue,
  130. &Item->DeviceEntry,
  131. FALSE,
  132. (ULONG)Item->Data);
  133. if (!Inserted) {
  134. if (Verbose) {
  135. printf ("started %x.%I64d\n", Item->Thread, Item->Data);
  136. }
  137. InsertDpcItem (&DpcQueue, &Item->DpcEntry);
  138. } else {
  139. if (Verbose) {
  140. printf ("queued %x.%I64d\n", Item->Thread, Item->Data);
  141. }
  142. }
  143. }
  144. return FALSE;
  145. }
  146. BOOL
  147. WINAPI
  148. ProducerThread100(
  149. PVOID Unused
  150. )
  151. {
  152. BOOLEAN Inserted;
  153. PTQ_ITEM Item;
  154. ULONG Data;
  155. ULONG64 Sequence;
  156. srand (GetCurrentThreadId());
  157. for (;;) {
  158. Sleep (0);
  159. while (Pause) {
  160. Sleep (100);
  161. }
  162. while (PauseProducer) {
  163. Sleep (100);
  164. }
  165. Item = malloc (sizeof (TQ_ITEM));
  166. ZeroMemory (Item, sizeof (*Item));
  167. GetNext (&Sequence, &Data);
  168. Item->Thread = GetCurrentThreadId ();
  169. Item->Sequence = Sequence;
  170. Item->Data = 100;
  171. Inserted = RaidInsertExDeviceQueue (&DeviceQueue,
  172. &Item->DeviceEntry,
  173. FALSE,
  174. (ULONG)Item->Data);
  175. if (!Inserted) {
  176. if (Verbose) {
  177. printf ("started %x.%I64d\n", Item->Thread, Item->Data);
  178. }
  179. InsertDpcItem (&DpcQueue, &Item->DpcEntry);
  180. } else {
  181. if (Verbose) {
  182. printf ("queued %x.%I64d\n", Item->Thread, Item->Data);
  183. }
  184. }
  185. }
  186. return FALSE;
  187. }
  188. BOOL
  189. WINAPI
  190. ErrorProducerThread(
  191. PVOID Unused
  192. )
  193. {
  194. BOOLEAN Inserted;
  195. PTQ_ITEM Item;
  196. ULONG64 Sequence;
  197. ULONG Data;
  198. for (;;) {
  199. Sleep (500);
  200. while (Pause) {
  201. Sleep (10);
  202. }
  203. Item = malloc (sizeof (TQ_ITEM));
  204. ZeroMemory (Item, sizeof (*Item));
  205. GetNext (&Sequence, &Data);
  206. Item->Thread = GetCurrentThreadId ();
  207. Item->Sequence = Sequence;
  208. Item->Data = Data;
  209. Inserted = RaidInsertExDeviceQueue (&DeviceQueue,
  210. &Item->DeviceEntry,
  211. TRUE,
  212. (ULONG)Item->Data);
  213. if (!Inserted) {
  214. if (Verbose) {
  215. printf ("started %x.%I64d\n", Item->Thread, Item->Data);
  216. }
  217. InsertDpcItem (&DpcQueue, &Item->DpcEntry);
  218. } else {
  219. if (Verbose) {
  220. printf ("queued %x.%I64d\n", Item->Thread, Item->Data);
  221. }
  222. }
  223. }
  224. return FALSE;
  225. }
  226. VOID
  227. DpcRoutine(
  228. IN PTQ_ITEM Item
  229. )
  230. {
  231. BOOLEAN RestartQueue;
  232. PKDEVICE_QUEUE_ENTRY Entry;
  233. if (Verbose || Cerbose) {
  234. printf ("completed %x.%I64d\n", Item->Thread, Item->Data);
  235. }
  236. free (Item);
  237. Entry = RaidRemoveExDeviceQueue (&DeviceQueue, &RestartQueue);
  238. if (Entry) {
  239. Item = CONTAINING_RECORD (Entry, TQ_ITEM, DeviceEntry);
  240. InsertDpcItem (&DpcQueue, &Item->DpcEntry);
  241. if (Verbose) {
  242. printf ("dpc started %x.%I64d\n", Item->Thread, Item->Data);
  243. }
  244. //
  245. // NB: in the port driver, we actually only do this when necessary.
  246. // The only problem with doing this always is a speed issue, and
  247. // we're not measuring speed in the simulation program.
  248. //
  249. for (Entry = RaidNormalizeExDeviceQueue (&DeviceQueue);
  250. Entry != NULL;
  251. Entry = RaidNormalizeExDeviceQueue (&DeviceQueue)) {
  252. Item = CONTAINING_RECORD (Entry, TQ_ITEM, DeviceEntry);
  253. InsertDpcItem (&DpcQueue, &Item->DpcEntry);
  254. }
  255. }
  256. }
  257. BOOL
  258. WINAPI
  259. DpcThread(
  260. PVOID Unused
  261. )
  262. {
  263. PLIST_ENTRY Entry;
  264. PTQ_ITEM Item;
  265. #if 1
  266. SetThreadPriority (GetCurrentThread (),
  267. THREAD_PRIORITY_ABOVE_NORMAL);
  268. #endif
  269. for (;;) {
  270. while (Pause) {
  271. Sleep (10);
  272. }
  273. //
  274. // Wait for DPC queue to have an item in it
  275. //
  276. Entry = RemoveDpcItem (&DpcQueue);
  277. Item = CONTAINING_RECORD (Entry, TQ_ITEM, DpcEntry);
  278. DpcRoutine (Item);
  279. }
  280. return FALSE;
  281. }
  282. enum {
  283. NoControl = 0,
  284. FreezeQueue,
  285. ResumeQueue
  286. };
  287. volatile ULONG Control = NoControl;
  288. BOOL
  289. WINAPI
  290. ControlThread(
  291. PVOID Unused
  292. )
  293. {
  294. for (;;) {
  295. Sleep (500);
  296. switch (Control) {
  297. case FreezeQueue:
  298. RaidFreezeExDeviceQueue (&DeviceQueue);
  299. Control = NoControl;
  300. break;
  301. case ResumeQueue:
  302. RaidResumeExDeviceQueue (&DeviceQueue);
  303. Control = NoControl;
  304. break;
  305. case NoControl:
  306. break;
  307. default:
  308. ASSERT (FALSE);
  309. }
  310. }
  311. return FALSE;
  312. }
  313. BOOL
  314. WINAPI
  315. ControlHandler(
  316. DWORD Val
  317. )
  318. {
  319. PLIST_ENTRY NextEntry;
  320. PTQ_ITEM Item;
  321. int ch;
  322. if (Val != CTRL_C_EVENT) {
  323. return FALSE;
  324. }
  325. Pause = TRUE;
  326. Sleep (1000);
  327. printf ("\n");
  328. do {
  329. printf ("tq> ");
  330. ch = getchar ();
  331. printf (" %c\n", ch);
  332. switch (tolower (ch)) {
  333. case 'd':
  334. printf ("Dump of DeviceQueue: %p\n", &DeviceQueue);
  335. printf (" Depth %d\n", DeviceQueue.Depth);
  336. printf (" Outstanding %d\n", DeviceQueue.OutstandingRequests);
  337. printf (" Device %d\n", DeviceQueue.DeviceRequests);
  338. printf (" ByPass %d\n", DeviceQueue.ByPassRequests);
  339. printf (" Frozen %d\n", DeviceQueue.Frozen);
  340. break;
  341. case 'l':
  342. __try {
  343. ULONG Count;
  344. Count = 0;
  345. for ( NextEntry = DeviceQueue.DeviceListHead.Flink;
  346. NextEntry != &DeviceQueue.DeviceListHead;
  347. NextEntry = NextEntry->Flink ) {
  348. Count++;
  349. Item = CONTAINING_RECORD (NextEntry, TQ_ITEM, DeviceEntry);
  350. printf (" item %d.%I64d [seq=%d]\n",
  351. Item->Thread,
  352. Item->Data,
  353. Item->Sequence);
  354. }
  355. printf ("DeviceList: %d entries\n", Count);
  356. }
  357. __except (EXCEPTION_EXECUTE_HANDLER) {
  358. printf ("ERROR: Inconsistent device list!\n");
  359. }
  360. break;
  361. case 'r':
  362. Control = ResumeQueue;
  363. break;
  364. case 'f':
  365. Control = FreezeQueue;
  366. break;
  367. case 'q':
  368. exit (0);
  369. break;
  370. case 'c':
  371. case 'g':
  372. break;
  373. case 'p':
  374. if (PauseProducer) {
  375. printf ("unpausing producers\n");
  376. PauseProducer = FALSE;
  377. } else {
  378. printf ("unpausing producers\n");
  379. PauseProducer = TRUE;
  380. }
  381. break;
  382. case 'v':
  383. if (Verbose) {
  384. Verbose = FALSE;
  385. printf ("verbose mode off\n");
  386. } else {
  387. Verbose = TRUE;
  388. printf ("verbose mode enabled\n");
  389. }
  390. case 'x': {
  391. ULONG NewDepth;
  392. printf ("depth> ");
  393. scanf ("%d", &NewDepth);
  394. RaidSetExDeviceQueueDepth (&DeviceQueue, NewDepth);
  395. printf ("stack depth set to %d\n", NewDepth);
  396. break;
  397. }
  398. case '?':
  399. printf (" d - dump queue\n");
  400. printf (" f - freeze queue\n");
  401. printf (" r - resume queue\n");
  402. printf (" p - toggle pause of producer threads\n");
  403. printf (" u - resume producer threads\n");
  404. printf (" g - go\n");
  405. printf (" x - set stack depth to new value\n");
  406. printf (" v - toggle verbose mode\n");
  407. printf (" q - stop\n");
  408. break;
  409. default:
  410. printf ("unrecognized operation '%c'\n", ch);
  411. }
  412. } while (ch != 'c' && ch != 'g');
  413. Pause = FALSE;
  414. return TRUE;
  415. }
  416. VOID
  417. __cdecl
  418. main(
  419. )
  420. {
  421. DWORD ThreadId;
  422. ULONG Depth;
  423. ULONG ProducerThreads;
  424. ULONG DpcThreads;
  425. ULONG i;
  426. SCHEDULING_ALGORITHM SchedulingAlgorithm;
  427. RAID_ADAPTER_QUEUE AdapterQueue;
  428. QUEUING_MODEL QueuingModel;
  429. //
  430. // Generic adapter queue.
  431. //
  432. QueuingModel.Algorithm = BackOffFullQueue;
  433. QueuingModel.BackOff.HighWaterPercent = 120;
  434. QueuingModel.BackOff.LowWaterPercent = 40;
  435. RaidCreateAdapterQueue (&AdapterQueue, &QueuingModel);
  436. //
  437. // NB: these should all be parameters
  438. //
  439. Depth = 1;
  440. ProducerThreads = 8;
  441. DpcThreads = 1;
  442. SchedulingAlgorithm = CScanScheduling;
  443. printf ("DeviceQueue Test: Depth %d Producers %d DPC Threads %d\n",
  444. Depth,
  445. ProducerThreads,
  446. DpcThreads);
  447. if (Verbose) {
  448. printf ("Verbose\n");
  449. }
  450. printf ("\n");
  451. CreateDpcQueue (&DpcQueue);
  452. RaidInitializeExDeviceQueue (&DeviceQueue,
  453. &AdapterQueue,
  454. Depth,
  455. SchedulingAlgorithm);
  456. SetConsoleCtrlHandler (ControlHandler, TRUE);
  457. for (i = 0; i < DpcThreads; i++) {
  458. CreateThread (NULL,
  459. 0,
  460. DpcThread,
  461. 0,
  462. 0,
  463. &ThreadId);
  464. }
  465. for (i = 0; i < ProducerThreads; i++) {
  466. CreateThread (NULL,
  467. 0,
  468. ProducerThread,
  469. 0,
  470. 0,
  471. &ThreadId);
  472. }
  473. CreateThread (NULL,
  474. 0,
  475. ControlThread,
  476. 0,
  477. 0,
  478. &ThreadId);
  479. CreateThread (NULL,
  480. 0,
  481. ProducerThread100,
  482. 0,
  483. 0,
  484. &ThreadId);
  485. #if 0
  486. CreateThread (NULL,
  487. 0,
  488. ErrorProducerThread,
  489. 0,
  490. 0,
  491. &ThreadId);
  492. CreateThread (NULL,
  493. 0,
  494. UpdateThread,
  495. 0,
  496. 0,
  497. &ThreadId);
  498. #endif
  499. Sleep (INFINITE);
  500. }