(timeout_handler): If waitpid returned 0, retry a couple of times. If
[kopensolaris-gnu/glibc.git] / test-skeleton.c
1 /* Skeleton for test programs.
2    Copyright (C) 1998, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, write to the Free
18    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19    02111-1307 USA.  */
20
21 #include <errno.h>
22 #include <getopt.h>
23 #include <search.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/resource.h>
30 #include <sys/wait.h>
31 #include <sys/param.h>
32
33 /* The test function is normally called `do_test' and it is called
34    with argc and argv as the arguments.  We nevertheless provide the
35    possibility to overwrite this name.  */
36 #ifndef TEST_FUNCTION
37 # define TEST_FUNCTION do_test (argc, argv)
38 #endif
39
40 #ifndef TEST_DATA_LIMIT
41 # define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with.  */
42 #endif
43
44 #define OPT_DIRECT 1000
45 #define OPT_TESTDIR 1001
46
47 static struct option options[] =
48 {
49 #ifdef CMDLINE_OPTIONS
50   CMDLINE_OPTIONS
51 #endif
52   { "direct", no_argument, NULL, OPT_DIRECT },
53   { "test-dir", required_argument, NULL, OPT_TESTDIR },
54   { NULL, 0, NULL, 0 }
55 };
56
57 /* PID of the test itself.  */
58 static pid_t pid;
59
60 /* Directory to place temporary files in.  */
61 static const char *test_dir;
62
63 /* List of temporary files.  */
64 struct temp_name_list
65 {
66   struct qelem q;
67   const char *name;
68 } *temp_name_list;
69
70 /* Add temporary files in list.  */
71 static void
72 __attribute__ ((unused))
73 add_temp_file (const char *name)
74 {
75   struct temp_name_list *newp
76     = (struct temp_name_list *) calloc (sizeof (*newp), 1);
77   if (newp != NULL)
78     {
79       newp->name = name;
80       if (temp_name_list == NULL)
81         temp_name_list = (struct temp_name_list *) &newp->q;
82       else
83         insque (newp, temp_name_list);
84     }
85 }
86
87 /* Delete all temporary files.  */
88 static void
89 delete_temp_files (void)
90 {
91   while (temp_name_list != NULL)
92     {
93       remove (temp_name_list->name);
94       temp_name_list = (struct temp_name_list *) temp_name_list->q.q_forw;
95     }
96 }
97
98 /* Create a temporary file.  */
99 static int
100 __attribute__ ((unused))
101 create_temp_file (const char *base, char **filename)
102 {
103   char *fname;
104   int fd;
105
106   fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base)
107                            + sizeof ("XXXXXX"));
108   if (fname == NULL)
109     {
110       puts ("out of memory");
111       return -1;
112     }
113   strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
114
115   fd = mkstemp (fname);
116   if (fd == -1)
117     {
118       printf ("cannot open temporary file '%s': %m\n", fname);
119       free (fname);
120       return -1;
121     }
122
123   add_temp_file (fname);
124   if (filename != NULL)
125     *filename = fname;
126
127   return fd;
128 }
129
130 /* Timeout handler.  We kill the child and exit with an error.  */
131 static void
132 __attribute__ ((noreturn))
133 timeout_handler (int sig __attribute__ ((unused)))
134 {
135   int killed;
136   int status;
137
138   /* Send signal.  */
139   kill (pid, SIGKILL);
140
141   /* Wait for it to terminate.  */
142   int i;
143   for (i = 0; i < 5; ++i)
144     {
145       killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
146       if (killed != 0)
147         break;
148
149       /* Delay, give the system time to process the kill.  If the
150          nanosleep() call return prematurely, all the better.  We
151          won't restart it since this probably means the child process
152          finally died.  */
153       struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
154       nanosleep (&ts, NULL);
155     }
156   if (killed != 0 && killed != pid)
157     {
158       perror ("Failed to killed test process");
159       exit (1);
160     }
161
162 #ifdef CLEANUP_HANDLER
163   CLEANUP_HANDLER;
164 #endif
165
166   /* If we expected this signal: good!  */
167 #ifdef EXPECTED_SIGNAL
168   if (EXPECTED_SIGNAL == SIGALRM)
169     exit (0);
170 #endif
171
172   if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL))
173     fputs ("Timed out: killed the child process\n", stderr);
174   else if (WIFSTOPPED (status))
175     fprintf (stderr, "Timed out: the child process was %s\n",
176              strsignal (WSTOPSIG (status)));
177   else if (WIFSIGNALED (status))
178     fprintf (stderr, "Timed out: the child process got signal %s\n",
179              strsignal (WTERMSIG (status)));
180   else
181     fprintf (stderr, "Timed out: killed the child process but it exited %d\n",
182              WEXITSTATUS (status));
183
184   /* Exit with an error.  */
185   exit (1);
186 }
187
188 /* We provide the entry point here.  */
189 int
190 main (int argc, char *argv[])
191 {
192   int direct = 0;       /* Directly call the test function?  */
193   int status;
194   int opt;
195   pid_t termpid;
196
197 #ifdef STDOUT_UNBUFFERED
198   setbuf (stdout, NULL);
199 #endif
200
201   while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
202     switch (opt)
203       {
204       case '?':
205         exit (1);
206       case OPT_DIRECT:
207         direct = 1;
208         break;
209       case OPT_TESTDIR:
210         test_dir = optarg;
211         break;
212 #ifdef CMDLINE_PROCESS
213         CMDLINE_PROCESS
214 #endif
215       }
216
217   /* Set TMPDIR to specified test directory.  */
218   if (test_dir != NULL)
219     {
220       setenv ("TMPDIR", test_dir, 1);
221
222       if (chdir (test_dir) < 0)
223         {
224           perror ("chdir");
225           exit (1);
226         }
227     }
228   else
229     {
230       test_dir = getenv ("TMPDIR");
231       if (test_dir == NULL || test_dir[0] == '\0')
232         test_dir = "/tmp";
233     }
234
235   /* Make sure we see all message, even those on stdout.  */
236   setvbuf (stdout, NULL, _IONBF, 0);
237
238   /* make sure temporary files are deleted.  */
239   atexit (delete_temp_files);
240
241   /* Correct for the possible parameters.  */
242   argv[optind - 1] = argv[0];
243   argv += optind - 1;
244   argc -= optind - 1;
245
246   /* Call the initializing function, if one is available.  */
247 #ifdef PREPARE
248   PREPARE (argc, argv);
249 #endif
250
251   /* If we are not expected to fork run the function immediately.  */
252   if (direct)
253     return TEST_FUNCTION;
254
255   /* Set up the test environment:
256      - prevent core dumps
257      - set up the timer
258      - fork and execute the function.  */
259
260   pid = fork ();
261   if (pid == 0)
262     {
263       /* This is the child.  */
264 #ifdef RLIMIT_CORE
265       /* Try to avoid dumping core.  */
266       struct rlimit core_limit;
267       core_limit.rlim_cur = 0;
268       core_limit.rlim_max = 0;
269       setrlimit (RLIMIT_CORE, &core_limit);
270 #endif
271
272 #ifdef RLIMIT_DATA
273       /* Try to avoid eating all memory if a test leaks.  */
274       struct rlimit data_limit;
275       if (getrlimit (RLIMIT_DATA, &data_limit) == 0)
276         {
277           if (TEST_DATA_LIMIT == RLIM_INFINITY)
278             data_limit.rlim_cur = data_limit.rlim_max;
279           else if (data_limit.rlim_cur > (rlim_t) TEST_DATA_LIMIT)
280             data_limit.rlim_cur = MIN ((rlim_t) TEST_DATA_LIMIT,
281                                        data_limit.rlim_max);
282           if (setrlimit (RLIMIT_DATA, &data_limit) < 0)
283             perror ("setrlimit: RLIMIT_DATA");
284         }
285       else
286         perror ("getrlimit: RLIMIT_DATA");
287 #endif
288
289       /* We put the test process in its own pgrp so that if it bogusly
290          generates any job control signals, they won't hit the whole build.  */
291       setpgid (0, 0);
292
293       /* Execute the test function and exit with the return value.   */
294       exit (TEST_FUNCTION);
295     }
296   else if (pid < 0)
297     {
298       perror ("Cannot fork test program");
299       exit (1);
300     }
301
302   /* Set timeout.  */
303 #ifndef TIMEOUT
304   /* Default timeout is two seconds.  */
305 # define TIMEOUT 2
306 #endif
307   signal (SIGALRM, timeout_handler);
308   alarm (TIMEOUT);
309
310   /* Wait for the regular termination.  */
311   termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
312   if (termpid == -1)
313     {
314       printf ("Waiting for test program failed: %m\n");
315       exit (1);
316     }
317   if (termpid != pid)
318     {
319       printf ("Oops, wrong test program terminated: expected %ld, got %ld\n",
320               (long int) pid, (long int) termpid);
321       exit (1);
322     }
323
324 #ifndef EXPECTED_SIGNAL
325   /* We don't expect any signal.  */
326 # define EXPECTED_SIGNAL 0
327 #endif
328   if (WTERMSIG (status) != EXPECTED_SIGNAL)
329     {
330       if (EXPECTED_SIGNAL != 0)
331         {
332           if (WTERMSIG (status) == 0)
333             fprintf (stderr,
334                      "Expected signal '%s' from child, got none\n",
335                      strsignal (EXPECTED_SIGNAL));
336           else
337             fprintf (stderr,
338                      "Incorrect signal from child: got `%s', need `%s'\n",
339                      strsignal (WTERMSIG (status)),
340                      strsignal (EXPECTED_SIGNAL));
341         }
342       else
343         fprintf (stderr, "Didn't expect signal from child: got `%s'\n",
344                  strsignal (WTERMSIG (status)));
345       exit (1);
346     }
347
348   /* Simply exit with the return value of the test.  */
349 #ifndef EXPECTED_STATUS
350   return WEXITSTATUS (status);
351 #else
352   if (WEXITSTATUS (status) != EXPECTED_STATUS)
353     {
354       fprintf (stderr, "Expected status %d, got %d\n",
355                EXPECTED_STATUS, WEXITSTATUS (status));
356       exit (1);
357     }
358
359   return 0;
360 #endif
361 }