testProcess.c 23 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing#kwsys for details.  */
3
4
#include "kwsysPrivate.h"
#include KWSYS_HEADER(Process.h)
5
#include KWSYS_HEADER(Encoding.h)
6
7
8
9

/* Work-around CMake dependency scanning limitation.  This must
   duplicate the above list of headers.  */
#if 0
10
11
#  include "Encoding.h.in"
#  include "Process.h.in"
12
13
#endif

14
#include <assert.h>
15
#include <limits.h>
16
17
#include <stdio.h>
#include <stdlib.h>
18
#include <string.h>
19
20

#if defined(_WIN32)
21
#  include <windows.h>
22
#else
23
24
#  include <signal.h>
#  include <unistd.h>
25
26
#endif

27
#if defined(__BORLANDC__)
28
#  pragma warn - 8060 /* possibly incorrect assignment */
29
30
#endif

31
32
/* Platform-specific sleep functions. */

33
#if defined(__BEOS__) && !defined(__ZETA__)
34
/* BeOS 5 doesn't have usleep(), but it has snooze(), which is identical. */
35
#  include <be/kernel/OS.h>
36
37
38
39
40
41
42
static inline void testProcess_usleep(unsigned int usec)
{
  snooze(usec);
}
#elif defined(_WIN32)
/* Windows can only sleep in millisecond intervals. */
static void testProcess_usleep(unsigned int usec)
43
{
44
  Sleep(usec / 1000);
45
46
}
#else
47
#  define testProcess_usleep usleep
48
49
#endif

50
51
52
#if defined(_WIN32)
static void testProcess_sleep(unsigned int sec)
{
53
  Sleep(sec * 1000);
54
55
56
57
58
59
60
61
}
#else
static void testProcess_sleep(unsigned int sec)
{
  sleep(sec);
}
#endif

62
63
64
int runChild(const char* cmd[], int state, int exception, int value, int share,
             int output, int delay, double timeout, int poll, int repeat,
             int disown, int createNewGroup, unsigned int interruptDelay);
65

Sean McBride's avatar
Sean McBride committed
66
static int test1(int argc, const char* argv[])
67
{
68
69
70
71
72
73
74
75
76
77
  /* This is a very basic functional test of kwsysProcess.  It is repeated
     numerous times to verify that there are no resource leaks in kwsysProcess
     that eventually lead to an error.  Many versions of OS X will fail after
     256 leaked file handles, so 257 iterations seems to be a good test.  On
     the other hand, too many iterations will cause the test to time out -
     especially if the test is instrumented with e.g. valgrind.

     If you have problems with this test timing out on your system, or want to
     run more than 257 iterations, you can change the number of iterations by
     setting the KWSYS_TEST_PROCESS_1_COUNT environment variable.  */
78
79
  (void)argc;
  (void)argv;
80
81
82
83
84
  fprintf(stdout, "Output on stdout from test returning 0.\n");
  fprintf(stderr, "Output on stderr from test returning 0.\n");
  return 0;
}

Sean McBride's avatar
Sean McBride committed
85
static int test2(int argc, const char* argv[])
86
{
87
88
  (void)argc;
  (void)argv;
89
90
91
92
93
  fprintf(stdout, "Output on stdout from test returning 123.\n");
  fprintf(stderr, "Output on stderr from test returning 123.\n");
  return 123;
}

Sean McBride's avatar
Sean McBride committed
94
static int test3(int argc, const char* argv[])
95
{
96
97
  (void)argc;
  (void)argv;
98
99
100
101
  fprintf(stdout, "Output before sleep on stdout from timeout test.\n");
  fprintf(stderr, "Output before sleep on stderr from timeout test.\n");
  fflush(stdout);
  fflush(stderr);
102
  testProcess_sleep(15);
103
104
105
106
107
  fprintf(stdout, "Output after sleep on stdout from timeout test.\n");
  fprintf(stderr, "Output after sleep on stderr from timeout test.\n");
  return 0;
}

Sean McBride's avatar
Sean McBride committed
108
static int test4(int argc, const char* argv[])
109
{
Brad King's avatar
Brad King committed
110
#ifndef CRASH_USING_ABORT
111
112
113
114
115
116
  /* Prepare a pointer to an invalid address.  Don't use null, because
  dereferencing null is undefined behaviour and compilers are free to
  do whatever they want. ex: Clang will warn at compile time, or even
  optimize away the write. We hope to 'outsmart' them by using
  'volatile' and a slightly larger address, based on a runtime value. */
  volatile int* invalidAddress = 0;
117
  invalidAddress += argc ? 1 : 2;
Brad King's avatar
Brad King committed
118
#endif
119

120
121
122
#if defined(_WIN32)
  /* Avoid error diagnostic popups since we are crashing on purpose.  */
  SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
123
#elif defined(__BEOS__) || defined(__HAIKU__)
124
125
  /* Avoid error diagnostic popups since we are crashing on purpose.  */
  disable_debugger(1);
126
#endif
127
128
  (void)argc;
  (void)argv;
129
  fprintf(stdout, "Output before crash on stdout from crash test.\n");
130
  fprintf(stderr, "Output before crash on stderr from crash test.\n");
131
132
  fflush(stdout);
  fflush(stderr);
Brad King's avatar
Brad King committed
133
134
135
#ifdef CRASH_USING_ABORT
  abort();
#else
136
  assert(invalidAddress); /* Quiet Clang scan-build. */
137
138
  /* Provoke deliberate crash by writing to the invalid address. */
  *invalidAddress = 0;
Brad King's avatar
Brad King committed
139
#endif
140
141
142
143
144
  fprintf(stdout, "Output after crash on stdout from crash test.\n");
  fprintf(stderr, "Output after crash on stderr from crash test.\n");
  return 0;
}

Sean McBride's avatar
Sean McBride committed
145
static int test5(int argc, const char* argv[])
146
147
148
{
  int r;
  const char* cmd[4];
149
  (void)argc;
150
151
152
153
154
155
156
157
  cmd[0] = argv[0];
  cmd[1] = "run";
  cmd[2] = "4";
  cmd[3] = 0;
  fprintf(stdout, "Output on stdout before recursive test.\n");
  fprintf(stderr, "Output on stderr before recursive test.\n");
  fflush(stdout);
  fflush(stderr);
Brad King's avatar
Brad King committed
158
159
160
161
162
163
  r = runChild(cmd, kwsysProcess_State_Exception,
#ifdef CRASH_USING_ABORT
               kwsysProcess_Exception_Other,
#else
               kwsysProcess_Exception_Fault,
#endif
164
               1, 1, 1, 0, 15, 0, 1, 0, 0, 0);
165
166
167
168
169
170
171
  fprintf(stdout, "Output on stdout after recursive test.\n");
  fprintf(stderr, "Output on stderr after recursive test.\n");
  fflush(stdout);
  fflush(stderr);
  return r;
}

172
#define TEST6_SIZE (4096 * 2)
Sean McBride's avatar
Sean McBride committed
173
static void test6(int argc, const char* argv[])
174
175
{
  int i;
176
177
178
179
  char runaway[TEST6_SIZE + 1];
  (void)argc;
  (void)argv;
  for (i = 0; i < TEST6_SIZE; ++i) {
180
    runaway[i] = '.';
181
  }
182
183
184
  runaway[TEST6_SIZE] = '\n';

  /* Generate huge amounts of output to test killing.  */
185
186
  for (;;) {
    fwrite(runaway, 1, TEST6_SIZE + 1, stdout);
187
    fflush(stdout);
188
  }
189
190
}

191
192
193
194
195
/* Define MINPOLL to be one more than the number of times output is
   written.  Define MAXPOLL to be the largest number of times a loop
   delaying 1/10th of a second should ever have to poll.  */
#define MINPOLL 5
#define MAXPOLL 20
Sean McBride's avatar
Sean McBride committed
196
static int test7(int argc, const char* argv[])
197
{
198
199
  (void)argc;
  (void)argv;
200
201
202
203
204
  fprintf(stdout, "Output on stdout before sleep.\n");
  fprintf(stderr, "Output on stderr before sleep.\n");
  fflush(stdout);
  fflush(stderr);
  /* Sleep for 1 second.  */
205
  testProcess_sleep(1);
206
207
208
209
210
211
  fprintf(stdout, "Output on stdout after sleep.\n");
  fprintf(stderr, "Output on stderr after sleep.\n");
  fflush(stdout);
  fflush(stderr);
  return 0;
}
212

Sean McBride's avatar
Sean McBride committed
213
static int test8(int argc, const char* argv[])
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
{
  /* Create a disowned grandchild to test handling of processes
     that exit before their children.  */
  int r;
  const char* cmd[4];
  (void)argc;
  cmd[0] = argv[0];
  cmd[1] = "run";
  cmd[2] = "108";
  cmd[3] = 0;
  fprintf(stdout, "Output on stdout before grandchild test.\n");
  fprintf(stderr, "Output on stderr before grandchild test.\n");
  fflush(stdout);
  fflush(stderr);
  r = runChild(cmd, kwsysProcess_State_Disowned, kwsysProcess_Exception_None,
229
               1, 1, 1, 0, 10, 0, 1, 1, 0, 0);
230
231
232
233
234
235
236
  fprintf(stdout, "Output on stdout after grandchild test.\n");
  fprintf(stderr, "Output on stderr after grandchild test.\n");
  fflush(stdout);
  fflush(stderr);
  return r;
}

Sean McBride's avatar
Sean McBride committed
237
static int test8_grandchild(int argc, const char* argv[])
238
{
239
240
  (void)argc;
  (void)argv;
241
242
243
244
245
246
247
248
249
250
  fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
  fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
  fflush(stdout);
  fflush(stderr);
  /* TODO: Instead of closing pipes here leave them open to make sure
     the grandparent can stop listening when the parent exits.  This
     part of the test cannot be enabled until the feature is
     implemented.  */
  fclose(stdout);
  fclose(stderr);
251
  testProcess_sleep(15);
252
253
254
  return 0;
}

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
static int test9(int argc, const char* argv[])
{
  /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
     process.  Here, we start a child process that sleeps for a long time
     while ignoring signals.  The test is successful if this process waits
     for the child to return before exiting from the Ctrl+C handler.

     WARNING:  This test will falsely pass if the share parameter of runChild
     was set to 0 when invoking the test9 process.  */
  int r;
  const char* cmd[4];
  (void)argc;
  cmd[0] = argv[0];
  cmd[1] = "run";
  cmd[2] = "109";
  cmd[3] = 0;
  fprintf(stdout, "Output on stdout before grandchild test.\n");
  fprintf(stderr, "Output on stderr before grandchild test.\n");
  fflush(stdout);
  fflush(stderr);
275
276
  r = runChild(cmd, kwsysProcess_State_Exited, kwsysProcess_Exception_None, 0,
               1, 1, 0, 30, 0, 1, 0, 0, 0);
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
  /* This sleep will avoid a race condition between this function exiting
     normally and our Ctrl+C handler exiting abnormally after the process
     exits.  */
  testProcess_sleep(1);
  fprintf(stdout, "Output on stdout after grandchild test.\n");
  fprintf(stderr, "Output on stderr after grandchild test.\n");
  fflush(stdout);
  fflush(stderr);
  return r;
}

#if defined(_WIN32)
static BOOL WINAPI test9_grandchild_handler(DWORD dwCtrlType)
{
  /* Ignore all Ctrl+C/Break signals.  We must use an actual handler function
     instead of using SetConsoleCtrlHandler(NULL, TRUE) so that we can also
     ignore Ctrl+Break in addition to Ctrl+C.  */
  (void)dwCtrlType;
  return TRUE;
}
#endif

static int test9_grandchild(int argc, const char* argv[])
{
  /* The grandchild just sleeps for a few seconds while ignoring signals.  */
302
303
  (void)argc;
  (void)argv;
304
#if defined(_WIN32)
305
  if (!SetConsoleCtrlHandler(test9_grandchild_handler, TRUE)) {
306
    return 1;
307
  }
308
309
310
311
312
#else
  struct sigaction sa;
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = SIG_IGN;
  sigemptyset(&sa.sa_mask);
313
  if (sigaction(SIGINT, &sa, 0) < 0) {
314
    return 1;
315
  }
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#endif
  fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
  fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
  fflush(stdout);
  fflush(stderr);
  /* Sleep for 9 seconds.  */
  testProcess_sleep(9);
  fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
  fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
  fflush(stdout);
  fflush(stderr);
  return 0;
}

static int test10(int argc, const char* argv[])
{
  /* Test Ctrl+C behavior: the root test program will send a Ctrl+C to this
     process.  Here, we start a child process that sleeps for a long time and
     processes signals normally.  However, this grandchild is created in a new
     process group - ensuring that Ctrl+C we receive is sent to our process
     groups.  We make sure it exits anyway.  */
  int r;
  const char* cmd[4];
  (void)argc;
  cmd[0] = argv[0];
  cmd[1] = "run";
  cmd[2] = "110";
  cmd[3] = 0;
  fprintf(stdout, "Output on stdout before grandchild test.\n");
  fprintf(stderr, "Output on stderr before grandchild test.\n");
  fflush(stdout);
  fflush(stderr);
348
349
350
  r =
    runChild(cmd, kwsysProcess_State_Exception,
             kwsysProcess_Exception_Interrupt, 0, 1, 1, 0, 30, 0, 1, 0, 1, 0);
351
352
353
354
355
356
357
358
359
360
  fprintf(stdout, "Output on stdout after grandchild test.\n");
  fprintf(stderr, "Output on stderr after grandchild test.\n");
  fflush(stdout);
  fflush(stderr);
  return r;
}

static int test10_grandchild(int argc, const char* argv[])
{
  /* The grandchild just sleeps for a few seconds and handles signals.  */
361
362
  (void)argc;
  (void)argv;
363
364
365
366
367
368
369
370
371
372
373
374
375
  fprintf(stdout, "Output on stdout from grandchild before sleep.\n");
  fprintf(stderr, "Output on stderr from grandchild before sleep.\n");
  fflush(stdout);
  fflush(stderr);
  /* Sleep for 6 seconds.  */
  testProcess_sleep(6);
  fprintf(stdout, "Output on stdout from grandchild after sleep.\n");
  fprintf(stderr, "Output on stderr from grandchild after sleep.\n");
  fflush(stdout);
  fflush(stderr);
  return 0;
}

376
377
378
379
static int runChild2(kwsysProcess* kp, const char* cmd[], int state,
                     int exception, int value, int share, int output,
                     int delay, double timeout, int poll, int disown,
                     int createNewGroup, unsigned int interruptDelay)
380
381
382
383
{
  int result = 0;
  char* data = 0;
  int length = 0;
384
385
  double userTimeout = 0;
  double* pUserTimeout = 0;
386
  kwsysProcess_SetCommand(kp, cmd);
387
  if (timeout >= 0) {
388
    kwsysProcess_SetTimeout(kp, timeout);
389
390
  }
  if (share) {
391
392
    kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDOUT, 1);
    kwsysProcess_SetPipeShared(kp, kwsysProcess_Pipe_STDERR, 1);
393
394
  }
  if (disown) {
395
    kwsysProcess_SetOption(kp, kwsysProcess_Option_Detach, 1);
396
397
  }
  if (createNewGroup) {
398
    kwsysProcess_SetOption(kp, kwsysProcess_Option_CreateProcessGroup, 1);
399
  }
400
  kwsysProcess_Execute(kp);
401

402
  if (poll) {
403
    pUserTimeout = &userTimeout;
404
  }
405

406
  if (interruptDelay) {
407
408
    testProcess_sleep(interruptDelay);
    kwsysProcess_Interrupt(kp);
409
  }
410

411
  if (!share && !disown) {
412
    int p;
413
414
415
    while ((p = kwsysProcess_WaitForData(kp, &data, &length, pUserTimeout))) {
      if (output) {
        if (poll && p == kwsysProcess_Pipe_Timeout) {
416
417
418
419
420
          fprintf(stdout, "WaitForData timeout reached.\n");
          fflush(stdout);

          /* Count the number of times we polled without getting data.
             If it is excessive then kill the child and fail.  */
421
422
          if (++poll >= MAXPOLL) {
            fprintf(stdout, "Poll count reached limit %d.\n", MAXPOLL);
423
424
            kwsysProcess_Kill(kp);
          }
425
426
        } else {
          fwrite(data, 1, (size_t)length, stdout);
427
428
          fflush(stdout);
        }
429
430
      }
      if (poll) {
431
        /* Delay to avoid busy loop during polling.  */
432
        testProcess_usleep(100000);
433
434
435
      }
      if (delay) {
/* Purposely sleeping only on Win32 to let pipe fill up.  */
436
#if defined(_WIN32)
437
        testProcess_usleep(100000);
438
#endif
439
      }
440
    }
441
  }
442

443
  if (disown) {
444
    kwsysProcess_Disown(kp);
445
  } else {
446
    kwsysProcess_WaitForExit(kp, 0);
447
  }
448

449
  switch (kwsysProcess_GetState(kp)) {
450
    case kwsysProcess_State_Starting:
451
452
      printf("No process has been executed.\n");
      break;
453
    case kwsysProcess_State_Executing:
454
455
      printf("The process is still executing.\n");
      break;
456
    case kwsysProcess_State_Expired:
457
458
      printf("Child was killed when timeout expired.\n");
      break;
459
    case kwsysProcess_State_Exited:
460
      printf("Child exited with value = %d\n", kwsysProcess_GetExitValue(kp));
461
      result = ((exception != kwsysProcess_GetExitException(kp)) ||
462
463
                (value != kwsysProcess_GetExitValue(kp)));
      break;
464
    case kwsysProcess_State_Killed:
465
466
      printf("Child was killed by parent.\n");
      break;
467
    case kwsysProcess_State_Exception:
468
469
      printf("Child terminated abnormally: %s\n",
             kwsysProcess_GetExceptionString(kp));
470
      result = ((exception != kwsysProcess_GetExitException(kp)) ||
471
472
                (value != kwsysProcess_GetExitValue(kp)));
      break;
473
    case kwsysProcess_State_Disowned:
474
475
      printf("Child was disowned.\n");
      break;
476
477
    case kwsysProcess_State_Error:
      printf("Error in administrating child process: [%s]\n",
478
479
             kwsysProcess_GetErrorString(kp));
      break;
Sean McBride's avatar
Sean McBride committed
480
  }
481

482
483
  if (result) {
    if (exception != kwsysProcess_GetExitException(kp)) {
484
485
486
      fprintf(stderr,
              "Mismatch in exit exception.  "
              "Should have been %d, was %d.\n",
487
              exception, kwsysProcess_GetExitException(kp));
488
489
    }
    if (value != kwsysProcess_GetExitValue(kp)) {
490
491
492
      fprintf(stderr,
              "Mismatch in exit value.  "
              "Should have been %d, was %d.\n",
493
              value, kwsysProcess_GetExitValue(kp));
494
    }
495
  }
496

497
  if (kwsysProcess_GetState(kp) != state) {
498
499
500
    fprintf(stderr,
            "Mismatch in state.  "
            "Should have been %d, was %d.\n",
501
            state, kwsysProcess_GetState(kp));
502
    result = 1;
503
  }
504
505
506

  /* We should have polled more times than there were data if polling
     was enabled.  */
507
508
509
  if (poll && poll < MINPOLL) {
    fprintf(stderr, "Poll count is %d, which is less than %d.\n", poll,
            MINPOLL);
510
    result = 1;
511
  }
512
513
514
515

  return result;
}

516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
/**
 * Runs a child process and blocks until it returns.  Arguments as follows:
 *
 * cmd            = Command line to run.
 * state          = Expected return value of kwsysProcess_GetState after exit.
 * exception      = Expected return value of kwsysProcess_GetExitException.
 * value          = Expected return value of kwsysProcess_GetExitValue.
 * share          = Whether to share stdout/stderr child pipes with our pipes
 *                  by way of kwsysProcess_SetPipeShared.  If false, new pipes
 *                  are created.
 * output         = If !share && !disown, whether to write the child's stdout
 *                  and stderr output to our stdout.
 * delay          = If !share && !disown, adds an additional short delay to
 *                  the pipe loop to allow the pipes to fill up; Windows only.
 * timeout        = Non-zero to sets a timeout in seconds via
 *                  kwsysProcess_SetTimeout.
 * poll           = If !share && !disown, we count the number of 0.1 second
 *                  intervals where the child pipes had no new data.  We fail
 *                  if not in the bounds of MINPOLL/MAXPOLL.
 * repeat         = Number of times to run the process.
 * disown         = If set, the process is disowned.
 * createNewGroup = If set, the process is created in a new process group.
 * interruptDelay = If non-zero, number of seconds to delay before
 *                  interrupting the process.  Note that this delay will occur
 *                  BEFORE any reading/polling of pipes occurs and before any
 *                  detachment occurs.
 */
543
544
545
int runChild(const char* cmd[], int state, int exception, int value, int share,
             int output, int delay, double timeout, int poll, int repeat,
             int disown, int createNewGroup, unsigned int interruptDelay)
546
{
547
  int result = 1;
548
  kwsysProcess* kp = kwsysProcess_New();
549
  if (!kp) {
550
551
    fprintf(stderr, "kwsysProcess_New returned NULL!\n");
    return 1;
552
553
554
555
556
  }
  while (repeat-- > 0) {
    result = runChild2(kp, cmd, state, exception, value, share, output, delay,
                       timeout, poll, disown, createNewGroup, interruptDelay);
    if (result) {
557
      break;
558
    }
559
  }
560
561
562
563
564
565
566
  kwsysProcess_Delete(kp);
  return result;
}

int main(int argc, const char* argv[])
{
  int n = 0;
567
568
569
570
571

#ifdef _WIN32
  int i;
  char new_args[10][_MAX_PATH];
  LPWSTR* w_av = CommandLineToArgvW(GetCommandLineW(), &argc);
572
  for (i = 0; i < argc; i++) {
573
574
575
576
577
578
    kwsysEncoding_wcstombs(new_args[i], w_av[i], _MAX_PATH);
    argv[i] = new_args[i];
  }
  LocalFree(w_av);
#endif

579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
#if 0
    {
    HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
    DuplicateHandle(GetCurrentProcess(), out,
                    GetCurrentProcess(), &out, 0, FALSE,
                    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    SetStdHandle(STD_OUTPUT_HANDLE, out);
    }
    {
    HANDLE out = GetStdHandle(STD_ERROR_HANDLE);
    DuplicateHandle(GetCurrentProcess(), out,
                    GetCurrentProcess(), &out, 0, FALSE,
                    DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
    SetStdHandle(STD_ERROR_HANDLE, out);
    }
#endif
595
  if (argc == 2) {
596
    n = atoi(argv[1]);
597
  } else if (argc == 3 && strcmp(argv[1], "run") == 0) {
598
    n = atoi(argv[2]);
599
  }
600
  /* Check arguments.  */
601
  if (((n >= 1 && n <= 10) || n == 108 || n == 109 || n == 110) && argc == 3) {
602
    /* This is the child process for a requested test number.  */
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
    switch (n) {
      case 1:
        return test1(argc, argv);
      case 2:
        return test2(argc, argv);
      case 3:
        return test3(argc, argv);
      case 4:
        return test4(argc, argv);
      case 5:
        return test5(argc, argv);
      case 6:
        test6(argc, argv);
        return 0;
      case 7:
        return test7(argc, argv);
      case 8:
        return test8(argc, argv);
      case 9:
        return test9(argc, argv);
      case 10:
        return test10(argc, argv);
      case 108:
        return test8_grandchild(argc, argv);
      case 109:
        return test9_grandchild(argc, argv);
      case 110:
        return test10_grandchild(argc, argv);
    }
632
633
    fprintf(stderr, "Invalid test number %d.\n", n);
    return 1;
634
635
  }
  if (n >= 1 && n <= 10) {
636
    /* This is the parent process for a requested test number.  */
637
638
639
640
641
642
    int states[10] = {
      kwsysProcess_State_Exited,   kwsysProcess_State_Exited,
      kwsysProcess_State_Expired,  kwsysProcess_State_Exception,
      kwsysProcess_State_Exited,   kwsysProcess_State_Expired,
      kwsysProcess_State_Exited,   kwsysProcess_State_Exited,
      kwsysProcess_State_Expired,  /* Ctrl+C handler test */
643
      kwsysProcess_State_Exception /* Process group test */
644
    };
645
    int exceptions[10] = {
Brad King's avatar
Brad King committed
646
647
648
649
650
651
652
653
654
655
      kwsysProcess_Exception_None,  kwsysProcess_Exception_None,
      kwsysProcess_Exception_None,
#ifdef CRASH_USING_ABORT
      kwsysProcess_Exception_Other,
#else
      kwsysProcess_Exception_Fault,
#endif
      kwsysProcess_Exception_None,  kwsysProcess_Exception_None,
      kwsysProcess_Exception_None,  kwsysProcess_Exception_None,
      kwsysProcess_Exception_None,  kwsysProcess_Exception_Interrupt
656
    };
657
658
659
660
661
662
663
664
665
    int values[10] = { 0, 123, 1, 1, 0, 0, 0, 0, 1, 1 };
    int shares[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
    int outputs[10] = { 1, 1, 1, 1, 1, 0, 1, 1, 1, 1 };
    int delays[10] = { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 };
    double timeouts[10] = { 10, 10, 10, 30, 30, 10, -1, 10, 6, 4 };
    int polls[10] = { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 };
    int repeat[10] = { 257, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
    int createNewGroups[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 };
    unsigned int interruptDelays[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 2 };
666
    int r;
667
    const char* cmd[4];
668
669
#ifdef _WIN32
    char* argv0 = 0;
670
671
#endif
    char* test1IterationsStr = getenv("KWSYS_TEST_PROCESS_1_COUNT");
672
    if (test1IterationsStr) {
673
      long int test1Iterations = strtol(test1IterationsStr, 0, 10);
674
      if (test1Iterations > 10 && test1Iterations != LONG_MAX) {
675
676
        repeat[0] = (int)test1Iterations;
      }
677
    }
678
#ifdef _WIN32
679
    if (n == 0 && (argv0 = strdup(argv[0]))) {
680
681
      /* Try converting to forward slashes to see if it works.  */
      char* c;
682
683
      for (c = argv0; *c; ++c) {
        if (*c == '\\') {
684
685
686
          *c = '/';
        }
      }
687
688
      cmd[0] = argv0;
    } else {
689
      cmd[0] = argv[0];
690
    }
691
#else
692
    cmd[0] = argv[0];
693
#endif
694
695
696
    cmd[1] = "run";
    cmd[2] = argv[1];
    cmd[3] = 0;
697
698
699
700
    fprintf(stdout, "Output on stdout before test %d.\n", n);
    fprintf(stderr, "Output on stderr before test %d.\n", n);
    fflush(stdout);
    fflush(stderr);
701
702
703
704
    r = runChild(cmd, states[n - 1], exceptions[n - 1], values[n - 1],
                 shares[n - 1], outputs[n - 1], delays[n - 1], timeouts[n - 1],
                 polls[n - 1], repeat[n - 1], 0, createNewGroups[n - 1],
                 interruptDelays[n - 1]);
705
706
707
708
    fprintf(stdout, "Output on stdout after test %d.\n", n);
    fprintf(stderr, "Output on stderr after test %d.\n", n);
    fflush(stdout);
    fflush(stderr);
Sean McBride's avatar
Sean McBride committed
709
#if defined(_WIN32)
710
    free(argv0);
711
#endif
712
    return r;
713
714
  }
  if (argc > 2 && strcmp(argv[1], "0") == 0) {
715
716
    /* This is the special debugging test to run a given command
       line.  */
717
    const char** cmd = argv + 2;
718
719
720
721
    int state = kwsysProcess_State_Exited;
    int exception = kwsysProcess_Exception_None;
    int value = 0;
    double timeout = 0;
722
723
    int r =
      runChild(cmd, state, exception, value, 0, 1, 0, timeout, 0, 1, 0, 0, 0);
724
    return r;
725
  } else {
726
727
    /* Improper usage.  */
    fprintf(stdout, "Usage: %s <test number>\n", argv[0]);
728
    return 1;
729
  }
730
}