diff --git a/ChangeLog b/ChangeLog index e19db5d054..fa3c109180 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,83 @@ +2016-12-09 Florian Weimer + + New subdirectory support for build and test infrastructure. + * extra-libs.mk (extra-libs-noinstall): Add variable. Use it when + setting install-lib. + * Makeconfig (link-extra-libs-tests): Define. + (+link-pie-tests, +link-static-tests, +link-tests): Use + link-extra-libs-tests. + (rpath-dirs, all-subdirs): Add support. + (built-modules): Add libsupport. + (libsupport): Define. + * support: New directory. + * support/Makefile: New file. + * support/check.c: Likewise. + * support/check.h: Likewise. + * support/delayed_exit.c: Likewise. + * support/ignore_stderr.c: Likewise. + * support/oom_error.c: Likewise. + * support/set_fortify_handler.c: Likewise. + * support/support.h: Likewise. + * support/temp_file-internal.h: Likewise. + * support/temp_file.c: Likewise. + * support/test-driver.c: Likewise. + * support/test-driver.h: Likewise. + * support/test_main.c: Likewise. + * support/write_message.c: Likewise. + * support/xasprintf.c: Likewise. + * support/xcalloc.c: Likewise. + * support/xmalloc.c: Likewise. + * support/xpthread_barrier_destroy.c: Likewise. + * support/xpthread_barrier_init.c: Likewise. + * support/xpthread_barrier_wait.c: Likewise. + * support/xpthread_cancel.c: Likewise. + * support/xpthread_check_return.c: Likewise. + * support/xpthread_cond_wait.c: Likewise. + * support/xpthread_create.c: Likewise. + * support/xpthread_detach.c: Likewise. + * support/xpthread_join.c: Likewise. + * support/xpthread_mutex_lock.c: Likewise. + * support/xpthread_mutex_unlock.c: Likewise. + * support/xpthread_sigmask.c: Likewise. + * support/xpthread_spin_lock.c: Likewise. + * support/xpthread_spin_unlock.c: Likewise. + * support/xrealloc.c: Likweise. + * support/xsignal.h: Likewise. + * support/xthread.h: Likewise. + * support_tempfile.h: Likewise. + * test-skeleton.c: Include , . + (TEST_DATA_LIMIT): Remove unused macro. + (_FAIL, FAIL_RET, FAIL_EXIT, FAIL_EXIT1): Remove. Now in + . + (oom_error, xmalloc, xcalloc, xrealloc, xasprintf, write_message) + (ignore_stderr, set_fortify_handler): Remove. Now in + . + (xpthread_sigmask): Remove. Now in . + (xpthread_mutex_lock, xpthread_spin_lock, xpthread_cond_wait) + (xpthread_barrier_wait, xpthread_create, xpthread_detach) + (xpthread_join): Remove. Now in . + (TEST_FUNCTION, PREPARE, CLEANUP_HANDLER, CMDLINE_PROCESS): + Introduce legacy wrappers. + * dlfcn/Makefile (bug-atexit3-lib.so): Link with $(libsupport). + * dlfcn/bug-atexit3-lib.cc: Include . + (write_message): Remove. + * dirent/opendir-tst1.c: Use instead of + test-skeleton.c. + * io/test-open-tmpfile: Likewise. + * io/tst-posix_fallocate-common.c: Likewise. + * libio/tst-fseek.c: Likewise. + * malloc/tst-malloc-backtrace.c: Likewise. + * malloc/tst-malloc-fork-deadlock.c: Likewise. + * malloc/tst-malloc-thread-exit.c: Likewise. + * nptl/tst-cancel7.c: Likewise. + * nptl/tst-cleanup0.c: Likewise. + * posix/tst-posix_fadvise-common.c: Likewise. + * rt/tst-shm.c: Likewise. + * time/bug-getdate1.c: Likewise. + * sysdeps/unix/sysv/linux/tst-fallocate-common.c: Likewise. + * sysdeps/unix/sysv/linux/tst-sync_file_range.c: Likewise. + * elf/Makefile (tst-piemod1.so): Link against libsupport. + 2016-12-08 Joseph Myers * Rules [$(run-built-tests) != no] (tests-expected): Add diff --git a/Makeconfig b/Makeconfig index e9d8da9d60..be45c3a0b9 100644 --- a/Makeconfig +++ b/Makeconfig @@ -394,6 +394,9 @@ ifndef after-link after-link = endif +# Additional libraries to link into every test. +link-extra-libs-tests = $(libsupport) + # Command for linking PIE programs with the C library. ifndef +link-pie +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \ @@ -412,8 +415,8 @@ $(+link-pie-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-pie-after-libc) $(call after-link,$@) endef define +link-pie-tests -$(+link-pie-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ - $(+link-pie-after-libc) +$(+link-pie-before-libc) $(link-extra-libs-tests) \ + $(rtld-tests-LDFLAGS) $(link-libc-tests) $(+link-pie-after-libc) $(call after-link,$@) endef define +link-pie-printers-tests @@ -439,7 +442,8 @@ $(+link-static-before-libc) $(link-libc-static) $(+link-static-after-libc) $(call after-link,$@) endef define +link-static-tests -$(+link-static-before-libc) $(link-libc-static-tests) $(+link-static-after-libc) +$(+link-static-before-libc) $(link-extra-libs-tests) \ + $(link-libc-static-tests) $(+link-static-after-libc) $(call after-link,$@) endef endif @@ -468,8 +472,8 @@ $(+link-before-libc) $(rtld-LDFLAGS) $(link-libc) $(+link-after-libc) $(call after-link,$@) endef define +link-tests -$(+link-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \ - $(+link-after-libc) +$(+link-before-libc) $(link-extra-libs-tests) \ + $(rtld-tests-LDFLAGS) $(link-libc-tests) $(+link-after-libc) $(call after-link,$@) endef define +link-printers-tests @@ -545,7 +549,7 @@ link-libc-printers-tests = $(link-libc-rpath) \ $(link-libc-tests-after-rpath-link) # This is how to find at build-time things that will be installed there. -rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec +rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support rpath-link = \ $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) else # build-static @@ -892,7 +896,7 @@ libio-include = -I$(..)libio # List of non-library modules that we build. built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \ libSegFault libpcprofile librpcsvc locale-programs \ - memusagestat nonlib nscd extramodules libnldbl + memusagestat nonlib nscd extramodules libnldbl libsupport in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \ $(libof-$( +#include diff --git a/dlfcn/Makefile b/dlfcn/Makefile index deab96e6a7..713e555b82 100644 --- a/dlfcn/Makefile +++ b/dlfcn/Makefile @@ -139,6 +139,7 @@ $(objpfx)bug-atexit2.out: $(objpfx)bug-atexit2-lib.so ifneq (,$(CXX)) LDLIBS-bug-atexit3-lib.so = -lstdc++ -lgcc_eh +$(objpfx)bug-atexit3-lib.so: $(libsupport) $(objpfx)bug-atexit3: $(libdl) $(objpfx)bug-atexit3.out: $(objpfx)bug-atexit3-lib.so endif diff --git a/dlfcn/bug-atexit3-lib.cc b/dlfcn/bug-atexit3-lib.cc index aba772004d..ed3334709a 100644 --- a/dlfcn/bug-atexit3-lib.cc +++ b/dlfcn/bug-atexit3-lib.cc @@ -1,12 +1,7 @@ #include #include -static void -write_message (const char *message) -{ - ssize_t unused __attribute__ ((unused)); - unused = write (STDOUT_FILENO, message, strlen (message)); -} +#include struct statclass { diff --git a/elf/Makefile b/elf/Makefile index f57927f403..330397e5d8 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -981,6 +981,7 @@ $(objpfx)tst-array5-static-cmp.out: tst-array5-static.exp \ CFLAGS-tst-pie1.c += $(pie-ccflag) CFLAGS-tst-pie2.c += $(pie-ccflag) +$(objpfx)tst-piemod1.so: $(libsupport) $(objpfx)tst-pie1: $(objpfx)tst-piemod1.so ifeq (yes,$(build-shared)) diff --git a/extra-lib.mk b/extra-lib.mk index b10748d185..2552049135 100644 --- a/extra-lib.mk +++ b/extra-lib.mk @@ -5,6 +5,9 @@ # The variable $($(lib)-routines) defines the list of modules # to be included in that library. A sysdep Makefile can add to # $(lib)-sysdep_routines to include additional modules. +# +# Libraries listed in $(extra-libs-noinstall) are built, but not +# installed. lib := $(firstword $(extra-libs-left)) extra-libs-left := $(filter-out $(lib),$(extra-libs-left)) @@ -28,7 +31,9 @@ extra-objs := $(extra-objs) all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines) # Add each flavor of library to the lists of things to build and install. +ifeq (,$(filter $(lib), $(extra-libs-noinstall))) install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o))) +endif extra-objs += $(foreach o,$(filter-out .os .oS,$(object-suffixes-$(lib))),\ $(patsubst %,%$o,$(filter-out \ $($(lib)-shared-only-routines),\ diff --git a/io/tst-open-tmpfile.c b/io/tst-open-tmpfile.c index 9242d62392..23fa819c3c 100644 --- a/io/tst-open-tmpfile.c +++ b/io/tst-open-tmpfile.c @@ -28,10 +28,7 @@ #include #include -static int do_test (void); - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include #ifdef O_TMPFILE typedef int (*wrapper_func) (const char *, int, mode_t); @@ -317,3 +314,5 @@ do_test (void) } #endif /* O_TMPFILE */ + +#include diff --git a/io/tst-posix_fallocate-common.c b/io/tst-posix_fallocate-common.c index 2f15a5df18..3073ffea95 100644 --- a/io/tst-posix_fallocate-common.c +++ b/io/tst-posix_fallocate-common.c @@ -17,32 +17,27 @@ . */ #include -#include +#include +#include #include +#include #include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#define TIMEOUT 20 /* sec. */ - -#include +#include +#include +#include static char *temp_filename; static int temp_fd; static void -do_prepare (void) +do_prepare (int argc, char **argv) { temp_fd = create_temp_file ("tst-posix_fallocate.", &temp_filename); if (temp_fd == -1) FAIL_EXIT1 ("cannot create temporary file: %m\n"); } - -#define FAIL(str) \ - do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0) +#define PREPARE do_prepare static int do_test_with_offset (off_t offset) @@ -83,3 +78,8 @@ do_test_with_offset (off_t offset) return 0; } + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include diff --git a/libio/tst-fseek.c b/libio/tst-fseek.c index 9bb0d7f707..1a81740ed9 100644 --- a/libio/tst-fseek.c +++ b/libio/tst-fseek.c @@ -24,9 +24,7 @@ #include #include -/* Defined in test-skeleton.c. */ -static int create_temp_file (const char *base, char **filename); - +#include static int do_seek_end (FILE *fp) @@ -168,6 +166,4 @@ do_test (void) return ret; } - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c index 3aee7fdb28..1f1f0e803c 100644 --- a/malloc/tst-malloc-backtrace.c +++ b/malloc/tst-malloc-backtrace.c @@ -16,9 +16,11 @@ License along with the GNU C Library; if not, see . */ - +#include #include +#include + #define SIZE 4096 /* Wrap free with a function to prevent gcc from optimizing it out. */ @@ -30,13 +32,6 @@ call_free (void *ptr) *(size_t *)(ptr - sizeof (size_t)) = 1; } -int do_test (void); - -#define TEST_FUNCTION do_test () -#define EXPECTED_SIGNAL SIGABRT - -#include "../test-skeleton.c" - int do_test (void) { @@ -53,3 +48,6 @@ do_test (void) doesn't optimize out that malloc call. */ return (ptr1 == ptr2); } + +#define EXPECTED_SIGNAL SIGABRT +#include diff --git a/malloc/tst-malloc-fork-deadlock.c b/malloc/tst-malloc-fork-deadlock.c index 94549ca459..cdef2257d2 100644 --- a/malloc/tst-malloc-fork-deadlock.c +++ b/malloc/tst-malloc-fork-deadlock.c @@ -28,9 +28,9 @@ #include #include -static int do_test (void); -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include +#include +#include enum { /* Number of threads which call fork. */ @@ -117,30 +117,14 @@ static void create_threads (pthread_t *threads, size_t count, void *(*func) (void *)) { for (size_t i = 0; i < count; ++i) - { - int ret = pthread_create (threads + i, NULL, func, NULL); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_create: %m\n"); - abort (); - } - } + threads[i] = xpthread_create (NULL, func, NULL); } static void join_threads (pthread_t *threads, size_t count) { for (size_t i = 0; i < count; ++i) - { - int ret = pthread_join (threads[i], NULL); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_join: %m\n"); - abort (); - } - } + xpthread_join (threads[i]); } /* Create a file which consists of a single long line, and assigns @@ -189,8 +173,8 @@ do_test (void) /* Leave some room for shutting down all threads gracefully. */ int timeout = 3; - if (timeout > TIMEOUT) - timeout = TIMEOUT - 1; + if (timeout > DEFAULT_TIMEOUT) + timeout = DEFAULT_TIMEOUT - 1; create_file_with_large_line (); @@ -218,3 +202,5 @@ do_test (void) return 0; } + +#include diff --git a/malloc/tst-malloc-thread-exit.c b/malloc/tst-malloc-thread-exit.c index fa6ebf98bf..9f92318c8d 100644 --- a/malloc/tst-malloc-thread-exit.c +++ b/malloc/tst-malloc-thread-exit.c @@ -33,10 +33,9 @@ #include #include -static int do_test (void); - -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include +#include +#include static bool termination_requested; static int inner_thread_count = 4; @@ -53,19 +52,8 @@ static void * malloc_first_thread (void * closure) { pthread_barrier_t *barrier = closure; - void *ptr = malloc (malloc_size); - if (ptr == NULL) - { - printf ("error: malloc: %m\n"); - abort (); - } - int ret = pthread_barrier_wait (barrier); - if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) - { - errno = ret; - printf ("error: pthread_barrier_wait: %m\n"); - abort (); - } + void *ptr = xmalloc (malloc_size); + xpthread_barrier_wait (barrier); unoptimized_free (ptr); return NULL; } @@ -74,19 +62,8 @@ static void * wait_first_thread (void * closure) { pthread_barrier_t *barrier = closure; - int ret = pthread_barrier_wait (barrier); - if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) - { - errno = ret; - printf ("error: pthread_barrier_wait: %m\n"); - abort (); - } - void *ptr = malloc (malloc_size); - if (ptr == NULL) - { - printf ("error: malloc: %m\n"); - abort (); - } + xpthread_barrier_wait (barrier); + void *ptr = xmalloc (malloc_size); unoptimized_free (ptr); return NULL; } @@ -94,23 +71,11 @@ wait_first_thread (void * closure) static void * outer_thread (void *closure) { - pthread_t *threads = calloc (sizeof (*threads), inner_thread_count); - if (threads == NULL) - { - printf ("error: calloc: %m\n"); - abort (); - } - + pthread_t *threads = xcalloc (sizeof (*threads), inner_thread_count); while (!__atomic_load_n (&termination_requested, __ATOMIC_RELAXED)) { pthread_barrier_t barrier; - int ret = pthread_barrier_init (&barrier, NULL, inner_thread_count + 1); - if (ret != 0) - { - errno = ret; - printf ("pthread_barrier_init: %m\n"); - abort (); - } + xpthread_barrier_init (&barrier, NULL, inner_thread_count + 1); for (int i = 0; i < inner_thread_count; ++i) { void *(*func) (void *); @@ -118,38 +83,12 @@ outer_thread (void *closure) func = malloc_first_thread; else func = wait_first_thread; - ret = pthread_create (threads + i, NULL, func, &barrier); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_create: %m\n"); - abort (); - } - } - ret = pthread_barrier_wait (&barrier); - if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) - { - errno = ret; - printf ("pthread_wait: %m\n"); - abort (); + threads[i] = xpthread_create (NULL, func, &barrier); } + xpthread_barrier_wait (&barrier); for (int i = 0; i < inner_thread_count; ++i) - { - ret = pthread_join (threads[i], NULL); - if (ret != 0) - { - ret = errno; - printf ("error: pthread_join: %m\n"); - abort (); - } - } - ret = pthread_barrier_destroy (&barrier); - if (ret != 0) - { - ret = errno; - printf ("pthread_barrier_destroy: %m\n"); - abort (); - } + xpthread_join (threads[i]); + xpthread_barrier_destroy (&barrier); } free (threads); @@ -172,26 +111,12 @@ do_test (void) /* Leave some room for shutting down all threads gracefully. */ int timeout = 3; - if (timeout > TIMEOUT) - timeout = TIMEOUT - 1; - - pthread_t *threads = calloc (sizeof (*threads), outer_thread_count); - if (threads == NULL) - { - printf ("error: calloc: %m\n"); - abort (); - } + if (timeout > DEFAULT_TIMEOUT) + timeout = DEFAULT_TIMEOUT - 1; + pthread_t *threads = xcalloc (sizeof (*threads), outer_thread_count); for (long i = 0; i < outer_thread_count; ++i) - { - int ret = pthread_create (threads + i, NULL, outer_thread, NULL); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_create: %m\n"); - abort (); - } - } + threads[i] = xpthread_create (NULL, outer_thread, NULL); struct timespec ts = {timeout, 0}; if (nanosleep (&ts, NULL)) @@ -203,16 +128,10 @@ do_test (void) __atomic_store_n (&termination_requested, true, __ATOMIC_RELAXED); for (long i = 0; i < outer_thread_count; ++i) - { - int ret = pthread_join (threads[i], NULL); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_join: %m\n"); - abort (); - } - } + xpthread_join (threads[i]); free (threads); return 0; } + +#include diff --git a/nptl/tst-cancel7.c b/nptl/tst-cancel7.c index 7f20862952..8eff3a8dac 100644 --- a/nptl/tst-cancel7.c +++ b/nptl/tst-cancel7.c @@ -24,6 +24,9 @@ #include #include #include +#include + +#include const char *command; const char *pidfile; @@ -105,18 +108,8 @@ do_test (void) sleep (1); while (access (pidfilename, R_OK) != 0); - if (pthread_cancel (th) != 0) - { - puts ("pthread_cancel failed"); - return 1; - } - - void *r; - if (pthread_join (th, &r) != 0) - { - puts ("pthread_join failed"); - return 1; - } + xpthread_cancel (th); + void *r = xpthread_join (th); sleep (1); @@ -196,15 +189,20 @@ do_cleanup (void) #define CMDLINE_OPTIONS \ { "command", required_argument, NULL, OPT_COMMAND }, \ { "pidfile", required_argument, NULL, OPT_PIDFILE }, -#define CMDLINE_PROCESS \ - case OPT_COMMAND: \ - command = optarg; \ - break; \ - case OPT_PIDFILE: \ - pidfile = optarg; \ - break; -#define CLEANUP_HANDLER do_cleanup () -#define PREPARE(argc, argv) do_prepare (argc, argv) -#define TEST_FUNCTION do_test () +static void +cmdline_process (int c) +{ + switch (c) + { + command = optarg; + break; + case OPT_PIDFILE: + pidfile = optarg; + break; + } +} +#define CMDLINE_PROCESS cmdline_process +#define CLEANUP_HANDLER do_cleanup +#define PREPARE do_prepare #define TIMEOUT 5 -#include "../test-skeleton.c" +#include diff --git a/nptl/tst-cleanup0.c b/nptl/tst-cleanup0.c index 011e5a60c1..601ad73634 100644 --- a/nptl/tst-cleanup0.c +++ b/nptl/tst-cleanup0.c @@ -71,5 +71,4 @@ do_test (void) #define EXPECTED_STATUS 9 -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#include diff --git a/posix/tst-posix_fadvise-common.c b/posix/tst-posix_fadvise-common.c index bb04c6116f..38dc0ce81c 100644 --- a/posix/tst-posix_fadvise-common.c +++ b/posix/tst-posix_fadvise-common.c @@ -16,17 +16,17 @@ License along with the GNU C Library; if not, see . */ +#include #include +#include +#include #include #include #include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#include +#include +#include +#include static char *temp_filename; static int temp_fd; @@ -34,7 +34,7 @@ static char fifoname[] = "/tmp/tst-posix_fadvise-fifo-XXXXXX"; static int fifofd; static void -do_prepare (void) +do_prepare (int argc, char **argv) { temp_fd = create_temp_file ("tst-posix_fadvise.", &temp_filename); if (temp_fd == -1) @@ -101,3 +101,10 @@ do_test_common (void) return 0; } + +#define PREPARE do_prepare + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include diff --git a/rt/tst-shm.c b/rt/tst-shm.c index 36fb9ebcd0..95a4f9b21d 100644 --- a/rt/tst-shm.c +++ b/rt/tst-shm.c @@ -199,9 +199,13 @@ do_test (void) return (!WIFEXITED (status1) || WEXITSTATUS (status1) != 0 || !WIFEXITED (status2) || WEXITSTATUS (status2) != 0); } -#define TEST_FUNCTION do_test () -#define CLEANUP_HANDLER shm_unlink ("/glibc-shm-test"); +static void +cleanup_handler (void) +{ + shm_unlink ("/glibc-shm-test"); +} +#define CLEANUP_HANDLER cleanup_handler -#include "../test-skeleton.c" +#include diff --git a/stdlib/tst-secure-getenv.c b/stdlib/tst-secure-getenv.c index 58208dbc59..ce8e73c97c 100644 --- a/stdlib/tst-secure-getenv.c +++ b/stdlib/tst-secure-getenv.c @@ -30,11 +30,12 @@ #include #include +#include +#include + static char MAGIC_ARGUMENT[] = "run-actual-test"; #define MAGIC_STATUS 19 -static const char *test_dir; - /* Return a GID which is not our current GID, but is present in the supplementary group list. */ static gid_t @@ -64,27 +65,17 @@ choose_gid (void) static int run_executable_sgid (gid_t target) { - char *dirname = 0; - char *execname = 0; + char *dirname = xasprintf ("%s/secure-getenv.%jd", + test_dir, (intmax_t) getpid ()); + char *execname = xasprintf ("%s/bin", dirname); int infd = -1; int outfd = -1; int ret = -1; - if (asprintf (&dirname, "%s/secure-getenv.%jd", - test_dir, (intmax_t) getpid ()) < 0) - { - printf ("asprintf: %m\n"); - goto err; - } if (mkdir (dirname, 0700) < 0) { printf ("mkdir: %m\n"); goto err; } - if (asprintf (&execname, "%s/bin", dirname) < 0) - { - printf ("asprintf: %m\n"); - goto err; - } infd = open ("/proc/self/exe", O_RDONLY); if (infd < 0) { @@ -247,6 +238,5 @@ alternative_main (int argc, char **argv) } } -#define PREPARE(argc, argv) alternative_main(argc, argv) -#define TEST_FUNCTION do_test () -#include "../test-skeleton.c" +#define PREPARE alternative_main +#include diff --git a/support/Makefile b/support/Makefile new file mode 100644 index 0000000000..bd425afc2b --- /dev/null +++ b/support/Makefile @@ -0,0 +1,64 @@ +# Makefile for support library, used only at build and test time +# Copyright (C) 2016 Free Software Foundation, Inc. +# This file is part of the GNU C Library. + +# The GNU C Library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. + +# The GNU C Library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# 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, see +# . + +subdir := support + +include ../Makeconfig + +extra-libs := libsupport +extra-libs-others = $(extra-libs) +extra-libs-noinstall := $(extra-libs) + +libsupport-routines = \ + check \ + delayed_exit \ + ignore_stderr \ + oom_error \ + set_fortify_handler \ + support_test_main \ + temp_file \ + write_message \ + xasprintf \ + xcalloc \ + xmalloc \ + xpthread_barrier_destroy \ + xpthread_barrier_init \ + xpthread_barrier_wait \ + xpthread_cancel \ + xpthread_check_return \ + xpthread_cond_wait \ + xpthread_create \ + xpthread_detach \ + xpthread_join \ + xpthread_mutex_lock \ + xpthread_mutex_unlock \ + xpthread_sigmask \ + xpthread_spin_lock \ + xpthread_spin_unlock \ + xrealloc \ + +libsupport-static-only-routines := $(libsupport-routines) +# Only build one variant of the library. +libsupport-inhibit-o := .os +ifeq ($(build-shared),yes) +libsupport-inhibit-o += .o +endif + +tests = README-testing + +include ../Rules diff --git a/support/README b/support/README new file mode 100644 index 0000000000..476cfcda59 --- /dev/null +++ b/support/README @@ -0,0 +1,29 @@ +This subdirectory contains infrastructure which is not put into +installed libraries, but may be linked into programs (installed or +not) and tests. + +# Error-checking wrappers + +These wrappers test for error return codes an terminate the process on +error. They are declared in these header files: + +* support.h +* xsignal.h +* xthread.h + +In general, new wrappers should be added to support.h if possible. +However, support.h must remain fully compatible with C90 and therefore +cannot include headers which use identifers not reserved in C90. If +the wrappers need additional types, additional headers such as +signal.h need to be introduced. + +# Test framework + +The test framework provides a main program for tests, including a +timeout for hanging tests. See README-testing.c for a minimal +example, and test-driver.c for details how to use it. The following +header files provide related declarations: + +* check.h +* temp_file.h +* test-driver.h diff --git a/support/README-testing.c b/support/README-testing.c new file mode 100644 index 0000000000..9d289c3020 --- /dev/null +++ b/support/README-testing.c @@ -0,0 +1,19 @@ +/* This file contains an example test case which shows minimal use of + the test framework. Additional testing hooks are described in + . */ + +/* This function will be called from the test driver. */ +static int +do_test (void) +{ + if (3 == 5) + /* Indicate failure. */ + return 1; + else + /* Indicate success. */ + return 0; +} + +/* This file references do_test above and contains the definition of + the main function. */ +#include diff --git a/support/check.c b/support/check.c new file mode 100644 index 0000000000..75fdf524b5 --- /dev/null +++ b/support/check.c @@ -0,0 +1,53 @@ +/* Support code for reporting test results. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include + +static void +print_failure (const char *file, int line, const char *format, va_list ap) +{ + printf ("error: %s:%d: ", file, line); + vprintf (format, ap); + puts (""); +} + +int +support_print_failure_impl (const char *file, int line, + const char *format, ...) +{ + va_list ap; + va_start (ap, format); + print_failure (file, line, format, ap); + va_end (ap); + return 1; +} + +void +support_exit_failure_impl (int status, const char *file, int line, + const char *format, ...) +{ + va_list ap; + va_start (ap, format); + print_failure (file, line, format, ap); + va_end (ap); + exit (status); +} diff --git a/support/check.h b/support/check.h new file mode 100644 index 0000000000..ff2652ca4e --- /dev/null +++ b/support/check.h @@ -0,0 +1,49 @@ +/* Macros for reporting test results. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#ifndef SUPPORT_CHECK_H +#define SUPPORT_CHECK_H + +#include + +__BEGIN_DECLS + +/* Print failure message to standard output and return 1. */ +#define FAIL_RET(...) \ + return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__) + +/* Print failure message and terminate the process with STATUS. */ +#define FAIL_EXIT(status, ...) \ + support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__) + +/* Print failure message and terminate with exit status 1. */ +#define FAIL_EXIT1(...) \ + support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__) + +int support_print_failure_impl (const char *file, int line, + const char *format, ...) + __attribute__ ((nonnull (1), format (printf, 3, 4))); +void support_exit_failure_impl (int exit_status, + const char *file, int line, + const char *format, ...) + __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5))); + + +__END_DECLS + +#endif /* SUPPORT_CHECK_H */ diff --git a/support/delayed_exit.c b/support/delayed_exit.c new file mode 100644 index 0000000000..d5b2e10927 --- /dev/null +++ b/support/delayed_exit.c @@ -0,0 +1,57 @@ +/* Time-triggered process termination. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include +#include + +#include +#include +#include +#include + +static void * +delayed_exit_thread (void *seconds_as_ptr) +{ + int seconds = (uintptr_t) seconds_as_ptr; + struct timespec delay = { seconds, 0 }; + struct timespec remaining = { 0 }; + if (nanosleep (&delay, &remaining) != 0) + { + printf ("error: nanosleep: %m\n"); + exit (1); + } + /* Exit the process sucessfully. */ + exit (0); + return NULL; +} + +void +delayed_exit (int seconds) +{ + /* Create the new thread with all signals blocked. */ + sigset_t all_blocked; + sigfillset (&all_blocked); + sigset_t old_set; + xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); + /* Create a detached thread. */ + pthread_t thr = xpthread_create + (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); + xpthread_detach (thr); + /* Restore the original signal mask. */ + xpthread_sigmask (SIG_SETMASK, &old_set, NULL); +} diff --git a/support/ignore_stderr.c b/support/ignore_stderr.c new file mode 100644 index 0000000000..1b35d06690 --- /dev/null +++ b/support/ignore_stderr.c @@ -0,0 +1,38 @@ +/* Avoid all the buffer overflow messages on stderr. + Copyright (C) 2015-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include +#include + +void +ignore_stderr (void) +{ + int fd = open (_PATH_DEVNULL, O_WRONLY); + if (fd == -1) + close (STDERR_FILENO); + else + { + dup2 (fd, STDERR_FILENO); + close (fd); + } + setenv ("LIBC_FATAL_STDERR_", "1", 1); +} diff --git a/support/oom_error.c b/support/oom_error.c new file mode 100644 index 0000000000..b28c5b4b87 --- /dev/null +++ b/support/oom_error.c @@ -0,0 +1,29 @@ +/* Reporting out-of-memory errors. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include + +void +oom_error (const char *function, size_t size) +{ + printf ("%s: unable to allocate %zu bytes: %m\n", function, size); + exit (1); +} diff --git a/support/set_fortify_handler.c b/support/set_fortify_handler.c new file mode 100644 index 0000000000..a976f44177 --- /dev/null +++ b/support/set_fortify_handler.c @@ -0,0 +1,34 @@ +/* Set signal handler for use in fortify tests. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include + +void +set_fortify_handler (void (*handler) (int sig)) +{ + struct sigaction sa; + + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGABRT, &sa, NULL); + ignore_stderr (); +} diff --git a/support/support.h b/support/support.h new file mode 100644 index 0000000000..fc7fba9a3a --- /dev/null +++ b/support/support.h @@ -0,0 +1,58 @@ +/* Common extra functions. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +/* This header file should only contain definitions compatible with + C90. (Using __attribute__ is fine because provides a + fallback.) */ + +#ifndef SUPPORT_H +#define SUPPORT_H + +#include +#include + +__BEGIN_DECLS + +/* Write a message to standard output. Can be used in signal + handlers. */ +void write_message (const char *message) __attribute__ ((nonnull (1))); + +/* Avoid all the buffer overflow messages on stderr. */ +void ignore_stderr (void); + +/* Set fortification error handler. Used when tests want to verify that bad + code is caught by the library. */ +void set_fortify_handler (void (*handler) (int sig)); + +/* Report an out-of-memory error for the allocation of SIZE bytes in + FUNCTION, terminating the process. */ +void oom_error (const char *function, size_t size) + __attribute__ ((nonnull (1))); + +/* Error-checking wrapper functions which terminate the process on + error. */ + +void *xmalloc (size_t) __attribute__ ((malloc)); +void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); +void *xrealloc (void *p, size_t n); +char *xasprintf (const char *format, ...) + __attribute__ ((format (printf, 1, 2), malloc)); + +__END_DECLS + +#endif /* SUPPORT_H */ diff --git a/support/support_test_main.c b/support/support_test_main.c new file mode 100644 index 0000000000..72771bf101 --- /dev/null +++ b/support/support_test_main.c @@ -0,0 +1,406 @@ +/* Main worker function for the test driver. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct option default_options[] = +{ + { "direct", no_argument, NULL, OPT_DIRECT }, + { "test-dir", required_argument, NULL, OPT_TESTDIR }, + { NULL, 0, NULL, 0 } +}; + +/* Show people how to run the program. */ +static void +usage (const struct option *options) +{ + size_t i; + + printf ("Usage: %s [options]\n" + "\n" + "Environment Variables:\n" + " TIMEOUTFACTOR An integer used to scale the timeout\n" + " TMPDIR Where to place temporary files\n" + " TEST_COREDUMPS Do not disable coredumps if set\n" + "\n", + program_invocation_short_name); + printf ("Options:\n"); + for (i = 0; options[i].name; ++i) + { + int indent; + + indent = printf (" --%s", options[i].name); + if (options[i].has_arg == required_argument) + indent += printf (" "); + printf ("%*s", 25 - indent, ""); + switch (options[i].val) + { + case OPT_DIRECT: + printf ("Run the test directly (instead of forking & monitoring)"); + break; + case OPT_TESTDIR: + printf ("Override the TMPDIR env var"); + break; + } + printf ("\n"); + } +} + +/* The PID of the test process. */ +static pid_t test_pid; + +/* The cleanup handler passed to test_main. */ +static void (*cleanup_function) (void); + +/* Timeout handler. We kill the child and exit with an error. */ +static void +__attribute__ ((noreturn)) +signal_handler (int sig) +{ + int killed; + int status; + + assert (test_pid > 1); + /* Kill the whole process group. */ + kill (-test_pid, SIGKILL); + /* In case setpgid failed in the child, kill it individually too. */ + kill (test_pid, SIGKILL); + + /* Wait for it to terminate. */ + int i; + for (i = 0; i < 5; ++i) + { + killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED); + if (killed != 0) + break; + + /* Delay, give the system time to process the kill. If the + nanosleep() call return prematurely, all the better. We + won't restart it since this probably means the child process + finally died. */ + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + if (killed != 0 && killed != test_pid) + { + printf ("Failed to kill test process: %m\n"); + exit (1); + } + + if (cleanup_function != NULL) + cleanup_function (); + + if (sig == SIGINT) + { + signal (sig, SIG_DFL); + raise (sig); + } + + if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) + puts ("Timed out: killed the child process"); + else if (WIFSTOPPED (status)) + printf ("Timed out: the child process was %s\n", + strsignal (WSTOPSIG (status))); + else if (WIFSIGNALED (status)) + printf ("Timed out: the child process got signal %s\n", + strsignal (WTERMSIG (status))); + else + printf ("Timed out: killed the child process but it exited %d\n", + WEXITSTATUS (status)); + + /* Exit with an error. */ + exit (1); +} + +/* Run test_function or test_function_argv. */ +static int +run_test_function (int argc, char **argv, const struct test_config *config) +{ + if (config->test_function != NULL) + return config->test_function (); + else if (config->test_function_argv != NULL) + return config->test_function_argv (argc, argv); + else + { + printf ("error: no test function defined\n"); + exit (1); + } +} + +static bool test_main_called; + +const char *test_dir = NULL; + +int +support_test_main (int argc, char **argv, const struct test_config *config) +{ + if (test_main_called) + { + printf ("error: test_main called for a second time\n"); + exit (1); + } + test_main_called = true; + const struct option *options; + if (config->options != NULL) + options = config->options; + else + options = default_options; + + cleanup_function = config->cleanup_function; + + int direct = 0; /* Directly call the test function? */ + int status; + int opt; + unsigned int timeoutfactor = 1; + pid_t termpid; + + if (!config->no_mallopt) + { + /* Make uses of freed and uninitialized memory known. Do not + pull in a definition for mallopt if it has not been defined + already. */ + extern __typeof__ (mallopt) mallopt __attribute__ ((weak)); + if (mallopt != NULL) + mallopt (M_PERTURB, 42); + } + + while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) + switch (opt) + { + case '?': + usage (options); + exit (1); + case OPT_DIRECT: + direct = 1; + break; + case OPT_TESTDIR: + test_dir = optarg; + break; + default: + if (config->cmdline_function != NULL) + config->cmdline_function (opt); + } + + /* 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"); + if (envstr_timeoutfactor != NULL) + { + char *envstr_conv = envstr_timeoutfactor; + unsigned long int env_fact; + + env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); + if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) + timeoutfactor = MAX (env_fact, 1); + } + + /* Set TMPDIR to specified test directory. */ + if (test_dir != NULL) + { + setenv ("TMPDIR", test_dir, 1); + + if (chdir (test_dir) < 0) + { + printf ("chdir: %m\n"); + exit (1); + } + } + else + { + test_dir = getenv ("TMPDIR"); + if (test_dir == NULL || test_dir[0] == '\0') + test_dir = "/tmp"; + } + if (support_set_test_dir != NULL) + support_set_test_dir (test_dir); + + int timeout = config->timeout; + if (timeout == 0) + timeout = DEFAULT_TIMEOUT; + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + /* Make sure temporary files are deleted. */ + if (support_delete_temp_files != NULL) + atexit (support_delete_temp_files); + + /* Correct for the possible parameters. */ + argv[optind - 1] = argv[0]; + argv += optind - 1; + argc -= optind - 1; + + /* Call the initializing function, if one is available. */ + if (config->prepare_function != NULL) + config->prepare_function (argc, argv); + + const char *envstr_direct = getenv ("TEST_DIRECT"); + if (envstr_direct != NULL) + { + FILE *f = fopen (envstr_direct, "w"); + if (f == NULL) + { + printf ("cannot open TEST_DIRECT output file '%s': %m\n", + envstr_direct); + exit (1); + } + + fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", + config->timeout, timeoutfactor); + if (config->expected_status != 0) + fprintf (f, "exit=%u\n", config->expected_status); + if (config->expected_signal != 0) + fprintf (f, "signal=%s\n", strsignal (config->expected_signal)); + + if (support_print_temp_files != NULL) + support_print_temp_files (f); + + fclose (f); + direct = 1; + } + + bool disable_coredumps; + { + const char *coredumps = getenv ("TEST_COREDUMPS"); + disable_coredumps = coredumps == NULL || coredumps[0] == '\0'; + } + + /* If we are not expected to fork run the function immediately. */ + if (direct) + return run_test_function (argc, argv, config); + + /* Set up the test environment: + - prevent core dumps + - set up the timer + - fork and execute the function. */ + + pid_t test_pid = fork (); + if (test_pid == 0) + { + /* This is the child. */ + if (disable_coredumps) + { + /* Try to avoid dumping core. This is necessary because we + run the test from the source tree, and the coredumps + would end up there (and not in the build tree). */ + struct rlimit core_limit; + core_limit.rlim_cur = 0; + core_limit.rlim_max = 0; + setrlimit (RLIMIT_CORE, &core_limit); + } + + /* 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. */ + 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 (run_test_function (argc, argv, config)); + } + else if (test_pid < 0) + { + printf ("Cannot fork test program: %m\n"); + exit (1); + } + + /* Set timeout. */ + signal (SIGALRM, signal_handler); + alarm (config->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 (test_pid, &status, 0)); + if (termpid == -1) + { + printf ("Waiting for test program failed: %m\n"); + exit (1); + } + if (termpid != test_pid) + { + printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", + (long int) test_pid, (long int) termpid); + exit (1); + } + + /* Process terminated normaly without timeout etc. */ + if (WIFEXITED (status)) + { + if (config->expected_status == 0) + { + if (config->expected_signal == 0) + /* Simply exit with the return value of the test. */ + return WEXITSTATUS (status); + else + { + printf ("Expected signal '%s' from child, got none\n", + strsignal (config->expected_signal)); + exit (1); + } + } + else + { + /* Non-zero exit status is expected */ + if (WEXITSTATUS (status) != config->expected_status) + { + printf ("Expected status %d, got %d\n", + config->expected_status, WEXITSTATUS (status)); + exit (1); + } + } + return 0; + } + /* Process was killed by timer or other signal. */ + else + { + if (config->expected_signal == 0) + { + printf ("Didn't expect signal from child: got `%s'\n", + strsignal (WTERMSIG (status))); + exit (1); + } + else if (WTERMSIG (status) != config->expected_signal) + { + printf ("Incorrect signal from child: got `%s', need `%s'\n", + strsignal (WTERMSIG (status)), + strsignal (config->expected_signal)); + exit (1); + } + + return 0; + } +} diff --git a/support/temp_file-internal.h b/support/temp_file-internal.h new file mode 100644 index 0000000000..1da9c4f82e --- /dev/null +++ b/support/temp_file-internal.h @@ -0,0 +1,31 @@ +/* Internal weak declarations for temporary file handling. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#ifndef SUPPORT_TEMP_FILE_INTERNAL_H +#define SUPPORT_TEMP_FILE_INTERNAL_H + +/* These functions are called by the test driver if they are + defined. Tests should not call them directly. */ + +#include + +void support_set_test_dir (const char *name) __attribute__ ((weak)); +void support_delete_temp_files (void) __attribute__ ((weak)); +void support_print_temp_files (FILE *) __attribute__ ((weak)); + +#endif /* SUPPORT_TEMP_FILE_INTERNAL_H */ diff --git a/support/temp_file.c b/support/temp_file.c new file mode 100644 index 0000000000..a67ab0bc95 --- /dev/null +++ b/support/temp_file.c @@ -0,0 +1,125 @@ +/* Temporary file handling for tests. + Copyright (C) 1998-2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +/* This is required to get an mkstemp which can create large files on + some 32-bit platforms. */ +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include + +#include +#include +#include +#include +#include + +/* List of temporary files. */ +static struct temp_name_list +{ + struct qelem q; + char *name; +} *temp_name_list; + +/* Location of the temporary files. Set by the test skeleton via + support_set_test_dir. The string is not be freed. */ +static const char *test_dir = _PATH_TMP; + +void +add_temp_file (const char *name) +{ + struct temp_name_list *newp + = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); + char *newname = strdup (name); + if (newname != NULL) + { + 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); +} + +int +create_temp_file (const char *base, char **filename) +{ + char *fname; + int fd; + + fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) + + sizeof ("XXXXXX")); + strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); + + fd = mkstemp (fname); + if (fd == -1) + { + printf ("cannot open temporary file '%s': %m\n", fname); + free (fname); + return -1; + } + + add_temp_file (fname); + if (filename != NULL) + *filename = fname; + else + free (fname); + + return fd; +} + +/* Helper functions called by the test skeleton follow. */ + +void +support_set_test_dir (const char *path) +{ + test_dir = path; +} + +void +support_delete_temp_files (void) +{ + while (temp_name_list != NULL) + { + remove (temp_name_list->name); + 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; + } +} + +void +support_print_temp_files (FILE *f) +{ + if (temp_name_list != NULL) + { + struct temp_name_list *n; + fprintf (f, "temp_files=(\n"); + for (n = temp_name_list; + n != NULL; + n = (struct temp_name_list *) n->q.q_forw) + fprintf (f, " '%s'\n", n->name); + fprintf (f, ")\n"); + } +} diff --git a/support/temp_file.h b/support/temp_file.h new file mode 100644 index 0000000000..1955f7b539 --- /dev/null +++ b/support/temp_file.h @@ -0,0 +1,37 @@ +/* Declarations for temporary file handling. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#ifndef SUPPORT_TEMP_FILE_H +#define SUPPORT_TEMP_FILE_H + +#include + +__BEGIN_DECLS + +/* Schedule a temporary file for deletion on exit. */ +void add_temp_file (const char *name); + +/* 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. */ +int create_temp_file (const char *base, char **filename); + +__END_DECLS + +#endif /* SUPPORT_TEMP_FILE_H */ diff --git a/support/test-driver.c b/support/test-driver.c new file mode 100644 index 0000000000..3a61b7bf3f --- /dev/null +++ b/support/test-driver.c @@ -0,0 +1,158 @@ +/* Main function for test programs. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +/* This file should be included from test cases. It will define a + main function which provides the test wrapper. + + It assumes that the test case defines a function + + int do_test (void); + + and arranges for that function being called under the test wrapper. + The do_test function should return 0 to indicate a passing test, 1 + to indicate a failing test, or 77 to indicate an unsupported test. + Other result values could be used to indicate a failing test, but + the result of the expression is passed to exit and exit only + returns the lower 8 bits of its input. A non-zero return with some + values could cause a test to incorrectly be considered passing when + it really failed. For this reason, the function should always + return 0 (EXIT_SUCCESS), 1 (EXIT_FAILURE), or 77 + (EXIT_UNSUPPORTED). + + The test function may print out diagnostic or warning messages as well + as messages about failures. These messages should be printed to stdout + and not stderr so that the output is properly ordered with respect to + the rest of the glibc testsuite run output. + + Several preprocessors macros can be defined before including this + file. + + The name of the do_test function can be changed with the + TEST_FUNCTION macro. It must expand to the desired function name. + + If the test case needs access to command line parameters, it must + define the TEST_FUNCTION_ARGV macro with the name of the test + function. It must have the following type: + + int TEST_FUNCTION_ARGV (int argc, char **argv); + + This overrides the do_test default function and is incompatible + with the TEST_FUNCTION macro. + + If PREPARE is defined, it must expand to the name of a function of + the type + + void PREPARE (int argc, char **); + + This function will be called early, after parsing the command line, + but before running the test, in the parent process which acts as + the test supervisor. + + If CLEANUP_HANDLER is defined, it must expand to the name of a + function of the type + + void CLEANUP_HANDLER (void); + + This function will be called from the timeout (SIGALRM) signal + handler. + + If EXPECTED_SIGNAL is defined, it must expanded to a constant which + denotes the expected signal number. + + If EXPECTED_STATUS is defined, it must expand to the expected exit + status. + + If TIMEOUT is defined, it must be positive constant. It overrides + the default test timeout and is measured in seconds. + + If TEST_NO_MALLOPT is defined, the test wrapper will not call + mallopt. + + Custom command line handling can be implemented by defining the + CMDLINE_OPTION macro (after including the header; this + requires _GNU_SOURCE to be defined). This macro must expand to a + to a comma-separated list of braced initializers for struct option + from , with a trailing comma. CMDLINE_PROCESS can be + defined as the name of a function which is called to process these + options. The function is passed the option character/number and + has this type: + + void CMDLINE_PROCESS (int); +*/ + +#include + +#include + +int +main (int argc, char **argv) +{ + struct test_config test_config; + memset (&test_config, 0, sizeof (test_config)); + +#ifdef PREPARE + test_config.prepare_function = (PREPARE); +#endif + +#if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV) +# error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time +#endif +#if defined (TEST_FUNCTION) + test_config.test_function = TEST_FUNCTION; +#elif defined (TEST_FUNCTION_ARGV) + test_config.test_function_argv = TEST_FUNCTION_ARGV; +#else + test_config.test_function = do_test; +#endif + +#ifdef CLEANUP_HANDLER + test_config.cleanup_function = CLEANUP_HANDLER; +#endif + +#ifdef EXPECTED_SIGNAL + test_config.expected_signal = (EXPECTED_SIGNAL); +#endif + +#ifdef EXPECTED_STATUS + test_config.expected_status = (EXPECTED_STATUS); +#endif + +#ifdef TEST_NO_MALLOPT + test_config.no_mallopt = 1; +#endif + +#ifdef TIMEOUT + test_config.timeout = TIMEOUT; +#endif + +#ifdef CMDLINE_OPTIONS + struct option options[] = + { + CMDLINE_OPTIONS + { "direct", no_argument, NULL, OPT_DIRECT }, + { "test-dir", required_argument, NULL, OPT_TESTDIR }, + { NULL, 0, NULL, 0 } + }; + test_config.options = &options; +#endif +#ifdef CMDLINE_PROCESS + test_config.cmdline_function = CMDLINE_PROCESS; +#endif + + return support_test_main (argc, argv, &test_config); +} diff --git a/support/test-driver.h b/support/test-driver.h new file mode 100644 index 0000000000..7787e9c4ff --- /dev/null +++ b/support/test-driver.h @@ -0,0 +1,68 @@ +/* Interfaces for the test driver. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#ifndef SUPPORT_TEST_DRIVER_H +#define SUPPORT_TEST_DRIVER_H + +#include + +__BEGIN_DECLS + +struct test_config +{ + void (*prepare_function) (int argc, char **argv); + int (*test_function) (void); + int (*test_function_argv) (int argc, char **argv); + void (*cleanup_function) (void); + void (*cmdline_function) (int); + const void *options; /* Custom options if not NULL. */ + int timeout; /* Test timeout in seconds. */ + int expected_status; /* Expected exit status. */ + int expected_signal; /* If non-zero, expect termination by signal. */ + char no_mallopt; /* Boolean flag to disable mallopt. */ +}; + +enum + { + /* Test exit status which indicates that the feature is + unsupported. */ + EXIT_UNSUPPORTED = 77, + + /* Default timeout is twenty seconds. Tests should normally + complete faster than this, but if they don't, that's abnormal + (a bug) anyways. */ + DEFAULT_TIMEOUT = 20, + + /* Used for command line argument parsing. */ + OPT_DIRECT = 1000, + OPT_TESTDIR, + }; + +/* Options provided by the test driver. */ +#define TEST_DEFAULT_OPTIONS \ + { "direct", no_argument, NULL, OPT_DIRECT }, \ + { "test-dir", required_argument, NULL, OPT_TESTDIR }, \ + +/* The directory the test should use for temporary files. */ +extern const char *test_dir; + +int support_test_main (int argc, char **argv, const struct test_config *); + +__END_DECLS + +#endif /* SUPPORT_TEST_DRIVER_H */ diff --git a/support/write_message.c b/support/write_message.c new file mode 100644 index 0000000000..be145e741a --- /dev/null +++ b/support/write_message.c @@ -0,0 +1,29 @@ +/* Write a message to standard output. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include + +void +write_message (const char *message) +{ + ssize_t unused __attribute__ ((unused)); + unused = write (STDOUT_FILENO, message, strlen (message)); +} diff --git a/support/xasprintf.c b/support/xasprintf.c new file mode 100644 index 0000000000..b9dc91ba4f --- /dev/null +++ b/support/xasprintf.c @@ -0,0 +1,38 @@ +/* Error-checking wrapper for asprintf. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include + +char * +xasprintf (const char *format, ...) +{ + va_list ap; + va_start (ap, format); + char *result; + if (vasprintf (&result, format, ap) < 0) + { + printf ("error: asprintf: %m\n"); + exit (1); + } + va_end (ap); + return result; +} diff --git a/support/xcalloc.c b/support/xcalloc.c new file mode 100644 index 0000000000..0ba5061295 --- /dev/null +++ b/support/xcalloc.c @@ -0,0 +1,34 @@ +/* Error-checking wrapper for calloc. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include + +void * +xcalloc (size_t n, size_t s) +{ + void *p; + + p = calloc (n, s); + if (p == NULL) + oom_error ("calloc", n * s); + return p; +} diff --git a/support/xmalloc.c b/support/xmalloc.c new file mode 100644 index 0000000000..8b0fc62f87 --- /dev/null +++ b/support/xmalloc.c @@ -0,0 +1,34 @@ +/* Error-checking wrapper for malloc. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include + +void * +xmalloc (size_t n) +{ + void *p; + + p = malloc (n); + if (p == NULL) + oom_error ("malloc", n); + return p; +} diff --git a/support/xpthread_barrier_destroy.c b/support/xpthread_barrier_destroy.c new file mode 100644 index 0000000000..f9ce97c93a --- /dev/null +++ b/support/xpthread_barrier_destroy.c @@ -0,0 +1,26 @@ +/* pthread_barrier_destroy with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_barrier_destroy (pthread_barrier_t *barrier) +{ + xpthread_check_return ("pthread_barrier_destroy", + pthread_barrier_destroy (barrier)); +} diff --git a/support/xpthread_barrier_init.c b/support/xpthread_barrier_init.c new file mode 100644 index 0000000000..1eba8c904e --- /dev/null +++ b/support/xpthread_barrier_init.c @@ -0,0 +1,27 @@ +/* pthread_barrier_init with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_barrier_init (pthread_barrier_t *barrier, + pthread_barrierattr_t *attr, unsigned int count) +{ + xpthread_check_return ("pthread_barrier_init", + pthread_barrier_init (barrier, attr, count)); +} diff --git a/support/xpthread_barrier_wait.c b/support/xpthread_barrier_wait.c new file mode 100644 index 0000000000..45139f4a89 --- /dev/null +++ b/support/xpthread_barrier_wait.c @@ -0,0 +1,28 @@ +/* pthread_barrier_wait with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +int +xpthread_barrier_wait (pthread_barrier_t *barrier) +{ + int ret = pthread_barrier_wait (barrier); + if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) + xpthread_check_return ("pthread_barrier_wait", ret); + return ret == PTHREAD_BARRIER_SERIAL_THREAD; +} diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c new file mode 100644 index 0000000000..dfbcf68079 --- /dev/null +++ b/support/xpthread_cancel.c @@ -0,0 +1,25 @@ +/* pthread_cancel with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_cancel (pthread_t thr) +{ + xpthread_check_return ("pthread_cancel", pthread_cancel (thr)); +} diff --git a/support/xpthread_check_return.c b/support/xpthread_check_return.c new file mode 100644 index 0000000000..8781ee11a1 --- /dev/null +++ b/support/xpthread_check_return.c @@ -0,0 +1,34 @@ +/* Return value checking for pthread functions, exit variant. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include + +void +xpthread_check_return (const char *function, int value) +{ + if (value != 0) + { + errno = value; + printf ("error: %s: %m\n", function); + exit (1); + } +} diff --git a/support/xpthread_cond_wait.c b/support/xpthread_cond_wait.c new file mode 100644 index 0000000000..844ae588ee --- /dev/null +++ b/support/xpthread_cond_wait.c @@ -0,0 +1,26 @@ +/* pthread_cond_wait with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + xpthread_check_return + ("pthread_cond_wait", pthread_cond_wait (cond, mutex)); +} diff --git a/support/xpthread_create.c b/support/xpthread_create.c new file mode 100644 index 0000000000..96d2d09928 --- /dev/null +++ b/support/xpthread_create.c @@ -0,0 +1,29 @@ +/* pthread_create with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +pthread_t +xpthread_create (pthread_attr_t *attr, + void *(*thread_func) (void *), void *closure) +{ + pthread_t thr; + xpthread_check_return + ("pthread_create", pthread_create (&thr, attr, thread_func, closure)); + return thr; +} diff --git a/support/xpthread_detach.c b/support/xpthread_detach.c new file mode 100644 index 0000000000..971cb72dea --- /dev/null +++ b/support/xpthread_detach.c @@ -0,0 +1,25 @@ +/* pthread_detach with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_detach (pthread_t thr) +{ + xpthread_check_return ("pthread_detach", pthread_detach (thr)); +} diff --git a/support/xpthread_join.c b/support/xpthread_join.c new file mode 100644 index 0000000000..1ab8620fb2 --- /dev/null +++ b/support/xpthread_join.c @@ -0,0 +1,27 @@ +/* pthread_join with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void * +xpthread_join (pthread_t thr) +{ + void *result; + xpthread_check_return ("pthread_join", pthread_join (thr, &result)); + return result; +} diff --git a/support/xpthread_mutex_lock.c b/support/xpthread_mutex_lock.c new file mode 100644 index 0000000000..3a72cabf90 --- /dev/null +++ b/support/xpthread_mutex_lock.c @@ -0,0 +1,25 @@ +/* pthread_mutex_lock with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_mutex_lock (pthread_mutex_t *mutex) +{ + xpthread_check_return ("pthread_mutex_lock", pthread_mutex_lock (mutex)); +} diff --git a/support/xpthread_mutex_unlock.c b/support/xpthread_mutex_unlock.c new file mode 100644 index 0000000000..640bf31582 --- /dev/null +++ b/support/xpthread_mutex_unlock.c @@ -0,0 +1,25 @@ +/* pthread_mutex_unlock with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_mutex_unlock (pthread_mutex_t *mutex) +{ + xpthread_check_return ("pthread_mutex_unlock", pthread_mutex_unlock (mutex)); +} diff --git a/support/xpthread_sigmask.c b/support/xpthread_sigmask.c new file mode 100644 index 0000000000..6a938c8a40 --- /dev/null +++ b/support/xpthread_sigmask.c @@ -0,0 +1,34 @@ +/* pthread_sigmask with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include +#include + +#include + +void +xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset) +{ + if (pthread_sigmask (how, set, oldset) != 0) + { + write_message ("error: pthread_setmask failed\n"); + /* Do not use exit because pthread_sigmask can be called from a + signal handler. */ + _exit (1); + } +} diff --git a/support/xpthread_spin_lock.c b/support/xpthread_spin_lock.c new file mode 100644 index 0000000000..3e7b0b843b --- /dev/null +++ b/support/xpthread_spin_lock.c @@ -0,0 +1,25 @@ +/* pthread_spin_lock with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_spin_lock (pthread_spinlock_t *lock) +{ + xpthread_check_return ("pthread_spin_lock", pthread_spin_lock (lock)); +} diff --git a/support/xpthread_spin_unlock.c b/support/xpthread_spin_unlock.c new file mode 100644 index 0000000000..7a5047b531 --- /dev/null +++ b/support/xpthread_spin_unlock.c @@ -0,0 +1,25 @@ +/* pthread_spin_unlock with error checking. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +void +xpthread_spin_unlock (pthread_spinlock_t *lock) +{ + xpthread_check_return ("pthread_spin_unlock", pthread_spin_unlock (lock)); +} diff --git a/support/xrealloc.c b/support/xrealloc.c new file mode 100644 index 0000000000..6c5a5a3d04 --- /dev/null +++ b/support/xrealloc.c @@ -0,0 +1,32 @@ +/* Error-checking wrapper for realloc. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#include + +#include +#include +#include + +void * +xrealloc (void *p, size_t n) +{ + void *result = realloc (p, n); + if (result == NULL && (n > 0 || p == NULL)) + oom_error ("realloc", n); + return result; +} diff --git a/support/xsignal.h b/support/xsignal.h new file mode 100644 index 0000000000..b10521484c --- /dev/null +++ b/support/xsignal.h @@ -0,0 +1,34 @@ +/* Support functionality for using signals. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#ifndef SUPPORT_SIGNAL_H +#define SUPPORT_SIGNAL_H + +#include +#include + +__BEGIN_DECLS + +/* The following functions call the corresponding libpthread functions + and terminate the process on error. */ + +void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset); + +__END_DECLS + +#endif /* SUPPORT_SIGNAL_H */ diff --git a/support/xthread.h b/support/xthread.h new file mode 100644 index 0000000000..f0dc0fa613 --- /dev/null +++ b/support/xthread.h @@ -0,0 +1,61 @@ +/* Support functionality for using threads. + Copyright (C) 2016 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + 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, see + . */ + +#ifndef SUPPORT_THREAD_H +#define SUPPORT_THREAD_H + +#include +#include + +__BEGIN_DECLS + +/* Terminate the process (with exit status 0) after SECONDS have + elapsed, from a helper thread. The process is terminated with the + exit function, so atexit handlers are executed. */ +void delayed_exit (int seconds); + +/* Terminate the process (with exit status 1) if VALUE is not zero. + In that case, print a failure message to standard output mentioning + FUNCTION. The process is terminated with the exit function, so + atexit handlers are executed. */ +void xpthread_check_return (const char *function, int value); + +/* The following functions call the corresponding libpthread functions + and terminate the process on error. */ + +void xpthread_barrier_init (pthread_barrier_t *barrier, + pthread_barrierattr_t *attr, unsigned int count); +void xpthread_barrier_destroy (pthread_barrier_t *barrier); +void xpthread_mutex_lock (pthread_mutex_t *mutex); +void xpthread_mutex_unlock (pthread_mutex_t *mutex); +void xpthread_spin_lock (pthread_spinlock_t *lock); +void xpthread_spin_unlock (pthread_spinlock_t *lock); +void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); +pthread_t xpthread_create (pthread_attr_t *attr, + void *(*thread_func) (void *), void *closure); +void xpthread_detach (pthread_t thr); +void xpthread_cancel (pthread_t thr); +void *xpthread_join (pthread_t thr); + +/* This function returns non-zero if pthread_barrier_wait returned + PTHREAD_BARRIER_SERIAL_THREAD. */ +int xpthread_barrier_wait (pthread_barrier_t *barrier); + +__END_DECLS + +#endif /* SUPPORT_THREAD_H */ diff --git a/sysdeps/unix/sysv/linux/tst-fallocate-common.c b/sysdeps/unix/sysv/linux/tst-fallocate-common.c index d98bf4a3e6..590b7a813c 100644 --- a/sysdeps/unix/sysv/linux/tst-fallocate-common.c +++ b/sysdeps/unix/sysv/linux/tst-fallocate-common.c @@ -16,33 +16,33 @@ License along with the GNU C Library; if not, see . */ +#include #include -#include +#include +#include +#include #include +#include #include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#define TIMEOUT 20 /* sec. */ +#include +#include +#include #define XSTR(s) STR(S) #define STR(s) #s -#include - static char *temp_filename; static int temp_fd; -void -do_prepare (void) +static void +do_prepare (int argc, char **argv) { temp_fd = create_temp_file ("tst-fallocate.", &temp_filename); if (temp_fd == -1) FAIL_EXIT1 ("cannot create temporary file: %m"); } +#define PREPARE do_prepare static int do_test_with_offset (off_t offset) @@ -91,3 +91,8 @@ do_test_with_offset (off_t offset) return 0; } + +/* This function is defined by the individual tests. */ +static int do_test (void); + +#include diff --git a/sysdeps/unix/sysv/linux/tst-sync_file_range.c b/sysdeps/unix/sysv/linux/tst-sync_file_range.c index 499a234e00..f2e5615fa9 100644 --- a/sysdeps/unix/sysv/linux/tst-sync_file_range.c +++ b/sysdeps/unix/sysv/linux/tst-sync_file_range.c @@ -18,21 +18,18 @@ /* sync_file_range is only define for LFS. */ #define _FILE_OFFSET_BITS 64 -#include #include +#include +#include +#include +#include -static void do_prepare (void); -#define PREPARE(argc, argv) do_prepare () -static int do_test (void); -#define TEST_FUNCTION do_test () - -#define TIMEOUT 20 /* sec. */ +#include +#include #define XSTR(s) STR(S) #define STR(s) #s -#include - static char *temp_filename; static int temp_fd; @@ -40,7 +37,7 @@ static char fifoname[] = "/tmp/tst-posix_fadvise-fifo-XXXXXX"; static int fifofd; void -do_prepare (void) +do_prepare (int argc, char **argv) { temp_fd = create_temp_file ("tst-file_sync_range.", &temp_filename); if (temp_fd == -1) @@ -57,6 +54,7 @@ do_prepare (void) if (fifofd == -1) FAIL_EXIT1 ("cannot open fifo: %m"); } +#define PREPARE do_prepare static int do_test (void) @@ -129,3 +127,5 @@ do_test (void) return 0; } + +#include diff --git a/test-skeleton.c b/test-skeleton.c index 154096fd8e..55ded17cab 100644 --- a/test-skeleton.c +++ b/test-skeleton.c @@ -1,4 +1,4 @@ -/* Skeleton for test programs. +/* Legacy test skeleton. Copyright (C) 1998-2016 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1998. @@ -17,6 +17,13 @@ License along with the GNU C Library; if not, see . */ +/* This test skeleton is to support running existing tests. New tests + should use instead; see the documentation + in that file for instructions, and for a + minimal example. */ + +/* This list of headers is needed so that tests which include + "../test-skeleton.c" at the beginning still compile. */ #include #include #include @@ -35,733 +42,67 @@ #include #include -/* The test function is normally called `do_test' and it is called - with argc and argv as the arguments. We nevertheless provide the - possibility to overwrite this name. +#include +#include +#include +#include - The TEST_FUNCTION expression should have a type of 'int' and should - return 0 to indicate a passing test, 1 to indicate a failing test, - or 77 to indicate an unsupported test. Other result values could be - used to indicate a failing test, but the result of the expression - is passed to exit and exit only returns the lower 8 bits of its input. - A non-zero return with some values could cause a test to incorrectly - be considered passing when it really failed. For this reason the - expression should always return 0, 1, or 77. - - The test function may print out diagnostic or warning messages as well - as messages about failures. These messages should be printed to stdout - and not stderr so that the output is properly ordered with respect to - the rest of the glibc testsuite run output. */ - -#ifndef TEST_FUNCTION -# define TEST_FUNCTION do_test (argc, argv) -#endif - -#ifndef TEST_DATA_LIMIT -# define TEST_DATA_LIMIT (64 << 20) /* Data limit (bytes) to run with. */ -#endif - -#ifndef TIMEOUT - /* Default timeout is twenty seconds. Tests should normally complete faster - than this, but if they don't, that's abnormal (a bug) anyways. */ -# define TIMEOUT 20 -#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; - -/* Directory to place temporary files in. */ -static const char *test_dir; - -#define _FAIL(...) \ - printf ("error: %s:%d: ", __FILE__, __LINE__); \ - printf (__VA_ARGS__); \ - printf ("\n"); \ - -#define FAIL_RET(...) \ - ({ \ - _FAIL (__VA_ARGS__); \ - return 1; \ - }) - -#define FAIL_EXIT(value, ...) \ - ({ \ - _FAIL (__VA_ARGS__); \ - exit (value); \ - }) - -#define FAIL_EXIT1(...) FAIL_EXIT(1, __VA_ARGS__) - -static void -oom_error (const char *fn, size_t size) -{ - printf ("%s: unable to allocate %zu bytes: %m\n", fn, size); - exit (1); -} - -/* Allocate N bytes of memory dynamically, with error checking. */ -__attribute__ ((unused)) -static void * -xmalloc (size_t n) -{ - void *p; - - p = malloc (n); - if (p == NULL) - oom_error ("malloc", n); - return p; -} - -/* Allocate memory for N elements of S bytes, with error checking. */ -__attribute__ ((unused)) -static void * -xcalloc (size_t n, size_t s) -{ - void *p; - - p = calloc (n, s); - if (p == NULL) - oom_error ("calloc", n * s); - return p; -} - -/* Change the size of an allocated block of memory P to N bytes, - with error checking. */ -__attribute__ ((unused)) -static void * -xrealloc (void *p, size_t n) -{ - void *result = realloc (p, n); - if (result == NULL && (n > 0 || p == NULL)) - oom_error ("realloc", n); - return result; -} - -/* Call asprintf with error checking. */ -__attribute__ ((always_inline, format (printf, 1, 2))) -static __inline__ char * -xasprintf (const char *format, ...) -{ - char *result; - if (asprintf (&result, format, __builtin_va_arg_pack ()) < 0) - { - printf ("error: asprintf: %m\n"); - exit (1); - } - return result; -} - -/* Write a message to standard output. Can be used in signal - handlers. */ -static void -__attribute__ ((unused)) -write_message (const char *message) -{ - ssize_t unused __attribute__ ((unused)); - unused = write (STDOUT_FILENO, message, strlen (message)); -} - -/* List of temporary files. */ -struct temp_name_list -{ - struct qelem q; - char *name; -} *temp_name_list; - -/* Add temporary files in list. */ -static void -__attribute__ ((unused)) -add_temp_file (const char *name) -{ - struct temp_name_list *newp - = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); - char *newname = strdup (name); - if (newname != NULL) - { - 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. */ -static void -delete_temp_files (void) -{ - while (temp_name_list != NULL) - { - remove (temp_name_list->name); - 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. 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. */ +/* TEST_FUNCTION is no longer used. */ static int -__attribute__ ((unused)) -create_temp_file (const char *base, char **filename) +legacy_test_function (int argc __attribute__ ((unused)), + char **argv __attribute__ ((unused))) { - char *fname; - int fd; - - fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) - + sizeof ("XXXXXX")); - strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); - - fd = mkstemp (fname); - if (fd == -1) - { - printf ("cannot open temporary file '%s': %m\n", fname); - free (fname); - return -1; - } - - add_temp_file (fname); - if (filename != NULL) - *filename = fname; - else - free (fname); - - return fd; -} - -/* Timeout handler. We kill the child and exit with an error. */ -static void -__attribute__ ((noreturn)) -signal_handler (int sig __attribute__ ((unused))) -{ - int killed; - int status; - - 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) - { - killed = waitpid (pid, &status, WNOHANG|WUNTRACED); - if (killed != 0) - break; - - /* Delay, give the system time to process the kill. If the - nanosleep() call return prematurely, all the better. We - won't restart it since this probably means the child process - finally died. */ - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = 100000000; - nanosleep (&ts, NULL); - } - if (killed != 0 && killed != pid) - { - printf ("Failed to kill test process: %m\n"); - exit (1); - } - -#ifdef CLEANUP_HANDLER - CLEANUP_HANDLER; +#ifdef TEST_FUNCTION + return TEST_FUNCTION; +# undef TEST_FUNCTION +#else + return do_test (argc, argv); #endif - - if (sig == SIGINT) - { - signal (sig, SIG_DFL); - raise (sig); - } - - /* If we expected this signal: good! */ -#ifdef EXPECTED_SIGNAL - if (EXPECTED_SIGNAL == SIGALRM) - exit (0); -#endif - - if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) - puts ("Timed out: killed the child process"); - else if (WIFSTOPPED (status)) - printf ("Timed out: the child process was %s\n", - strsignal (WSTOPSIG (status))); - else if (WIFSIGNALED (status)) - printf ("Timed out: the child process got signal %s\n", - strsignal (WTERMSIG (status))); - else - printf ("Timed out: killed the child process but it exited %d\n", - WEXITSTATUS (status)); - - /* Exit with an error. */ - exit (1); } +#define TEST_FUNCTION_ARGV legacy_test_function -/* Avoid all the buffer overflow messages on stderr. */ -static void -__attribute__ ((unused)) -ignore_stderr (void) -{ - int fd = open (_PATH_DEVNULL, O_WRONLY); - if (fd == -1) - close (STDERR_FILENO); - else - { - dup2 (fd, STDERR_FILENO); - close (fd); - } - setenv ("LIBC_FATAL_STDERR_", "1", 1); -} - -/* Set fortification error handler. Used when tests want to verify that bad - code is caught by the library. */ -static void -__attribute__ ((unused)) -set_fortify_handler (void (*handler) (int sig)) -{ - struct sigaction sa; - - sa.sa_handler = handler; - sa.sa_flags = 0; - sigemptyset (&sa.sa_mask); - - sigaction (SIGABRT, &sa, NULL); - ignore_stderr (); -} - -/* Show people how to run the program. */ -static void -usage (void) -{ - size_t i; - - printf ("Usage: %s [options]\n" - "\n" - "Environment Variables:\n" - " TIMEOUTFACTOR An integer used to scale the timeout\n" - " TMPDIR Where to place temporary files\n" - "\n", - program_invocation_short_name); - printf ("Options:\n"); - for (i = 0; options[i].name; ++i) - { - int indent; - - indent = printf (" --%s", options[i].name); - if (options[i].has_arg == required_argument) - indent += printf (" "); - printf ("%*s", 25 - indent, ""); - switch (options[i].val) - { - case OPT_DIRECT: - printf ("Run the test directly (instead of forking & monitoring)"); - break; - case OPT_TESTDIR: - printf ("Override the TMPDIR env var"); - break; - } - printf ("\n"); - } -} - -/* We provide the entry point here. */ -int -main (int argc, char *argv[]) -{ - int direct = 0; /* Directly call the test function? */ - int status; - int opt; - unsigned int timeoutfactor = 1; - pid_t termpid; - -#ifndef TEST_NO_MALLOPT - /* Make uses of freed and uninitialized memory known. */ - mallopt (M_PERTURB, 42); -#endif - -#ifdef STDOUT_UNBUFFERED - setbuf (stdout, NULL); -#endif - - while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) - switch (opt) - { - case '?': - usage (); - exit (1); - case OPT_DIRECT: - direct = 1; - break; - case OPT_TESTDIR: - test_dir = optarg; - break; -#ifdef CMDLINE_PROCESS - CMDLINE_PROCESS -#endif - } - - /* 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"); - if (envstr_timeoutfactor != NULL) - { - char *envstr_conv = envstr_timeoutfactor; - unsigned long int env_fact; - - env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); - if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) - timeoutfactor = MAX (env_fact, 1); - } - - /* Set TMPDIR to specified test directory. */ - if (test_dir != NULL) - { - setenv ("TMPDIR", test_dir, 1); - - if (chdir (test_dir) < 0) - { - printf ("chdir: %m\n"); - exit (1); - } - } - else - { - test_dir = getenv ("TMPDIR"); - if (test_dir == NULL || test_dir[0] == '\0') - test_dir = "/tmp"; - } - - /* Make sure we see all message, even those on stdout. */ - setvbuf (stdout, NULL, _IONBF, 0); - - /* Make sure temporary files are deleted. */ - atexit (delete_temp_files); - - /* Correct for the possible parameters. */ - argv[optind - 1] = argv[0]; - argv += optind - 1; - argc -= optind - 1; - - /* Call the initializing function, if one is available. */ +/* PREPARE is a function name in the new skeleton. */ #ifdef PREPARE +static void +legacy_prepare_function (int argc __attribute__ ((unused)), + char **argv __attribute__ ((unused))) +{ PREPARE (argc, argv); +} +# undef PREPARE +# define PREPARE legacy_prepare_function #endif - const char *envstr_direct = getenv ("TEST_DIRECT"); - if (envstr_direct != NULL) - { - FILE *f = fopen (envstr_direct, "w"); - if (f == NULL) - { - printf ("cannot open TEST_DIRECT output file '%s': %m\n", - envstr_direct); - exit (1); - } - - fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", TIMEOUT, timeoutfactor); -#ifdef EXPECTED_STATUS - fprintf (f, "exit=%u\n", EXPECTED_STATUS); -#endif -#ifdef EXPECTED_SIGNAL - switch (EXPECTED_SIGNAL) - { - default: abort (); -# define init_sig(signo, name, text) \ - case signo: fprintf (f, "signal=%s\n", name); break; -# include -# undef init_sig - } +/* CLEANUP_HANDLER is a function name in the new skeleton. */ +#ifdef CLEANUP_HANDLER +static void +legacy_cleanup_handler_function (void) +{ + CLEANUP_HANDLER; +} +# undef CLEANUP_HANDLER +# define CLEANUP_HANDLER legacy_cleanup_handler_function #endif - if (temp_name_list != NULL) - { - struct temp_name_list *n; - fprintf (f, "temp_files=(\n"); - for (n = temp_name_list; - n != NULL; - n = (struct temp_name_list *) n->q.q_forw) - fprintf (f, " '%s'\n", n->name); - fprintf (f, ")\n"); - } - - fclose (f); - direct = 1; - } - - /* If we are not expected to fork run the function immediately. */ - if (direct) - return TEST_FUNCTION; - - /* Set up the test environment: - - prevent core dumps - - set up the timer - - fork and execute the function. */ - - pid = fork (); - if (pid == 0) +/* CMDLINE_PROCESS is a function name in the new skeleton. */ +#ifdef CMDLINE_PROCESS +static void +legacy_cmdline_process_function (int c) +{ + switch (c) { - /* This is the child. */ -#ifdef RLIMIT_CORE - /* Try to avoid dumping core. */ - struct rlimit core_limit; - core_limit.rlim_cur = 0; - core_limit.rlim_max = 0; - setrlimit (RLIMIT_CORE, &core_limit); -#endif - - /* 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. */ - 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); - } - else if (pid < 0) - { - printf ("Cannot fork test program: %m\n"); - exit (1); - } - - /* Set timeout. */ - 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) - { - printf ("Waiting for test program failed: %m\n"); - exit (1); - } - if (termpid != pid) - { - printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", - (long int) pid, (long int) termpid); - exit (1); - } - - /* Process terminated normaly without timeout etc. */ - if (WIFEXITED (status)) - { -#ifndef EXPECTED_STATUS -# ifndef EXPECTED_SIGNAL - /* Simply exit with the return value of the test. */ - return WEXITSTATUS (status); -# else - printf ("Expected signal '%s' from child, got none\n", - strsignal (EXPECTED_SIGNAL)); - exit (1); -# endif -#else - if (WEXITSTATUS (status) != EXPECTED_STATUS) - { - printf ("Expected status %d, got %d\n", - EXPECTED_STATUS, WEXITSTATUS (status)); - exit (1); - } - - return 0; -#endif - } - /* Process was killed by timer or other signal. */ - else - { -#ifndef EXPECTED_SIGNAL - printf ("Didn't expect signal from child: got `%s'\n", - strsignal (WTERMSIG (status))); - exit (1); -#else - if (WTERMSIG (status) != EXPECTED_SIGNAL) - { - printf ("Incorrect signal from child: got `%s', need `%s'\n", - strsignal (WTERMSIG (status)), - strsignal (EXPECTED_SIGNAL)); - exit (1); - } - - return 0; -#endif + CMDLINE_PROCESS } } +# undef CMDLINE_PROCESS +# define CMDLINE_PROCESS legacy_cmdline_process_function +#endif + +/* Include the new test-skeleton. */ +#include /* The following functionality is only available if was included before this file. */ #ifdef _PTHREAD_H - -/* Call pthread_sigmask with error checking. */ -static void -xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset) -{ - if (pthread_sigmask (how, set, oldset) != 0) - { - write_message ("error: pthread_setmask failed\n"); - _exit (1); - } -} - -/* Call pthread_mutex_lock with error checking. */ -__attribute__ ((unused)) -static void -xpthread_mutex_lock (pthread_mutex_t *mutex) -{ - int ret = pthread_mutex_lock (mutex); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_mutex_lock: %m\n"); - exit (1); - } -} - -/* Call pthread_spin_lock with error checking. */ -__attribute__ ((unused)) -static void -xpthread_spin_lock (pthread_spinlock_t *lock) -{ - int ret = pthread_spin_lock (lock); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_spin_lock: %m\n"); - exit (1); - } -} - -/* Call pthread_cond_wait with error checking. */ -__attribute__ ((unused)) -static void -xpthread_cond_wait (pthread_cond_t * cond, - pthread_mutex_t * mutex) -{ - int ret = pthread_cond_wait (cond, mutex); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_cond_wait: %m\n"); - exit (1); - } -} - -/* Call pthread_barrier_wait with error checking. */ -__attribute__ ((unused)) -static int -xpthread_barrier_wait (pthread_barrier_t *barrier) -{ - int ret = pthread_barrier_wait (barrier); - if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) - { - errno = ret; - printf ("error: pthread_barrier_wait: %m\n"); - exit (1); - } - return ret; -} - -/* Call pthread_create with error checking. */ -static pthread_t -xpthread_create (pthread_attr_t *attr, - void *(*thread_func) (void *), void *closure) -{ - pthread_t thr; - int ret = pthread_create (&thr, attr, thread_func, closure); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_create: %m\n"); - exit (1); - } - return thr; -} - -/* Call pthread_detach with error checking. */ -static void -xpthread_detach (pthread_t thr) -{ - int ret = pthread_detach (thr); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_detach: %m\n"); - exit (1); - } -} - -/* Call pthread_join with error checking. */ -__attribute__ ((unused)) -static void * -xpthread_join (pthread_t thr) -{ - void *result; - int ret = pthread_join (thr, &result); - if (ret != 0) - { - errno = ret; - printf ("error: pthread_join: %m\n"); - exit (1); - } - return result; -} - -/* Used to implement the delayed_exit function defined below. */ -static void * -delayed_exit_thread (void *seconds_as_ptr) -{ - int seconds = (uintptr_t) seconds_as_ptr; - struct timespec delay = { seconds, 0 }; - struct timespec remaining = { 0 }; - if (nanosleep (&delay, &remaining) != 0) - { - printf ("error: nanosleep: %m\n"); - _exit (1); - } - /* Exit the process sucessfully. */ - exit (0); - return NULL; -} - -/* Exit (with status 0) after SECONDS have elapsed, from a helper - thread. The process is terminated with the exit function, so - atexit handlers are executed. */ -__attribute__ ((unused)) -static void -delayed_exit (int seconds) -{ - /* Create the new thread with all signals blocked. */ - sigset_t all_blocked; - sigfillset (&all_blocked); - sigset_t old_set; - xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); - /* Create a detached thread. */ - pthread_t thr = xpthread_create - (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); - xpthread_detach (thr); - /* Restore the original signal mask. */ - xpthread_sigmask (SIG_SETMASK, &old_set, NULL); -} - +# include #endif /* _PTHREAD_H */ diff --git a/time/bug-getdate1.c b/time/bug-getdate1.c index 3d68cf2a79..9afafba5be 100644 --- a/time/bug-getdate1.c +++ b/time/bug-getdate1.c @@ -3,6 +3,8 @@ #include #include +#include + static char *templ_filename; // Writes template given as parameter to file, @@ -133,14 +135,18 @@ do_test (int argc, char *argv[]) return res; } +#define TEST_FUNCTION_ARGV do_test -#define PREPARE(argc, argv) \ - if (argc < 2) \ - { \ - puts ("Command line: progname template_filename_full_path"); \ - exit (1); \ - } \ - add_temp_file (argv[1]) +static void +do_prepare (int argc, char **argv) +{ + if (argc < 2) + { + puts ("Command line: progname template_filename_full_path"); + exit (1); + } + add_temp_file (argv[1]); +} +#define PREPARE do_prepare -#define TEST_FUNCTION do_test (argc, argv) -#include "../test-skeleton.c" +#include