summaryrefslogtreecommitdiff
path: root/test/test-skeleton.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/test-skeleton.c')
-rw-r--r--test/test-skeleton.c116
1 files changed, 80 insertions, 36 deletions
diff --git a/test/test-skeleton.c b/test/test-skeleton.c
index adfc8b75b..4f2680485 100644
--- a/test/test-skeleton.c
+++ b/test/test-skeleton.c
@@ -14,10 +14,10 @@
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
- License along with the GNU C Library; if not, write to the Free
- Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA. */
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
@@ -44,19 +44,6 @@
# define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with. */
#endif
-#define OPT_DIRECT 1000
-#define OPT_TESTDIR 1001
-
-static struct option options[] =
-{
-#ifdef CMDLINE_OPTIONS
- CMDLINE_OPTIONS
-#endif
- { "direct", no_argument, NULL, OPT_DIRECT },
- { "test-dir", required_argument, NULL, OPT_TESTDIR },
- { NULL, 0, NULL, 0 }
-};
-
/* PID of the test itself. */
static pid_t pid;
@@ -67,7 +54,7 @@ static const char *test_dir;
struct temp_name_list
{
struct qelem q;
- const char *name;
+ char *name;
} *temp_name_list;
/* Add temporary files in list. */
@@ -77,14 +64,17 @@ add_temp_file (const char *name)
{
struct temp_name_list *newp
= (struct temp_name_list *) calloc (sizeof (*newp), 1);
- if (newp != NULL)
+ char *newname = strdup (name);
+ if (newp != NULL && newname != NULL)
{
- newp->name = name;
+ newp->name = newname;
if (temp_name_list == NULL)
temp_name_list = (struct temp_name_list *) &newp->q;
else
insque (newp, temp_name_list);
}
+ else
+ free (newp);
}
/* Delete all temporary files. */
@@ -94,17 +84,25 @@ delete_temp_files (void)
while (temp_name_list != NULL)
{
remove (temp_name_list->name);
- temp_name_list = (struct temp_name_list *) temp_name_list->q.q_forw;
+ free (temp_name_list->name);
+
+ struct temp_name_list *next
+ = (struct temp_name_list *) temp_name_list->q.q_forw;
+ free (temp_name_list);
+ temp_name_list = next;
}
}
-/* Create a temporary file. */
+/* Create a temporary file. Return the opened file descriptor on
+ success, or -1 on failure. Write the file name to *FILENAME if
+ FILENAME is not NULL. In this case, the caller is expected to free
+ *FILENAME. */
static int
__attribute__ ((unused))
create_temp_file (const char *base, char **filename)
{
char *fname;
- int fd;
+ int _fd;
fname = (char *) malloc (strlen (test_dir) + 1 + strlen (base)
+ sizeof ("XXXXXX"));
@@ -115,8 +113,8 @@ create_temp_file (const char *base, char **filename)
}
strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX");
- fd = mkstemp (fname);
- if (fd == -1)
+ _fd = mkstemp (fname);
+ if (_fd == -1)
{
printf ("cannot open temporary file '%s': %s\n", fname, strerror(errno));
free (fname);
@@ -126,25 +124,33 @@ create_temp_file (const char *base, char **filename)
add_temp_file (fname);
if (filename != NULL)
*filename = fname;
+ else
+ free (fname);
- return fd;
+ return _fd;
}
/* Timeout handler. We kill the child and exit with an error. */
static void
__attribute__ ((noreturn))
-timeout_handler (int sig __attribute__ ((unused)))
+signal_handler (int sig __attribute__ ((unused)))
{
int killed = 0;
int status;
+ int i;
- /* Send signal. */
+ assert (pid > 1);
+ /* Kill the whole process group. */
+ kill (-pid, SIGKILL);
+ /* In case setpgid failed in the child, kill it individually too. */
kill (pid, SIGKILL);
/* Wait for it to terminate. */
- int i;
for (i = 0; i < 5; ++i)
{
+#ifdef __UCLIBC_HAS_REALTIME__
+ struct timespec ts;
+#endif
killed = waitpid (pid, &status, WNOHANG|WUNTRACED);
if (killed != 0)
break;
@@ -153,10 +159,14 @@ timeout_handler (int sig __attribute__ ((unused)))
nanosleep() call return prematurely, all the better. We
won't restart it since this probably means the child process
finally died. */
- struct timespec ts;
+#ifdef __UCLIBC_HAS_REALTIME__
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
nanosleep (&ts, NULL);
+#else
+ /* No nanosleep, just sleep 1s instead of 0.1s */
+ sleep(1);
+#endif
}
if (killed != 0 && killed != pid)
{
@@ -168,6 +178,12 @@ timeout_handler (int sig __attribute__ ((unused)))
CLEANUP_HANDLER;
#endif
+ if (sig == SIGINT)
+ {
+ signal (sig, SIG_DFL);
+ raise (sig);
+ }
+
/* If we expected this signal: good! */
#ifdef EXPECTED_SIGNAL
if (EXPECTED_SIGNAL == SIGALRM)
@@ -190,6 +206,18 @@ timeout_handler (int sig __attribute__ ((unused)))
exit (1);
}
+#ifdef __XXX_HANDLE_CTRL_C
+static void
+__attribute__ ((noreturn))
+handler_killpid(int sig)
+{
+ kill(pid, SIGKILL); /* kill test */
+ signal(sig, SIG_DFL);
+ raise(sig); /* kill ourself */
+ _exit(128 + sig); /* paranoia */
+}
+#endif
+
/* We provide the entry point here. */
int
main (int argc, char *argv[])
@@ -203,6 +231,7 @@ main (int argc, char *argv[])
int opt;
unsigned int timeoutfactor = 1;
pid_t termpid;
+ char *envstr_timeoutfactor;
/* Make uses of freed and uninitialized memory known. */
#ifdef __MALLOC_STANDARD__
@@ -216,15 +245,18 @@ main (int argc, char *argv[])
setbuf (stdout, NULL);
#endif
- while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1)
+# ifndef CMDLINE_OPTIONS
+# define CMDLINE_OPTIONS ""
+# endif
+ while ((opt = getopt (argc, argv, "+dt:" CMDLINE_OPTIONS)) >= 0)
switch (opt)
{
case '?':
exit (1);
- case OPT_DIRECT:
+ case 'd':
direct = 1;
break;
- case OPT_TESTDIR:
+ case 't':
test_dir = optarg;
break;
#ifdef CMDLINE_PROCESS
@@ -234,7 +266,7 @@ main (int argc, char *argv[])
/* If set, read the test TIMEOUTFACTOR value from the environment.
This value is used to scale the default test timeout values. */
- char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
+ envstr_timeoutfactor = getenv ("TIMEOUTFACTOR");
if (envstr_timeoutfactor != NULL)
{
char *envstr_conv = envstr_timeoutfactor;
@@ -293,6 +325,9 @@ main (int argc, char *argv[])
if (pid == 0)
{
/* This is the child. */
+#ifdef RLIMIT_DATA
+ struct rlimit data_limit;
+#endif
#ifdef RLIMIT_CORE
/* Try to avoid dumping core. */
struct rlimit core_limit;
@@ -303,7 +338,6 @@ main (int argc, char *argv[])
#ifdef RLIMIT_DATA
/* Try to avoid eating all memory if a test leaks. */
- struct rlimit data_limit;
if (getrlimit (RLIMIT_DATA, &data_limit) == 0)
{
if (TEST_DATA_LIMIT == RLIM_INFINITY)
@@ -320,7 +354,8 @@ main (int argc, char *argv[])
/* We put the test process in its own pgrp so that if it bogusly
generates any job control signals, they won't hit the whole build. */
- setpgid (0, 0);
+ if (setpgid (0, 0) != 0)
+ printf ("Failed to set the process group ID: %m\n");
/* Execute the test function and exit with the return value. */
exit (TEST_FUNCTION);
@@ -332,14 +367,23 @@ main (int argc, char *argv[])
exit (1);
}
+#ifdef __XXX_HANDLE_CTRL_C
+ signal (SIGTERM, handler_killpid);
+ signal (SIGINT, handler_killpid);
+ signal (SIGQUIT, handler_killpid);
+#endif
+
/* Set timeout. */
#ifndef TIMEOUT
/* Default timeout is two seconds. */
# define TIMEOUT 2
#endif
- signal (SIGALRM, timeout_handler);
+ signal (SIGALRM, signal_handler);
alarm (TIMEOUT * timeoutfactor);
+ /* Make sure we clean up if the wrapper gets interrupted. */
+ signal (SIGINT, signal_handler);
+
/* Wait for the regular termination. */
termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
if (termpid == -1)