Source code of Windows XP (NT5)
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.

688 lines
16 KiB

  1. #include <string.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <time.h>
  5. #include "windows.h"
  6. HANDLE PrintfAvailable;
  7. HANDLE ReadyToWork;
  8. HANDLE ReadyToReport;
  9. HANDLE DoneReporting;
  10. HANDLE StartOperationsEvent;
  11. HANDLE BeginReporting;
  12. typedef struct _THREAD_WORK {
  13. char *NameOfPort;
  14. HANDLE FileToUse;
  15. DWORD NumberOfChars;
  16. BOOL DoWrite;
  17. OVERLAPPED Ol;
  18. UCHAR BufferForOp[1];
  19. } THREAD_WORK,*PTHREAD_WORK;
  20. char NameOfWrite[] = "Write";
  21. char NameOfRead[] = "Read";
  22. DWORD
  23. WorkThread(
  24. LPVOID ThreadContext
  25. )
  26. {
  27. PTHREAD_WORK ToDo = ThreadContext;
  28. DWORD FinalCountOfOp;
  29. DWORD LastError;
  30. clock_t Start;
  31. clock_t Finish;
  32. BOOL OpDone;
  33. char *OperationName;
  34. OperationName = (ToDo->DoWrite)?(&NameOfWrite[0]):(&NameOfRead[0]);
  35. if (!ReleaseSemaphore(ReadyToWork,1,NULL)) {
  36. WaitForSingleObject(PrintfAvailable,-1);
  37. printf(
  38. "Couldn't release the ready to start semaphore for port %s\n",
  39. ToDo->NameOfPort
  40. );
  41. ReleaseSemaphore(PrintfAvailable,1,NULL);
  42. ReleaseSemaphore(ReadyToReport,1,NULL);
  43. ReleaseSemaphore(DoneReporting,1,NULL);
  44. return 1;
  45. }
  46. WaitForSingleObject(StartOperationsEvent,-1);
  47. if (ToDo->DoWrite) {
  48. Start = clock();
  49. OpDone = WriteFile(
  50. ToDo->FileToUse,
  51. &ToDo->BufferForOp[0],
  52. ToDo->NumberOfChars,
  53. &FinalCountOfOp,
  54. &ToDo->Ol
  55. );
  56. } else {
  57. Start = clock();
  58. OpDone = ReadFile(
  59. ToDo->FileToUse,
  60. &ToDo->BufferForOp[0],
  61. ToDo->NumberOfChars,
  62. &FinalCountOfOp,
  63. &ToDo->Ol
  64. );
  65. }
  66. if (!OpDone) {
  67. LastError = GetLastError();
  68. if (LastError != ERROR_IO_PENDING) {
  69. WaitForSingleObject(PrintfAvailable,-1);
  70. printf(
  71. "Could not start the %s for %s - error: %d\n",
  72. OperationName,
  73. ToDo->NameOfPort,
  74. LastError
  75. );
  76. ReleaseSemaphore(PrintfAvailable,1,NULL);
  77. ReleaseSemaphore(ReadyToReport,1,NULL);
  78. ReleaseSemaphore(DoneReporting,1,NULL);
  79. return 1;
  80. }
  81. if (!GetOverlappedResult(
  82. ToDo->FileToUse,
  83. &ToDo->Ol,
  84. &FinalCountOfOp,
  85. TRUE
  86. )) {
  87. LastError = GetLastError();
  88. WaitForSingleObject(PrintfAvailable,-1);
  89. printf(
  90. "Wait on %s for port %s failed - error: %d\n",
  91. OperationName,
  92. ToDo->NameOfPort,
  93. LastError
  94. );
  95. ReleaseSemaphore(PrintfAvailable,1,NULL);
  96. ReleaseSemaphore(ReadyToReport,1,NULL);
  97. ReleaseSemaphore(DoneReporting,1,NULL);
  98. return 1;
  99. }
  100. }
  101. Finish = clock();
  102. if (!ReleaseSemaphore(ReadyToReport,1,NULL)) {
  103. WaitForSingleObject(PrintfAvailable,-1);
  104. printf(
  105. "Couldn't release the ready to report semaphore for port %s\n",
  106. ToDo->NameOfPort
  107. );
  108. ReleaseSemaphore(PrintfAvailable,1,NULL);
  109. return 1;
  110. }
  111. WaitForSingleObject(BeginReporting,-1);
  112. WaitForSingleObject(PrintfAvailable,-1);
  113. printf("%s for %s\n",OperationName,ToDo->NameOfPort);
  114. printf("-------Time to write %f\n",(((double)(Finish-Start))/CLOCKS_PER_SEC));
  115. printf("-------Chars per second %f\n",((double)FinalCountOfOp)/(((double)(Finish-Start))/CLOCKS_PER_SEC));
  116. printf("-------Number actually done by %s: %d.\n",OperationName,FinalCountOfOp);
  117. //
  118. // if this is the write code then check the data.
  119. //
  120. if (ToDo->DoWrite) {
  121. DWORD TotalCount;
  122. DWORD j;
  123. for (
  124. TotalCount = 0;
  125. TotalCount < FinalCountOfOp;
  126. ) {
  127. for (
  128. j = (0xff - 10);
  129. j != 0; // When it wraps around.
  130. j++
  131. ) {
  132. if (ToDo->BufferForOp[TotalCount] != ((UCHAR)j)) {
  133. WaitForSingleObject(PrintfAvailable,-1);
  134. printf("Bad data starting at: %d\n",TotalCount);
  135. printf("BufferForOp[TotalCount]: %x\n",ToDo->BufferForOp[TotalCount]);
  136. printf("j: %x\n",j);
  137. ReleaseSemaphore(PrintfAvailable,1,NULL);
  138. goto DoneWithCheck;
  139. }
  140. TotalCount++;
  141. if (TotalCount >= FinalCountOfOp) {
  142. goto DoneWithCheck;
  143. }
  144. }
  145. }
  146. DoneWithCheck:;
  147. }
  148. ReleaseSemaphore(PrintfAvailable,1,NULL);
  149. if (!ReleaseSemaphore(DoneReporting,1,NULL)) {
  150. WaitForSingleObject(PrintfAvailable,-1);
  151. printf(
  152. "Couldn't release the done reporting semaphore for port %s\n",
  153. ToDo->NameOfPort
  154. );
  155. ReleaseSemaphore(PrintfAvailable,1,NULL);
  156. }
  157. return 1;
  158. }
  159. void main(int argc,char *argv[]) {
  160. HANDLE hFile;
  161. DCB MyDcb;
  162. DWORD NumberOfChars;
  163. DWORD UseBaud;
  164. DWORD NumberOfDataBits = 8;
  165. COMMTIMEOUTS To;
  166. DWORD i;
  167. DWORD NumberOfPorts;
  168. if (argc < 4) {
  169. printf("Ivalid number of args - tserialm #chars Baud COMx [COMX...]\n");
  170. }
  171. NumberOfPorts = argc - 3;
  172. sscanf(argv[1],"%d",&NumberOfChars);
  173. sscanf(argv[2],"%d",&UseBaud);
  174. //
  175. // Create a global event that each thread will wait on
  176. // to start it's work.
  177. //
  178. StartOperationsEvent = CreateEvent(
  179. NULL,
  180. TRUE,
  181. FALSE,
  182. NULL
  183. );
  184. if (!StartOperationsEvent) {
  185. printf("StartOperationsEvent could not be created\n");
  186. exit(1);
  187. }
  188. //
  189. // Create a global event that each thread will wait on
  190. // to start reporting its results.
  191. //
  192. BeginReporting = CreateEvent(
  193. NULL,
  194. TRUE,
  195. FALSE,
  196. NULL
  197. );
  198. if (!BeginReporting) {
  199. printf("Begin reporting could not be created\n");
  200. exit(1);
  201. }
  202. //
  203. // Create a semaphore that is used to make sure that
  204. // only one thread is doing printf at a time.
  205. //
  206. PrintfAvailable = CreateSemaphore(
  207. NULL,
  208. 1,
  209. 1,
  210. NULL
  211. );
  212. if (!PrintfAvailable) {
  213. printf("PrintfAvailable could not be created\n");
  214. exit(1);
  215. }
  216. //
  217. // Create a semaphore that is used to indicate that all threads
  218. // are waiting to work.
  219. //
  220. ReadyToWork = CreateSemaphore(
  221. NULL,
  222. 0,
  223. NumberOfPorts*2,
  224. NULL
  225. );
  226. if (!ReadyToWork) {
  227. printf("Ready to work could not be created\n");
  228. exit(1);
  229. }
  230. //
  231. // Create a semaphore that is used to indicate that all threads
  232. // are ready to report their results.
  233. //
  234. ReadyToReport = CreateSemaphore(
  235. NULL,
  236. 0,
  237. NumberOfPorts*2,
  238. NULL
  239. );
  240. if (!ReadyToReport) {
  241. printf("Ready to report could not be created\n");
  242. exit(1);
  243. }
  244. //
  245. // Create a semaphore that is used to indicate that all threads
  246. // are done reporting.
  247. //
  248. DoneReporting = CreateSemaphore(
  249. NULL,
  250. 0,
  251. NumberOfPorts*2,
  252. NULL
  253. );
  254. if (!DoneReporting) {
  255. printf("Done reporting could not be created\n");
  256. exit(1);
  257. }
  258. for (
  259. i = 1;
  260. i <= NumberOfPorts;
  261. i++
  262. ) {
  263. PTHREAD_WORK ReadContext;
  264. PTHREAD_WORK WriteContext;
  265. DWORD TotalCount;
  266. DWORD j;
  267. DWORD ThreadId;
  268. if ((hFile = CreateFile(
  269. argv[i+2],
  270. GENERIC_READ | GENERIC_WRITE,
  271. 0,
  272. NULL,
  273. CREATE_ALWAYS,
  274. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  275. NULL
  276. )) == ((HANDLE)-1)) {
  277. WaitForSingleObject(PrintfAvailable,-1);
  278. printf(
  279. "Couldn't open %s\n",
  280. argv[i+2]
  281. );
  282. ReleaseSemaphore(PrintfAvailable,1,NULL);
  283. exit(1);
  284. }
  285. To.ReadIntervalTimeout = 0;
  286. To.ReadTotalTimeoutMultiplier = ((1000+(((UseBaud+9)/10)-1))/((UseBaud+9)/10));
  287. if (!To.ReadTotalTimeoutMultiplier) {
  288. To.ReadTotalTimeoutMultiplier = 1;
  289. }
  290. To.WriteTotalTimeoutMultiplier = ((1000+(((UseBaud+9)/10)-1))/((UseBaud+9)/10));
  291. if (!To.WriteTotalTimeoutMultiplier) {
  292. To.WriteTotalTimeoutMultiplier = 1;
  293. }
  294. To.ReadTotalTimeoutConstant = 5000;
  295. To.WriteTotalTimeoutConstant = 5000;
  296. if (!SetCommTimeouts(
  297. hFile,
  298. &To
  299. )) {
  300. WaitForSingleObject(PrintfAvailable,-1);
  301. printf(
  302. "Couldn't set the timeouts for port %s error %d\n",
  303. argv[i+2],
  304. GetLastError()
  305. );
  306. ReleaseSemaphore(PrintfAvailable,1,NULL);
  307. exit(1);
  308. }
  309. if (!GetCommState(
  310. hFile,
  311. &MyDcb
  312. )) {
  313. WaitForSingleObject(PrintfAvailable,-1);
  314. printf(
  315. "Couldn't get the comm state for port %s error %d\n",
  316. argv[i+2],
  317. GetLastError()
  318. );
  319. ReleaseSemaphore(PrintfAvailable,1,NULL);
  320. exit(1);
  321. }
  322. MyDcb.BaudRate = UseBaud;
  323. MyDcb.ByteSize = 8;
  324. MyDcb.Parity = NOPARITY;
  325. MyDcb.StopBits = ONESTOPBIT;
  326. MyDcb.fOutxDsrFlow = TRUE;
  327. MyDcb.fDtrControl = DTR_CONTROL_HANDSHAKE;
  328. if (!SetCommState(
  329. hFile,
  330. &MyDcb
  331. )) {
  332. WaitForSingleObject(PrintfAvailable,-1);
  333. printf(
  334. "Couldn't set the comm state for port %s error %d\n",
  335. argv[i+2],
  336. GetLastError()
  337. );
  338. ReleaseSemaphore(PrintfAvailable,1,NULL);
  339. exit(1);
  340. }
  341. //
  342. // Alloc two thread contexts for the read and the
  343. // write thread.
  344. //
  345. ReadContext = malloc(sizeof(THREAD_WORK)+(NumberOfChars-1));
  346. if (!ReadContext) {
  347. WaitForSingleObject(PrintfAvailable,-1);
  348. printf(
  349. "Couldn't create the read thread context for %s\n",
  350. argv[i+2]
  351. );
  352. ReleaseSemaphore(PrintfAvailable,1,NULL);
  353. exit(1);
  354. }
  355. WriteContext = malloc(sizeof(THREAD_WORK)+(NumberOfChars-1));
  356. if (!WriteContext) {
  357. WaitForSingleObject(PrintfAvailable,-1);
  358. printf(
  359. "Couldn't create the write thread context for %s\n",
  360. argv[i+2]
  361. );
  362. ReleaseSemaphore(PrintfAvailable,1,NULL);
  363. exit(1);
  364. }
  365. ReadContext->NameOfPort = argv[i+2];
  366. ReadContext->FileToUse = hFile;
  367. ReadContext->NumberOfChars = NumberOfChars;
  368. ReadContext->DoWrite = FALSE;
  369. if (!(ReadContext->Ol.hEvent = CreateEvent(
  370. NULL,
  371. FALSE,
  372. FALSE,
  373. NULL
  374. ))) {
  375. WaitForSingleObject(PrintfAvailable,-1);
  376. printf(
  377. "Couldn't create read overlapped event for %s\n",
  378. argv[i+2]
  379. );
  380. ReleaseSemaphore(PrintfAvailable,1,NULL);
  381. exit(1);
  382. } else {
  383. ReadContext->Ol.Internal = 0;
  384. ReadContext->Ol.InternalHigh = 0;
  385. ReadContext->Ol.Offset = 0;
  386. ReadContext->Ol.OffsetHigh = 0;
  387. }
  388. WriteContext->NameOfPort = argv[i+2];
  389. WriteContext->FileToUse = hFile;
  390. WriteContext->NumberOfChars = NumberOfChars;
  391. WriteContext->DoWrite = TRUE;
  392. if (!(WriteContext->Ol.hEvent = CreateEvent(
  393. NULL,
  394. FALSE,
  395. FALSE,
  396. NULL
  397. ))) {
  398. WaitForSingleObject(PrintfAvailable,-1);
  399. printf(
  400. "Couldn't create write overlapped event for %s\n",
  401. argv[i+2]
  402. );
  403. ReleaseSemaphore(PrintfAvailable,1,NULL);
  404. exit(1);
  405. } else {
  406. WriteContext->Ol.Internal = 0;
  407. WriteContext->Ol.InternalHigh = 0;
  408. WriteContext->Ol.Offset = 0;
  409. WriteContext->Ol.OffsetHigh = 0;
  410. }
  411. for (
  412. TotalCount = 0;
  413. TotalCount < NumberOfChars;
  414. ) {
  415. for (
  416. j = (0xff - 10);
  417. j != 0; // When it wraps around
  418. j++
  419. ) {
  420. WriteContext->BufferForOp[TotalCount] = (UCHAR)j;
  421. TotalCount++;
  422. if (TotalCount >= NumberOfChars) {
  423. break;
  424. }
  425. }
  426. }
  427. if (!CreateThread(
  428. NULL,
  429. 0,
  430. WorkThread,
  431. ReadContext,
  432. 0,
  433. &ThreadId
  434. )) {
  435. WaitForSingleObject(PrintfAvailable,-1);
  436. printf(
  437. "Couldn't create the read thread for %s\n",
  438. argv[i+2]
  439. );
  440. ReleaseSemaphore(PrintfAvailable,1,NULL);
  441. exit(1);
  442. }
  443. if (!CreateThread(
  444. NULL,
  445. 0,
  446. WorkThread,
  447. WriteContext,
  448. 0,
  449. &ThreadId
  450. )) {
  451. WaitForSingleObject(PrintfAvailable,-1);
  452. printf(
  453. "Couldn't create the write thread for %s\n",
  454. argv[i+2]
  455. );
  456. ReleaseSemaphore(PrintfAvailable,1,NULL);
  457. exit(1);
  458. }
  459. }
  460. //
  461. // Wait for all the threads to signal that they
  462. // are ready to work
  463. //
  464. for (
  465. i = 0;
  466. i < NumberOfPorts*2;
  467. i++
  468. ) {
  469. if (WaitForSingleObject(ReadyToWork,-1)) {
  470. WaitForSingleObject(PrintfAvailable,-1);
  471. printf(
  472. "Got an error waiting for threads to be ready to work: %d\n",i
  473. );
  474. ReleaseSemaphore(PrintfAvailable,1,NULL);
  475. exit(1);
  476. }
  477. }
  478. //
  479. // Tell them to start working.
  480. //
  481. SetEvent(StartOperationsEvent);
  482. //
  483. // Wait for all the threads to report that they
  484. // are done with their io an that they are ready to report.
  485. //
  486. for (
  487. i = 0;
  488. i < NumberOfPorts*2;
  489. i++
  490. ) {
  491. if (WaitForSingleObject(ReadyToReport,-1)) {
  492. WaitForSingleObject(PrintfAvailable,-1);
  493. printf(
  494. "Got an error waiting for threads to be ready to report.\n"
  495. );
  496. ReleaseSemaphore(PrintfAvailable,1,NULL);
  497. exit(1);
  498. }
  499. }
  500. //
  501. // Tell all the threads that its ok for them to report.
  502. //
  503. SetEvent(BeginReporting);
  504. //
  505. // Wait for all the thread to complete reporting. Then
  506. // we can finish.
  507. //
  508. for (
  509. i = 0;
  510. i < NumberOfPorts*2;
  511. i++
  512. ) {
  513. if (WaitForSingleObject(DoneReporting,-1)) {
  514. WaitForSingleObject(PrintfAvailable,-1);
  515. printf(
  516. "Got an error waiting for threads to be done reporting.\n"
  517. );
  518. ReleaseSemaphore(PrintfAvailable,1,NULL);
  519. exit(1);
  520. }
  521. }
  522. //
  523. // All gone.
  524. //
  525. exit(1);
  526. }