diff options
Diffstat (limited to 'test/test-skeleton.c')
| -rw-r--r-- | test/test-skeleton.c | 116 |
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) |
