1 /*=========================================================================
3 Program: KWSys - Kitware System Library
4 Module: $RCSfile: testProcess.c,v $
6 Copyright (c) Kitware, Inc., Insight Consortium. All rights reserved.
7 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the above copyright notices for more information.
13 =========================================================================*/
14 #include "kwsysPrivate.h"
15 #include KWSYS_HEADER(Process.h)
17 /* Work-around CMake dependency scanning limitation. This must
18 duplicate the above list of headers. */
20 # include "Process.h.in"
33 #if defined(__BORLANDC__)
34 # pragma warn -8060 /* possibly incorrect assignment */
37 #if defined(__BEOS__) && !defined(__ZETA__)
38 /* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
39 # include <be/kernel/OS.h>
40 static inline void testProcess_usleep(unsigned int msec
)
45 # define testProcess_usleep usleep
48 int runChild(const char* cmd
[], int state
, int exception
, int value
,
49 int share
, int output
, int delay
, double timeout
, int poll
,
50 int repeat
, int disown
);
52 int test1(int argc
, const char* argv
[])
54 (void)argc
; (void)argv
;
55 fprintf(stdout
, "Output on stdout from test returning 0.\n");
56 fprintf(stderr
, "Output on stderr from test returning 0.\n");
60 int test2(int argc
, const char* argv
[])
62 (void)argc
; (void)argv
;
63 fprintf(stdout
, "Output on stdout from test returning 123.\n");
64 fprintf(stderr
, "Output on stderr from test returning 123.\n");
68 int test3(int argc
, const char* argv
[])
70 (void)argc
; (void)argv
;
71 fprintf(stdout
, "Output before sleep on stdout from timeout test.\n");
72 fprintf(stderr
, "Output before sleep on stderr from timeout test.\n");
80 fprintf(stdout
, "Output after sleep on stdout from timeout test.\n");
81 fprintf(stderr
, "Output after sleep on stderr from timeout test.\n");
85 int test4(int argc
, const char* argv
[])
88 /* Avoid error diagnostic popups since we are crashing on purpose. */
89 SetErrorMode(SEM_FAILCRITICALERRORS
| SEM_NOGPFAULTERRORBOX
);
90 #elif defined(__BEOS__)
91 /* Avoid error diagnostic popups since we are crashing on purpose. */
94 (void)argc
; (void)argv
;
95 fprintf(stdout
, "Output before crash on stdout from crash test.\n");
96 fprintf(stderr
, "Output before crash on stderr from crash test.\n");
100 fprintf(stdout
, "Output after crash on stdout from crash test.\n");
101 fprintf(stderr
, "Output after crash on stderr from crash test.\n");
105 int test5(int argc
, const char* argv
[])
114 fprintf(stdout
, "Output on stdout before recursive test.\n");
115 fprintf(stderr
, "Output on stderr before recursive test.\n");
118 r
= runChild(cmd
, kwsysProcess_State_Exception
,
119 kwsysProcess_Exception_Fault
, 1, 1, 1, 0, 15, 0, 1, 0);
120 fprintf(stdout
, "Output on stdout after recursive test.\n");
121 fprintf(stderr
, "Output on stderr after recursive test.\n");
127 #define TEST6_SIZE (4096*2)
128 void test6(int argc
, const char* argv
[])
131 char runaway
[TEST6_SIZE
+1];
132 (void)argc
; (void)argv
;
133 for(i
=0;i
< TEST6_SIZE
;++i
)
137 runaway
[TEST6_SIZE
] = '\n';
139 /* Generate huge amounts of output to test killing. */
142 fwrite(runaway
, 1, TEST6_SIZE
+1, stdout
);
147 /* Define MINPOLL to be one more than the number of times output is
148 written. Define MAXPOLL to be the largest number of times a loop
149 delaying 1/10th of a second should ever have to poll. */
152 int test7(int argc
, const char* argv
[])
154 (void)argc
; (void)argv
;
155 fprintf(stdout
, "Output on stdout before sleep.\n");
156 fprintf(stderr
, "Output on stderr before sleep.\n");
159 /* Sleep for 1 second. */
165 fprintf(stdout
, "Output on stdout after sleep.\n");
166 fprintf(stderr
, "Output on stderr after sleep.\n");
172 int test8(int argc
, const char* argv
[])
174 /* Create a disowned grandchild to test handling of processes
175 that exit before their children. */
183 fprintf(stdout
, "Output on stdout before grandchild test.\n");
184 fprintf(stderr
, "Output on stderr before grandchild test.\n");
187 r
= runChild(cmd
, kwsysProcess_State_Disowned
, kwsysProcess_Exception_None
,
188 1, 1, 1, 0, 10, 0, 1, 1);
189 fprintf(stdout
, "Output on stdout after grandchild test.\n");
190 fprintf(stderr
, "Output on stderr after grandchild test.\n");
196 int test8_grandchild(int argc
, const char* argv
[])
198 (void)argc
; (void)argv
;
199 fprintf(stdout
, "Output on stdout from grandchild before sleep.\n");
200 fprintf(stderr
, "Output on stderr from grandchild before sleep.\n");
203 /* TODO: Instead of closing pipes here leave them open to make sure
204 the grandparent can stop listening when the parent exits. This
205 part of the test cannot be enabled until the feature is
217 int runChild2(kwsysProcess
* kp
,
218 const char* cmd
[], int state
, int exception
, int value
,
219 int share
, int output
, int delay
, double timeout
,
220 int poll
, int disown
)
225 double userTimeout
= 0;
226 double* pUserTimeout
= 0;
227 kwsysProcess_SetCommand(kp
, cmd
);
230 kwsysProcess_SetTimeout(kp
, timeout
);
234 kwsysProcess_SetPipeShared(kp
, kwsysProcess_Pipe_STDOUT
, 1);
235 kwsysProcess_SetPipeShared(kp
, kwsysProcess_Pipe_STDERR
, 1);
239 kwsysProcess_SetOption(kp
, kwsysProcess_Option_Detach
, 1);
241 kwsysProcess_Execute(kp
);
245 pUserTimeout
= &userTimeout
;
248 if(!share
&& !disown
)
251 while((p
= kwsysProcess_WaitForData(kp
, &data
, &length
, pUserTimeout
)))
255 if(poll
&& p
== kwsysProcess_Pipe_Timeout
)
257 fprintf(stdout
, "WaitForData timeout reached.\n");
260 /* Count the number of times we polled without getting data.
261 If it is excessive then kill the child and fail. */
262 if(++poll
>= MAXPOLL
)
264 fprintf(stdout
, "Poll count reached limit %d.\n",
266 kwsysProcess_Kill(kp
);
271 fwrite(data
, 1, length
, stdout
);
277 /* Delay to avoid busy loop during polling. */
281 testProcess_usleep(100000);
286 /* Purposely sleeping only on Win32 to let pipe fill up. */
296 kwsysProcess_Disown(kp
);
300 kwsysProcess_WaitForExit(kp
, 0);
303 switch (kwsysProcess_GetState(kp
))
305 case kwsysProcess_State_Starting
:
306 printf("No process has been executed.\n"); break;
307 case kwsysProcess_State_Executing
:
308 printf("The process is still executing.\n"); break;
309 case kwsysProcess_State_Expired
:
310 printf("Child was killed when timeout expired.\n"); break;
311 case kwsysProcess_State_Exited
:
312 printf("Child exited with value = %d\n",
313 kwsysProcess_GetExitValue(kp
));
314 result
= ((exception
!= kwsysProcess_GetExitException(kp
)) ||
315 (value
!= kwsysProcess_GetExitValue(kp
))); break;
316 case kwsysProcess_State_Killed
:
317 printf("Child was killed by parent.\n"); break;
318 case kwsysProcess_State_Exception
:
319 printf("Child terminated abnormally: %s\n",
320 kwsysProcess_GetExceptionString(kp
));
321 result
= ((exception
!= kwsysProcess_GetExitException(kp
)) ||
322 (value
!= kwsysProcess_GetExitValue(kp
))); break;
323 case kwsysProcess_State_Disowned
:
324 printf("Child was disowned.\n"); break;
325 case kwsysProcess_State_Error
:
326 printf("Error in administrating child process: [%s]\n",
327 kwsysProcess_GetErrorString(kp
)); break;
332 if(exception
!= kwsysProcess_GetExitException(kp
))
334 fprintf(stderr
, "Mismatch in exit exception. "
335 "Should have been %d, was %d.\n",
336 exception
, kwsysProcess_GetExitException(kp
));
338 if(value
!= kwsysProcess_GetExitValue(kp
))
340 fprintf(stderr
, "Mismatch in exit value. "
341 "Should have been %d, was %d.\n",
342 value
, kwsysProcess_GetExitValue(kp
));
346 if(kwsysProcess_GetState(kp
) != state
)
348 fprintf(stderr
, "Mismatch in state. "
349 "Should have been %d, was %d.\n",
350 state
, kwsysProcess_GetState(kp
));
354 /* We should have polled more times than there were data if polling
356 if(poll
&& poll
< MINPOLL
)
358 fprintf(stderr
, "Poll count is %d, which is less than %d.\n",
366 int runChild(const char* cmd
[], int state
, int exception
, int value
,
367 int share
, int output
, int delay
, double timeout
,
368 int poll
, int repeat
, int disown
)
371 kwsysProcess
* kp
= kwsysProcess_New();
374 fprintf(stderr
, "kwsysProcess_New returned NULL!\n");
379 result
= runChild2(kp
, cmd
, state
, exception
, value
, share
,
380 output
, delay
, timeout
, poll
, disown
);
382 kwsysProcess_Delete(kp
);
386 int main(int argc
, const char* argv
[])
391 HANDLE out
= GetStdHandle(STD_OUTPUT_HANDLE
);
392 DuplicateHandle(GetCurrentProcess(), out
,
393 GetCurrentProcess(), &out
, 0, FALSE
,
394 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
395 SetStdHandle(STD_OUTPUT_HANDLE
, out
);
398 HANDLE out
= GetStdHandle(STD_ERROR_HANDLE
);
399 DuplicateHandle(GetCurrentProcess(), out
,
400 GetCurrentProcess(), &out
, 0, FALSE
,
401 DUPLICATE_SAME_ACCESS
| DUPLICATE_CLOSE_SOURCE
);
402 SetStdHandle(STD_ERROR_HANDLE
, out
);
409 else if(argc
== 3 && strcmp(argv
[1], "run") == 0)
413 /* Check arguments. */
414 if(((n
>= 1 && n
<= 8) || n
== 108) && argc
== 3)
416 /* This is the child process for a requested test number. */
419 case 1: return test1(argc
, argv
);
420 case 2: return test2(argc
, argv
);
421 case 3: return test3(argc
, argv
);
422 case 4: return test4(argc
, argv
);
423 case 5: return test5(argc
, argv
);
424 case 6: test6(argc
, argv
); return 0;
425 case 7: return test7(argc
, argv
);
426 case 8: return test8(argc
, argv
);
427 case 108: return test8_grandchild(argc
, argv
);
429 fprintf(stderr
, "Invalid test number %d.\n", n
);
432 else if(n
>= 1 && n
<= 8)
434 /* This is the parent process for a requested test number. */
437 kwsysProcess_State_Exited
,
438 kwsysProcess_State_Exited
,
439 kwsysProcess_State_Expired
,
440 kwsysProcess_State_Exception
,
441 kwsysProcess_State_Exited
,
442 kwsysProcess_State_Expired
,
443 kwsysProcess_State_Exited
,
444 kwsysProcess_State_Exited
448 kwsysProcess_Exception_None
,
449 kwsysProcess_Exception_None
,
450 kwsysProcess_Exception_None
,
451 kwsysProcess_Exception_Fault
,
452 kwsysProcess_Exception_None
,
453 kwsysProcess_Exception_None
,
454 kwsysProcess_Exception_None
,
455 kwsysProcess_Exception_None
457 int values
[8] = {0, 123, 1, 1, 0, 0, 0, 0};
458 int outputs
[8] = {1, 1, 1, 1, 1, 0, 1, 1};
459 int delays
[8] = {0, 0, 0, 0, 0, 1, 0, 0};
460 double timeouts
[8] = {10, 10, 10, 10, 30, 10, -1, 10};
461 int polls
[8] = {0, 0, 0, 0, 0, 0, 1, 0};
462 int repeat
[8] = {2, 1, 1, 1, 1, 1, 1, 1};
467 if(n
== 0 && (argv0
= strdup(argv
[0])))
469 /* Try converting to forward slashes to see if it works. */
471 for(c
=argv0
; *c
; ++c
)
490 fprintf(stdout
, "Output on stdout before test %d.\n", n
);
491 fprintf(stderr
, "Output on stderr before test %d.\n", n
);
494 r
= runChild(cmd
, states
[n
-1], exceptions
[n
-1], values
[n
-1], 0,
495 outputs
[n
-1], delays
[n
-1], timeouts
[n
-1],
496 polls
[n
-1], repeat
[n
-1], 0);
497 fprintf(stdout
, "Output on stdout after test %d.\n", n
);
498 fprintf(stderr
, "Output on stderr after test %d.\n", n
);
502 if(argv0
) { free(argv0
); }
506 else if(argc
> 2 && strcmp(argv
[1], "0") == 0)
508 /* This is the special debugging test to run a given command
510 const char** cmd
= argv
+2;
511 int state
= kwsysProcess_State_Exited
;
512 int exception
= kwsysProcess_Exception_None
;
515 int r
= runChild(cmd
, state
, exception
, value
, 0, 1, 0, timeout
, 0, 1, 0);
520 /* Improper usage. */
521 fprintf(stdout
, "Usage: %s <test number>\n", argv
[0]);