testProcess.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. /*=========================================================================
  2. Program: KWSys - Kitware System Library
  3. Module: $RCSfile$
  4. Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
  5. See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
  6. This software is distributed WITHOUT ANY WARRANTY; without even
  7. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  8. PURPOSE. See the above copyright notices for more information.
  9. =========================================================================*/
  10. #include "kwsysPrivate.h"
  11. #include KWSYS_HEADER(Process.h)
  12. /* Work-around CMake dependency scanning limitation. This must
  13. duplicate the above list of headers. */
  14. #if 0
  15. # include "Process.h.in"
  16. #endif
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #if defined(_WIN32)
  21. # include <windows.h>
  22. #else
  23. # include <unistd.h>
  24. #endif
  25. int runChild(const char* cmd[], int state, int exception, int value,
  26. int share, int output, int delay, double timeout, int poll,
  27. int repeat);
  28. int test1(int argc, const char* argv[])
  29. {
  30. (void)argc; (void)argv;
  31. fprintf(stdout, "Output on stdout from test returning 0.\n");
  32. fprintf(stderr, "Output on stderr from test returning 0.\n");
  33. return 0;
  34. }
  35. int test2(int argc, const char* argv[])
  36. {
  37. (void)argc; (void)argv;
  38. fprintf(stdout, "Output on stdout from test returning 123.\n");
  39. fprintf(stderr, "Output on stderr from test returning 123.\n");
  40. return 123;
  41. }
  42. int test3(int argc, const char* argv[])
  43. {
  44. (void)argc; (void)argv;
  45. fprintf(stdout, "Output before sleep on stdout from timeout test.\n");
  46. fprintf(stderr, "Output before sleep on stderr from timeout test.\n");
  47. fflush(stdout);
  48. fflush(stderr);
  49. #if defined(_WIN32)
  50. Sleep(15000);
  51. #else
  52. sleep(15);
  53. #endif
  54. fprintf(stdout, "Output after sleep on stdout from timeout test.\n");
  55. fprintf(stderr, "Output after sleep on stderr from timeout test.\n");
  56. return 0;
  57. }
  58. int test4(int argc, const char* argv[])
  59. {
  60. #if defined(_WIN32)
  61. /* Avoid error diagnostic popups since we are crashing on purpose. */
  62. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
  63. #endif
  64. (void)argc; (void)argv;
  65. fprintf(stdout, "Output before crash on stdout from crash test.\n");
  66. fprintf(stderr, "Output before crash on stderr from crash test.\n");
  67. fflush(stdout);
  68. fflush(stderr);
  69. *(int*)0 = 0;
  70. fprintf(stdout, "Output after crash on stdout from crash test.\n");
  71. fprintf(stderr, "Output after crash on stderr from crash test.\n");
  72. return 0;
  73. }
  74. /* Quick hack to test grandchild killing. */
  75. /*#define TEST5_GRANDCHILD_KILL*/
  76. #ifdef TEST5_GRANDCHILD_KILL
  77. # define TEST5_TIMEOUT 10
  78. #else
  79. # define TEST5_TIMEOUT 30
  80. #endif
  81. int test5(int argc, const char* argv[])
  82. {
  83. int r;
  84. const char* cmd[4];
  85. (void)argc;
  86. cmd[0] = argv[0];
  87. cmd[1] = "run";
  88. #ifdef TEST5_GRANDCHILD_KILL
  89. cmd[2] = "3";
  90. #else
  91. cmd[2] = "4";
  92. #endif
  93. cmd[3] = 0;
  94. fprintf(stdout, "Output on stdout before recursive test.\n");
  95. fprintf(stderr, "Output on stderr before recursive test.\n");
  96. fflush(stdout);
  97. fflush(stderr);
  98. r = runChild(cmd, kwsysProcess_State_Exception,
  99. kwsysProcess_Exception_Fault, 1, 1, 1, 0, 15, 0, 1);
  100. fprintf(stdout, "Output on stdout after recursive test.\n");
  101. fprintf(stderr, "Output on stderr after recursive test.\n");
  102. fflush(stdout);
  103. fflush(stderr);
  104. return r;
  105. }
  106. #define TEST6_SIZE (4096*2)
  107. void test6(int argc, const char* argv[])
  108. {
  109. int i;
  110. char runaway[TEST6_SIZE+1];
  111. (void)argc; (void)argv;
  112. for(i=0;i < TEST6_SIZE;++i)
  113. {
  114. runaway[i] = '.';
  115. }
  116. runaway[TEST6_SIZE] = '\n';
  117. /* Generate huge amounts of output to test killing. */
  118. for(;;)
  119. {
  120. fwrite(runaway, 1, TEST6_SIZE+1, stdout);
  121. fflush(stdout);
  122. }
  123. }
  124. /* Define MINPOLL to be one more than the number of times output is
  125. written. Define MAXPOLL to be the largest number of times a loop
  126. delaying 1/10th of a second should ever have to poll. */
  127. #define MINPOLL 5
  128. #define MAXPOLL 20
  129. int test7(int argc, const char* argv[])
  130. {
  131. (void)argc; (void)argv;
  132. fprintf(stdout, "Output on stdout before sleep.\n");
  133. fprintf(stderr, "Output on stderr before sleep.\n");
  134. fflush(stdout);
  135. fflush(stderr);
  136. /* Sleep for 1 second. */
  137. #if defined(_WIN32)
  138. Sleep(1000);
  139. #else
  140. sleep(1);
  141. #endif
  142. fprintf(stdout, "Output on stdout after sleep.\n");
  143. fprintf(stderr, "Output on stderr after sleep.\n");
  144. fflush(stdout);
  145. fflush(stderr);
  146. return 0;
  147. }
  148. int runChild2(kwsysProcess* kp,
  149. const char* cmd[], int state, int exception, int value,
  150. int share, int output, int delay, double timeout,
  151. int poll)
  152. {
  153. int result = 0;
  154. char* data = 0;
  155. int length = 0;
  156. double userTimeout = 0;
  157. double* pUserTimeout = 0;
  158. kwsysProcess_SetCommand(kp, cmd);
  159. if(timeout >= 0)
  160. {
  161. kwsysProcess_SetTimeout(kp, timeout);
  162. }
  163. if(share)
  164. {
  165. kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1);
  166. kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1);
  167. }
  168. kwsysProcess_Execute(kp);
  169. if(poll)
  170. {
  171. pUserTimeout = &userTimeout;
  172. }
  173. if(!share)
  174. {
  175. int p;
  176. while((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout)))
  177. {
  178. if(output)
  179. {
  180. if(poll && p == kwsysProcess_Pipe_Timeout)
  181. {
  182. fprintf(stdout, "WaitForData timeout reached.\n");
  183. fflush(stdout);
  184. /* Count the number of times we polled without getting data.
  185. If it is excessive then kill the child and fail. */
  186. if(++poll >= MAXPOLL)
  187. {
  188. fprintf(stdout, "Poll count reached limit %d.\n",
  189. MAXPOLL);
  190. kwsysProcess_Kill(kp);
  191. }
  192. }
  193. else
  194. {
  195. fwrite(data, 1, length, stdout);
  196. fflush(stdout);
  197. }
  198. }
  199. if(poll)
  200. {
  201. /* Delay to avoid busy loop during polling. */
  202. #if defined(_WIN32)
  203. Sleep(100);
  204. #else
  205. usleep(100000);
  206. #endif
  207. }
  208. if(delay)
  209. {
  210. /* Purposely sleeping only on Win32 to let pipe fill up. */
  211. #if defined(_WIN32)
  212. Sleep(100);
  213. #endif
  214. }
  215. }
  216. }
  217. kwsysProcess_WaitForExit(kp, 0);
  218. switch (kwsysProcess_GetState(kp))
  219. {
  220. case kwsysProcess_State_Starting:
  221. printf("No process has been executed.\n"); break;
  222. case kwsysProcess_State_Executing:
  223. printf("The process is still executing.\n"); break;
  224. case kwsysProcess_State_Expired:
  225. printf("Child was killed when timeout expired.\n"); break;
  226. case kwsysProcess_State_Exited:
  227. printf("Child exited with value = %d\n",
  228. kwsysProcess_GetExitValue(kp));
  229. result = ((exception != kwsysProcess_GetExitException(kp)) ||
  230. (value != kwsysProcess_GetExitValue(kp))); break;
  231. case kwsysProcess_State_Killed:
  232. printf("Child was killed by parent.\n"); break;
  233. case kwsysProcess_State_Exception:
  234. printf("Child terminated abnormally: %s\n",
  235. kwsysProcess_GetExceptionString(kp));
  236. result = ((exception != kwsysProcess_GetExitException(kp)) ||
  237. (value != kwsysProcess_GetExitValue(kp))); break;
  238. case kwsysProcess_State_Error:
  239. printf("Error in administrating child process: [%s]\n",
  240. kwsysProcess_GetErrorString(kp)); break;
  241. };
  242. if(result)
  243. {
  244. if(exception != kwsysProcess_GetExitException(kp))
  245. {
  246. fprintf(stderr, "Mismatch in exit exception. "
  247. "Should have been %d, was %d.\n",
  248. exception, kwsysProcess_GetExitException(kp));
  249. }
  250. if(value != kwsysProcess_GetExitValue(kp))
  251. {
  252. fprintf(stderr, "Mismatch in exit value. "
  253. "Should have been %d, was %d.\n",
  254. value, kwsysProcess_GetExitValue(kp));
  255. }
  256. }
  257. if(kwsysProcess_GetState(kp) != state)
  258. {
  259. fprintf(stderr, "Mismatch in state. "
  260. "Should have been %d, was %d.\n",
  261. state, kwsysProcess_GetState(kp));
  262. result = 1;
  263. }
  264. /* We should have polled more times than there were data if polling
  265. was enabled. */
  266. if(poll && poll < MINPOLL)
  267. {
  268. fprintf(stderr, "Poll count is %d, which is less than %d.\n",
  269. poll, MINPOLL);
  270. result = 1;
  271. }
  272. return result;
  273. }
  274. int runChild(const char* cmd[], int state, int exception, int value,
  275. int share, int output, int delay, double timeout,
  276. int poll, int repeat)
  277. {
  278. int result = 1;
  279. kwsysProcess* kp = kwsysProcess_New();
  280. if(!kp)
  281. {
  282. fprintf(stderr, "kwsysProcess_New returned NULL!\n");
  283. return 1;
  284. }
  285. while(repeat-- > 0)
  286. {
  287. result = runChild2(kp, cmd, state, exception, value, share,
  288. output, delay, timeout, poll);
  289. }
  290. kwsysProcess_Delete(kp);
  291. return result;
  292. }
  293. int main(int argc, const char* argv[])
  294. {
  295. int n = 0;
  296. #if 0
  297. {
  298. HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
  299. DuplicateHandle(GetCurrentProcess(), out,
  300. GetCurrentProcess(), &out, 0, FALSE,
  301. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  302. SetStdHandle(STD_OUTPUT_HANDLE, out);
  303. }
  304. {
  305. HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
  306. DuplicateHandle(GetCurrentProcess(), out,
  307. GetCurrentProcess(), &out, 0, FALSE,
  308. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  309. SetStdHandle(STD_ERROR_HANDLE, out);
  310. }
  311. #endif
  312. if(argc == 2)
  313. {
  314. n = atoi(argv[1]);
  315. }
  316. else if(argc == 3 && strcmp(argv[1], "run") == 0)
  317. {
  318. n = atoi(argv[2]);
  319. }
  320. /* Check arguments. */
  321. if(n >= 1 && n <= 7 && argc == 3)
  322. {
  323. /* This is the child process for a requested test number. */
  324. switch (n)
  325. {
  326. case 1: return test1(argc, argv);
  327. case 2: return test2(argc, argv);
  328. case 3: return test3(argc, argv);
  329. case 4: return test4(argc, argv);
  330. case 5: return test5(argc, argv);
  331. case 6: test6(argc, argv); return 0;
  332. case 7: return test7(argc, argv);
  333. }
  334. fprintf(stderr, "Invalid test number %d.\n", n);
  335. return 1;
  336. }
  337. else if(n >= 1 && n <= 7)
  338. {
  339. /* This is the parent process for a requested test number. */
  340. int states[7] =
  341. {
  342. kwsysProcess_State_Exited,
  343. kwsysProcess_State_Exited,
  344. kwsysProcess_State_Expired,
  345. kwsysProcess_State_Exception,
  346. kwsysProcess_State_Exited,
  347. kwsysProcess_State_Expired,
  348. kwsysProcess_State_Exited
  349. };
  350. int exceptions[7] =
  351. {
  352. kwsysProcess_Exception_None,
  353. kwsysProcess_Exception_None,
  354. kwsysProcess_Exception_None,
  355. kwsysProcess_Exception_Fault,
  356. kwsysProcess_Exception_None,
  357. kwsysProcess_Exception_None,
  358. kwsysProcess_Exception_None
  359. };
  360. int values[7] = {0, 123, 1, 1, 0, 0, 0};
  361. int outputs[7] = {1, 1, 1, 1, 1, 0, 1};
  362. int delays[7] = {0, 0, 0, 0, 0, 1, 0};
  363. double timeouts[7] = {10, 10, 10, 10, TEST5_TIMEOUT, 10, -1};
  364. int polls[7] = {0, 0, 0, 0, 0, 0, 1};
  365. int repeat[7] = {2, 1, 1, 1, 1, 1, 1};
  366. int r;
  367. const char* cmd[4];
  368. #ifdef _WIN32
  369. char* argv0 = 0;
  370. if(n == 0 && (argv0 = strdup(argv[0])))
  371. {
  372. /* Try converting to forward slashes to see if it works. */
  373. char* c;
  374. for(c=argv0; *c; ++c)
  375. {
  376. if(*c == '\\')
  377. {
  378. *c = '/';
  379. }
  380. }
  381. cmd[0] = argv0;
  382. }
  383. else
  384. {
  385. cmd[0] = argv[0];
  386. }
  387. #else
  388. cmd[0] = argv[0];
  389. #endif
  390. cmd[1] = "run";
  391. cmd[2] = argv[1];
  392. cmd[3] = 0;
  393. fprintf(stdout, "Output on stdout before test %d.\n", n);
  394. fprintf(stderr, "Output on stderr before test %d.\n", n);
  395. fflush(stdout);
  396. fflush(stderr);
  397. r = runChild(cmd, states[n-1], exceptions[n-1], values[n-1], 0,
  398. outputs[n-1], delays[n-1], timeouts[n-1],
  399. polls[n-1], repeat[n-1]);
  400. fprintf(stdout, "Output on stdout after test %d.\n", n);
  401. fprintf(stderr, "Output on stderr after test %d.\n", n);
  402. fflush(stdout);
  403. fflush(stderr);
  404. #if _WIN32
  405. if(argv0) { free(argv0); }
  406. #endif
  407. return r;
  408. }
  409. else if(argc > 2 && strcmp(argv[1], "0") == 0)
  410. {
  411. /* This is the special debugging test to run a given command
  412. line. */
  413. const char** cmd = argv+2;
  414. int state = kwsysProcess_State_Exited;
  415. int exception = kwsysProcess_Exception_None;
  416. int value = 0;
  417. double timeout = 0;
  418. int r = runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1);
  419. return r;
  420. }
  421. else
  422. {
  423. /* Improper usage. */
  424. fprintf(stdout, "Usage: %s <test number>\n", argv[0]);
  425. return 1;
  426. }
  427. }