1 /* Main worker function for the test driver.
2 Copyright (C) 1998-2019 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <support/test-driver.h>
20 #include <support/check.h>
21 #include <support/temp_file-internal.h>
31 #include <sys/param.h>
32 #include <sys/resource.h>
34 #include <sys/types.h>
39 static const struct option default_options
[] =
45 /* Show people how to run the program. */
47 usage (const struct option
*options
)
51 printf ("Usage: %s [options]\n"
53 "Environment Variables:\n"
54 " TIMEOUTFACTOR An integer used to scale the timeout\n"
55 " TMPDIR Where to place temporary files\n"
56 " TEST_COREDUMPS Do not disable coredumps if set\n"
58 program_invocation_short_name
);
59 printf ("Options:\n");
60 for (i
= 0; options
[i
].name
; ++i
)
64 indent
= printf (" --%s", options
[i
].name
);
65 if (options
[i
].has_arg
== required_argument
)
66 indent
+= printf (" <arg>");
67 printf ("%*s", 25 - indent
, "");
68 switch (options
[i
].val
)
71 printf ("Increase the output verbosity");
74 printf ("Run the test directly (instead of forking & monitoring)");
77 printf ("Override the TMPDIR env var");
84 /* The PID of the test process. */
85 static pid_t test_pid
;
87 /* The cleanup handler passed to test_main. */
88 static void (*cleanup_function
) (void);
91 print_timestamp (const char *what
, struct timeval tv
)
94 if (gmtime_r (&tv
.tv_sec
, &tm
) == NULL
)
95 printf ("%s: %lld.%06d\n",
96 what
, (long long int) tv
.tv_sec
, (int) tv
.tv_usec
);
98 printf ("%s: %04d-%02d-%02dT%02d:%02d:%02d.%06d\n",
99 what
, 1900 + tm
.tm_year
, tm
.tm_mon
+ 1, tm
.tm_mday
,
100 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
, (int) tv
.tv_usec
);
103 /* Timeout handler. We kill the child and exit with an error. */
105 __attribute__ ((noreturn
))
106 signal_handler (int sig
)
111 /* Do this first to avoid further interference from the
114 bool now_available
= gettimeofday (&now
, NULL
) == 0;
116 bool st_available
= fstat64 (STDOUT_FILENO
, &st
) == 0 && st
.st_mtime
!= 0;
118 assert (test_pid
> 1);
119 /* Kill the whole process group. */
120 kill (-test_pid
, SIGKILL
);
121 /* In case setpgid failed in the child, kill it individually too. */
122 kill (test_pid
, SIGKILL
);
124 /* Wait for it to terminate. */
126 for (i
= 0; i
< 5; ++i
)
128 killed
= waitpid (test_pid
, &status
, WNOHANG
|WUNTRACED
);
132 /* Delay, give the system time to process the kill. If the
133 nanosleep() call return prematurely, all the better. We
134 won't restart it since this probably means the child process
138 ts
.tv_nsec
= 100000000;
139 nanosleep (&ts
, NULL
);
141 if (killed
!= 0 && killed
!= test_pid
)
143 printf ("Failed to kill test process: %m\n");
147 if (cleanup_function
!= NULL
)
152 signal (sig
, SIG_DFL
);
156 if (killed
== 0 || (WIFSIGNALED (status
) && WTERMSIG (status
) == SIGKILL
))
157 puts ("Timed out: killed the child process");
158 else if (WIFSTOPPED (status
))
159 printf ("Timed out: the child process was %s\n",
160 strsignal (WSTOPSIG (status
)));
161 else if (WIFSIGNALED (status
))
162 printf ("Timed out: the child process got signal %s\n",
163 strsignal (WTERMSIG (status
)));
165 printf ("Timed out: killed the child process but it exited %d\n",
166 WEXITSTATUS (status
));
169 print_timestamp ("Termination time", now
);
171 print_timestamp ("Last write to standard output",
172 (struct timeval
) { st
.st_mtim
.tv_sec
,
173 st
.st_mtim
.tv_nsec
/ 1000 });
175 /* Exit with an error. */
179 /* Run test_function or test_function_argv. */
181 run_test_function (int argc
, char **argv
, const struct test_config
*config
)
183 if (config
->test_function
!= NULL
)
184 return config
->test_function ();
185 else if (config
->test_function_argv
!= NULL
)
186 return config
->test_function_argv (argc
, argv
);
189 printf ("error: no test function defined\n");
194 static bool test_main_called
;
196 const char *test_dir
= NULL
;
197 unsigned int test_verbose
= 0;
199 /* If test failure reporting has been linked in, it may contribute
200 additional test failures. */
202 adjust_exit_status (int status
)
204 if (support_report_failure
!= NULL
)
205 return support_report_failure (status
);
210 support_test_main (int argc
, char **argv
, const struct test_config
*config
)
212 if (test_main_called
)
214 printf ("error: test_main called for a second time\n");
217 test_main_called
= true;
218 const struct option
*options
;
219 if (config
->options
!= NULL
)
220 options
= config
->options
;
222 options
= default_options
;
224 cleanup_function
= config
->cleanup_function
;
226 int direct
= 0; /* Directly call the test function? */
229 unsigned int timeoutfactor
= 1;
232 if (!config
->no_mallopt
)
234 /* Make uses of freed and uninitialized memory known. Do not
235 pull in a definition for mallopt if it has not been defined
237 extern __typeof__ (mallopt
) mallopt
__attribute__ ((weak
));
239 mallopt (M_PERTURB
, 42);
242 while ((opt
= getopt_long (argc
, argv
, config
->optstring
, options
, NULL
))
259 if (config
->cmdline_function
!= NULL
)
260 config
->cmdline_function (opt
);
263 /* If set, read the test TIMEOUTFACTOR value from the environment.
264 This value is used to scale the default test timeout values. */
265 char *envstr_timeoutfactor
= getenv ("TIMEOUTFACTOR");
266 if (envstr_timeoutfactor
!= NULL
)
268 char *envstr_conv
= envstr_timeoutfactor
;
269 unsigned long int env_fact
;
271 env_fact
= strtoul (envstr_timeoutfactor
, &envstr_conv
, 0);
272 if (*envstr_conv
== '\0' && envstr_conv
!= envstr_timeoutfactor
)
273 timeoutfactor
= MAX (env_fact
, 1);
276 /* Set TMPDIR to specified test directory. */
277 if (test_dir
!= NULL
)
279 setenv ("TMPDIR", test_dir
, 1);
281 if (chdir (test_dir
) < 0)
283 printf ("chdir: %m\n");
289 test_dir
= getenv ("TMPDIR");
290 if (test_dir
== NULL
|| test_dir
[0] == '\0')
293 if (support_set_test_dir
!= NULL
)
294 support_set_test_dir (test_dir
);
296 int timeout
= config
->timeout
;
298 timeout
= DEFAULT_TIMEOUT
;
300 /* Make sure we see all message, even those on stdout. */
301 if (!config
->no_setvbuf
)
302 setvbuf (stdout
, NULL
, _IONBF
, 0);
304 /* Make sure temporary files are deleted. */
305 if (support_delete_temp_files
!= NULL
)
306 atexit (support_delete_temp_files
);
308 /* Correct for the possible parameters. */
309 argv
[optind
- 1] = argv
[0];
313 /* Call the initializing function, if one is available. */
314 if (config
->prepare_function
!= NULL
)
315 config
->prepare_function (argc
, argv
);
317 const char *envstr_direct
= getenv ("TEST_DIRECT");
318 if (envstr_direct
!= NULL
)
320 FILE *f
= fopen (envstr_direct
, "w");
323 printf ("cannot open TEST_DIRECT output file '%s': %m\n",
328 fprintf (f
, "timeout=%u\ntimeoutfactor=%u\n",
329 config
->timeout
, timeoutfactor
);
330 if (config
->expected_status
!= 0)
331 fprintf (f
, "exit=%u\n", config
->expected_status
);
332 if (config
->expected_signal
!= 0)
333 fprintf (f
, "signal=%s\n", strsignal (config
->expected_signal
));
335 if (support_print_temp_files
!= NULL
)
336 support_print_temp_files (f
);
342 bool disable_coredumps
;
344 const char *coredumps
= getenv ("TEST_COREDUMPS");
345 disable_coredumps
= coredumps
== NULL
|| coredumps
[0] == '\0';
348 /* If we are not expected to fork run the function immediately. */
350 return adjust_exit_status (run_test_function (argc
, argv
, config
));
352 /* Set up the test environment:
355 - fork and execute the function. */
360 /* This is the child. */
361 if (disable_coredumps
)
363 /* Try to avoid dumping core. This is necessary because we
364 run the test from the source tree, and the coredumps
365 would end up there (and not in the build tree). */
366 struct rlimit core_limit
;
367 core_limit
.rlim_cur
= 0;
368 core_limit
.rlim_max
= 0;
369 setrlimit (RLIMIT_CORE
, &core_limit
);
372 /* We put the test process in its own pgrp so that if it bogusly
373 generates any job control signals, they won't hit the whole build. */
374 if (setpgid (0, 0) != 0)
375 printf ("Failed to set the process group ID: %m\n");
377 /* Execute the test function and exit with the return value. */
378 exit (run_test_function (argc
, argv
, config
));
380 else if (test_pid
< 0)
382 printf ("Cannot fork test program: %m\n");
387 signal (SIGALRM
, signal_handler
);
388 alarm (timeout
* timeoutfactor
);
390 /* Make sure we clean up if the wrapper gets interrupted. */
391 signal (SIGINT
, signal_handler
);
393 /* Wait for the regular termination. */
394 termpid
= TEMP_FAILURE_RETRY (waitpid (test_pid
, &status
, 0));
397 printf ("Waiting for test program failed: %m\n");
400 if (termpid
!= test_pid
)
402 printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
403 (long int) test_pid
, (long int) termpid
);
407 /* Process terminated normaly without timeout etc. */
408 if (WIFEXITED (status
))
410 if (config
->expected_status
== 0)
412 if (config
->expected_signal
== 0)
413 /* Exit with the return value of the test. */
414 return adjust_exit_status (WEXITSTATUS (status
));
417 printf ("Expected signal '%s' from child, got none\n",
418 strsignal (config
->expected_signal
));
424 /* Non-zero exit status is expected */
425 if (WEXITSTATUS (status
) != config
->expected_status
)
427 printf ("Expected status %d, got %d\n",
428 config
->expected_status
, WEXITSTATUS (status
));
432 return adjust_exit_status (0);
434 /* Process was killed by timer or other signal. */
437 if (config
->expected_signal
== 0)
439 printf ("Didn't expect signal from child: got `%s'\n",
440 strsignal (WTERMSIG (status
)));
443 else if (WTERMSIG (status
) != config
->expected_signal
)
445 printf ("Incorrect signal from child: got `%s', need `%s'\n",
446 strsignal (WTERMSIG (status
)),
447 strsignal (config
->expected_signal
));
451 return adjust_exit_status (0);