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.

700 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. conidle.c
  5. Abstract:
  6. This module builds a console test program to stress idle
  7. detection, and registration/unregistration mechanisms.
  8. The quality of the code for the test programs is as such.
  9. Author:
  10. Cenk Ergan (cenke)
  11. Environment:
  12. User Mode
  13. --*/
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <wmium.h>
  19. #include <ntdddisk.h>
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <time.h>
  23. #include "idlrpc.h"
  24. #include "idlecomn.h"
  25. //
  26. // Note that the following code is test quality code.
  27. //
  28. DWORD
  29. RegisterIdleTask (
  30. IN IT_IDLE_TASK_ID IdleTaskId,
  31. OUT HANDLE *ItHandle,
  32. OUT HANDLE *StartEvent,
  33. OUT HANDLE *StopEvent
  34. );
  35. DWORD
  36. UnregisterIdleTask (
  37. IN HANDLE ItHandle,
  38. IN HANDLE StartEvent,
  39. IN HANDLE StopEvent
  40. );
  41. DWORD
  42. ProcessIdleTasks (
  43. VOID
  44. );
  45. #define NUM_TEST_TASKS 3
  46. typedef enum _WORKTYPE {
  47. CpuWork,
  48. DiskWork,
  49. MaxWorkType
  50. } WORKTYPE, *PWORKTYPE;
  51. typedef struct _TESTTASK {
  52. HANDLE ThreadHandle;
  53. ULONG No;
  54. IT_IDLE_TASK_ID Id;
  55. IT_HANDLE ItHandle;
  56. HANDLE StartEvent;
  57. HANDLE StopEvent;
  58. } TESTTASK, *PTESTTASK;
  59. typedef struct _TESTWORK {
  60. ULONG No;
  61. WORKTYPE Type;
  62. DWORD WorkLength;
  63. HANDLE StopEvent;
  64. } TESTWORK, *PTESTWORK;
  65. TESTTASK g_Tasks[NUM_TEST_TASKS];
  66. BOOLEAN g_ProcessingIdleTasks = FALSE;
  67. HANDLE g_ProcessedIdleTasksEvent = NULL;
  68. #define MAX_WAIT_FOR_START 20000
  69. #define MAX_WORK_LENGTH 5000
  70. #define MAX_READ_SIZE (64 * 1024)
  71. DWORD
  72. WINAPI
  73. DoWorkThreadProc(
  74. LPVOID lpParameter
  75. )
  76. {
  77. PTESTWORK Work;
  78. DWORD EndTime;
  79. DWORD WaitResult;
  80. DWORD ErrorCode;
  81. DWORD RunTillTime;
  82. HANDLE DiskHandle;
  83. PVOID ReadBuffer;
  84. BOOL ReadResult;
  85. ULONG NumBytesRead;
  86. LARGE_INTEGER VolumeSize;
  87. LARGE_INTEGER SeekPosition;
  88. ULONG ReadIdx;
  89. DISK_GEOMETRY DiskGeometry;
  90. ULONG BytesReturned;
  91. static LONG DiskNumber;
  92. //
  93. // Initialize locals.
  94. //
  95. Work = lpParameter;
  96. EndTime = GetTickCount() + Work->WorkLength;
  97. DiskHandle = NULL;
  98. ReadBuffer = NULL;
  99. //
  100. // Do initialization for performing specified work.
  101. //
  102. switch (Work->Type) {
  103. case DiskWork:
  104. //
  105. // Open disk. Maybe we could open different physical drives
  106. // each time.
  107. //
  108. DiskHandle = CreateFile(L"\\\\.\\PHYSICALDRIVE0",
  109. GENERIC_READ,
  110. FILE_SHARE_READ | FILE_SHARE_WRITE,
  111. NULL,
  112. OPEN_EXISTING,
  113. FILE_FLAG_NO_BUFFERING,
  114. 0);
  115. if (!DiskHandle) {
  116. ErrorCode = GetLastError();
  117. printf("W%d: Failed open PHYSICALDRIVE0.\n", Work->No);
  118. goto cleanup;
  119. }
  120. //
  121. // Get volume size.
  122. //
  123. if (!DeviceIoControl(DiskHandle,
  124. IOCTL_DISK_GET_DRIVE_GEOMETRY,
  125. NULL,
  126. 0,
  127. &DiskGeometry,
  128. sizeof(DiskGeometry),
  129. &BytesReturned,
  130. NULL)) {
  131. ErrorCode = GetLastError();
  132. printf("W%d: Failed GET_DRIVE_GEOMETRY.\n", Work->No);
  133. goto cleanup;
  134. }
  135. VolumeSize.QuadPart = DiskGeometry.Cylinders.QuadPart *
  136. DiskGeometry.TracksPerCylinder *
  137. DiskGeometry.SectorsPerTrack *
  138. DiskGeometry.BytesPerSector;
  139. //
  140. // Allocate buffer.
  141. //
  142. ReadBuffer = VirtualAlloc(NULL,
  143. MAX_READ_SIZE,
  144. MEM_COMMIT,
  145. PAGE_READWRITE);
  146. if (!ReadBuffer) {
  147. ErrorCode = ERROR_NOT_ENOUGH_MEMORY;
  148. printf("W%d: Failed VirtualAlloc.\n", Work->No);
  149. goto cleanup;
  150. }
  151. break;
  152. default:
  153. //
  154. // Nothing to prepare.
  155. //
  156. break;
  157. }
  158. while (GetTickCount() < EndTime) {
  159. //
  160. // Check if we are asked to stop.
  161. //
  162. WaitResult = WaitForSingleObject(Work->StopEvent, 0);
  163. if (WaitResult == WAIT_OBJECT_0) {
  164. ErrorCode = ERROR_SUCCESS;
  165. goto cleanup;
  166. }
  167. //
  168. // Do a unit of work that should not take more than several
  169. // tens of milliseconds.
  170. //
  171. switch (Work->Type) {
  172. case CpuWork:
  173. RunTillTime = GetTickCount() + 10;
  174. while (GetTickCount() < RunTillTime) ;
  175. break;
  176. case DiskWork:
  177. //
  178. // Seek to random position.
  179. //
  180. SeekPosition.QuadPart = rand() * 4 * 1024;
  181. SeekPosition.QuadPart %= VolumeSize.QuadPart;
  182. if (!SetFilePointerEx(DiskHandle,
  183. SeekPosition,
  184. NULL,
  185. FILE_BEGIN)) {
  186. printf("W%d: Failed SetFilePointerEx.\n", Work->No);
  187. ErrorCode = GetLastError();
  188. goto cleanup;
  189. }
  190. //
  191. // Issue read.
  192. //
  193. ReadResult = ReadFile(DiskHandle,
  194. ReadBuffer,
  195. MAX_READ_SIZE,
  196. &NumBytesRead,
  197. NULL);
  198. if (!ReadResult) {
  199. printf("W%d: Failed ReadFile.\n", Work->No);
  200. ErrorCode = GetLastError();
  201. goto cleanup;
  202. }
  203. break;
  204. default:
  205. printf("W%d: Not valid work type %d!\n", Work->No, Work->Type);
  206. ErrorCode = ERROR_INVALID_PARAMETER;
  207. goto cleanup;
  208. }
  209. }
  210. ErrorCode = ERROR_SUCCESS;
  211. cleanup:
  212. if (DiskHandle) {
  213. CloseHandle(DiskHandle);
  214. }
  215. if (ReadBuffer) {
  216. VirtualFree(ReadBuffer, 0, MEM_RELEASE);
  217. }
  218. printf("W%d: Exiting with error code: %d\n", Work->No, ErrorCode);
  219. return ErrorCode;
  220. }
  221. DWORD
  222. WINAPI
  223. TaskThreadProc(
  224. LPVOID lpParameter
  225. )
  226. {
  227. PTESTTASK Task = lpParameter;
  228. TESTWORK Work;
  229. DWORD ErrorCode;
  230. WORKTYPE Type;
  231. DWORD WaitResult;
  232. DWORD WaitForStart;
  233. HANDLE WorkerThreadHandle;
  234. DWORD WorkLength;
  235. HANDLE Events[2];
  236. DWORD ElapsedTime;
  237. DWORD StartTime;
  238. ULONG TryIdx;
  239. BOOLEAN RegisteredIdleTask;
  240. //
  241. // Initialize locals.
  242. //
  243. RegisteredIdleTask = FALSE;
  244. WorkerThreadHandle = NULL;
  245. RtlZeroMemory(&Work, sizeof(Work));
  246. //
  247. // Initialize work structure.
  248. //
  249. Work.StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  250. if (!Work.StopEvent) {
  251. goto cleanup;
  252. }
  253. Work.No = Task->No;
  254. //
  255. // Loop registering, running, unregistering idle tasks.
  256. //
  257. while (TRUE) {
  258. //
  259. // If we are force-processing all tasks, usually wait for all tasks
  260. // to complete before queueing a new task.
  261. //
  262. if (g_ProcessingIdleTasks) {
  263. if ((rand() % 3) != 0) {
  264. printf("%d: Waiting for g_ProcessedIdleTasksEvent\n", Task->No);
  265. WaitResult = WaitForSingleObject(g_ProcessedIdleTasksEvent, INFINITE);
  266. if (WaitResult != WAIT_OBJECT_0) {
  267. ErrorCode = GetLastError();
  268. printf("%d: Failed wait for g_ProcessedIdleTasksEvent=%x\n", Task->No, ErrorCode);
  269. goto cleanup;
  270. }
  271. }
  272. }
  273. //
  274. // Register the idle task.
  275. //
  276. ErrorCode = RegisterIdleTask(Task->Id,
  277. &Task->ItHandle,
  278. &Task->StartEvent,
  279. &Task->StopEvent);
  280. if (ErrorCode != ERROR_SUCCESS) {
  281. printf("%d: Could not register: %d\n", Task->No, ErrorCode);
  282. goto cleanup;
  283. }
  284. RegisteredIdleTask = TRUE;
  285. //
  286. // Determine task parameters.
  287. //
  288. Type = rand() % MaxWorkType;
  289. WaitForStart = rand() % MAX_WAIT_FOR_START;
  290. WorkLength = rand() % MAX_WORK_LENGTH;
  291. //
  292. // Update work item.
  293. //
  294. Work.Type = Type;
  295. Work.WorkLength = WorkLength;
  296. printf("%d: NewTask Type=%d,WStart=%d,Length=%d,Handle=%p\n",
  297. Task->No, Type, WaitForStart, WorkLength, Task->ItHandle);
  298. do {
  299. //
  300. // Wait to be signaled.
  301. //
  302. printf("%d: Waiting for start\n", Task->No);
  303. WaitResult = WaitForSingleObject(Task->StartEvent, WaitForStart);
  304. if (WaitResult == WAIT_TIMEOUT) {
  305. printf("%d: Timed out wait for start. Re-registering\n", Task->No);
  306. break;
  307. }
  308. //
  309. // Spawn the work.
  310. //
  311. ResetEvent(Work.StopEvent);
  312. StartTime = GetTickCount();
  313. WorkerThreadHandle = CreateThread(NULL,
  314. 0,
  315. DoWorkThreadProc,
  316. &Work,
  317. 0,
  318. NULL);
  319. if (!WorkerThreadHandle) {
  320. ErrorCode = GetLastError();
  321. printf("%d: Failed spawn work: %d\n", Task->No, ErrorCode);
  322. goto cleanup;
  323. }
  324. //
  325. // Wait for stop event to be signaled or the work to be
  326. // completed.
  327. //
  328. Events[0] = WorkerThreadHandle;
  329. Events[1] = Task->StopEvent;
  330. printf("%d: Waiting for stop or workdone\n", Task->No);
  331. WaitResult = WaitForMultipleObjects(2,
  332. Events,
  333. FALSE,
  334. INFINITE);
  335. if (WaitResult == WAIT_OBJECT_0) {
  336. //
  337. // Break out if the work was done.
  338. //
  339. printf("%d: Work done.\n", Task->No);
  340. CloseHandle(WorkerThreadHandle);
  341. WorkerThreadHandle = NULL;
  342. break;
  343. } else if (WaitResult == WAIT_OBJECT_0 + 1) {
  344. //
  345. // We were told to stop. Signal the worker thread and
  346. // wait.
  347. //
  348. printf("%d: Stopped, Waiting for thread to exit\n", Task->No);
  349. SetEvent(Work.StopEvent);
  350. WaitForSingleObject(WorkerThreadHandle, INFINITE);
  351. CloseHandle(WorkerThreadHandle);
  352. WorkerThreadHandle = NULL;
  353. //
  354. // This is not really the time we worked (e.g. we may be
  355. // switched out etc.) We want to keep rolling and this is
  356. // what we can get easily.
  357. //
  358. ElapsedTime = GetTickCount() - StartTime;
  359. if (ElapsedTime > Work.WorkLength) {
  360. //
  361. // We've gone too long with this work. Unregistester
  362. // this task and pick another one.
  363. //
  364. break;
  365. }
  366. Work.WorkLength -= ElapsedTime;
  367. //
  368. // Loop on until we pass enough time with this work.
  369. //
  370. } else {
  371. //
  372. // There was an error.
  373. //
  374. ErrorCode = GetLastError();
  375. printf("%d: WaitForMultipleObjects failed: %d\n", Task->No, ErrorCode);
  376. goto cleanup;
  377. }
  378. } while (TRUE);
  379. ASSERT(RegisteredIdleTask);
  380. UnregisterIdleTask(Task->ItHandle,
  381. Task->StartEvent,
  382. Task->StopEvent);
  383. RegisteredIdleTask = FALSE;
  384. }
  385. cleanup:
  386. if (RegisteredIdleTask) {
  387. UnregisterIdleTask(Task->ItHandle,
  388. Task->StartEvent,
  389. Task->StopEvent);
  390. }
  391. if (WorkerThreadHandle) {
  392. SetEvent(Work.StopEvent);
  393. WaitForSingleObject(WorkerThreadHandle, INFINITE);
  394. CloseHandle(WorkerThreadHandle);
  395. }
  396. if (Work.StopEvent) {
  397. CloseHandle(Work.StopEvent);
  398. }
  399. return ErrorCode;
  400. }
  401. int
  402. __cdecl
  403. main(int argc, char* argv[])
  404. {
  405. DWORD ErrorCode;
  406. ULONG TaskIdx;
  407. IT_IDLE_DETECTION_PARAMETERS Parameters;
  408. PTESTTASK Task;
  409. INPUT MouseInput;
  410. ULONG SleepTime;
  411. //
  412. // Initialize locals.
  413. //
  414. RtlZeroMemory(&MouseInput, sizeof(MouseInput));
  415. MouseInput.type = INPUT_MOUSE;
  416. MouseInput.mi.dwFlags = MOUSEEVENTF_MOVE;
  417. //
  418. // Initialize globals.
  419. //
  420. g_ProcessingIdleTasks = FALSE;
  421. g_ProcessedIdleTasksEvent = NULL;
  422. //
  423. // Initialize random.
  424. //
  425. srand((unsigned)time(NULL));
  426. //
  427. // Create an manual reset event that will be signaled when we finish
  428. // processing all tasks after telling the server to process all tasks.
  429. //
  430. g_ProcessedIdleTasksEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  431. if (!g_ProcessedIdleTasksEvent) {
  432. ErrorCode = GetLastError();
  433. printf("Failed to create g_ProcessedIdleTasksEvent=%x\n",ErrorCode);
  434. goto cleanup;
  435. }
  436. //
  437. // Set idle detection parameters for stress.
  438. //
  439. Parameters.IdleDetectionPeriod = 1000;
  440. Parameters.IdleVerificationPeriod = 500;
  441. Parameters.NumVerifications = 2;
  442. Parameters.IdleInputCheckPeriod = 100;
  443. Parameters.IdleTaskRunningCheckPeriod = 1000;
  444. Parameters.MinCpuIdlePercentage = 50;
  445. Parameters.MinDiskIdlePercentage = 50;
  446. Parameters.MaxNumRegisteredTasks = 500;
  447. RpcTryExcept {
  448. ErrorCode = ItSrvSetDetectionParameters(NULL, &Parameters);
  449. }
  450. RpcExcept(IT_RPC_EXCEPTION_HANDLER()) {
  451. ErrorCode = RpcExceptionCode();
  452. }
  453. RpcEndExcept
  454. if (ErrorCode != ERROR_SUCCESS) {
  455. printf("Failed set idle detection params for stress.\n");
  456. goto cleanup;
  457. }
  458. //
  459. // Register and start tasks.
  460. //
  461. for (TaskIdx = 0; TaskIdx < NUM_TEST_TASKS; TaskIdx++) {
  462. Task = &g_Tasks[TaskIdx];
  463. Task->No = TaskIdx;
  464. Task->Id = ItOptimalDiskLayoutTaskId;
  465. Task->ThreadHandle = CreateThread(NULL,
  466. 0,
  467. TaskThreadProc,
  468. &g_Tasks[TaskIdx],
  469. 0,
  470. 0);
  471. if (!Task->ThreadHandle) {
  472. ErrorCode = GetLastError();
  473. printf("Could not spawn task %d: %x\n", TaskIdx, ErrorCode);
  474. goto cleanup;
  475. }
  476. }
  477. //
  478. // Loop forever sending input messages once in a while to stop
  479. // idle tasks.
  480. //
  481. while (1) {
  482. SleepTime = MAX_WAIT_FOR_START * (rand() % 64) / 64;
  483. Sleep(SleepTime);
  484. //
  485. // Every so often, ask all idle tasks to be processed.
  486. //
  487. if ((rand() % 2) == 0) {
  488. if ((rand() % 2) == 0) {
  489. printf("MainThread: Sending user input before processing all tasks\n");
  490. SendInput(1, &MouseInput, sizeof(MouseInput));
  491. }
  492. printf("MainThread: ProcessIdleTasks()\n");
  493. ResetEvent(g_ProcessedIdleTasksEvent);
  494. g_ProcessingIdleTasks = TRUE;
  495. ErrorCode = ProcessIdleTasks();
  496. printf("MainThread: ProcessIdleTasks()=%x\n",ErrorCode);
  497. g_ProcessingIdleTasks = FALSE;
  498. SetEvent(g_ProcessedIdleTasksEvent);
  499. if (ErrorCode != ERROR_SUCCESS) {
  500. goto cleanup;
  501. }
  502. }
  503. if ((rand() % 2) == 0) {
  504. printf("MainThread: Sending user input\n");
  505. SendInput(1, &MouseInput, sizeof(MouseInput));
  506. }
  507. }
  508. cleanup:
  509. if (g_ProcessedIdleTasksEvent) {
  510. CloseHandle(g_ProcessedIdleTasksEvent);
  511. }
  512. return ErrorCode;
  513. }
  514. /*********************************************************************/
  515. /* MIDL allocate and free */
  516. /*********************************************************************/
  517. void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
  518. {
  519. return(HeapAlloc(GetProcessHeap(),0,(len)));
  520. }
  521. void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
  522. {
  523. HeapFree(GetProcessHeap(),0,(ptr));
  524. }