From patchwork Mon Dec 5 15:57:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florian Weimer X-Patchwork-Id: 702765 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tXTtf4mC7z9sxS for ; Tue, 6 Dec 2016 02:58:02 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="M4Fy1pS3"; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:to:references:cc:from:message-id:date :mime-version:in-reply-to:content-type; q=dns; s=default; b=pa7x 8nNGV8Ir9j7kL2jZfd78f+NliUi3hS3f10DaTvmAT+d9+Ttsypp2/kPeLwCS8I/c jt+BuWTorCftI4bAeOgMmKIboZzxFhmXIqsEOBRTDWJTh32YqAviEZuV+GoyyO+Z lnHBGdDt+QXftHSjhgPt/9I8gabiL8vsAkZTm4I= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:subject:to:references:cc:from:message-id:date :mime-version:in-reply-to:content-type; s=default; bh=SKsVe222YW 8Jl423urm0MwW788Q=; b=M4Fy1pS33pY0Ukl/m2NM5nsmtGuu9Pf14jtFSuU97n 4WC4NtaBWROD+zggKyEgbFiWUR0G0pMe0NwGAbr11Q7pWaw4sPnQTWVbTQ9lw9n2 wytwS7rFnj/YDLx4rcVlsDAhpLrQb0saT828zrsB7qHw0haZnL1cwdX8sfzeuMc+ k= Received: (qmail 102725 invoked by alias); 5 Dec 2016 15:57:44 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 102708 invoked by uid 89); 5 Dec 2016 15:57:43 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=BAYES_50, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=ld.so, UD:ld.so, ldso, hanging X-HELO: mx1.redhat.com Subject: Re: [PATCH] support: Introduce new subdirectory for test infrastructure To: "Carlos O'Donell" , Andreas Schwab References: <425c6518-69f7-e68d-9599-d81c8c137c96@redhat.com> <14a1be0f-2b7b-56ce-ec18-dabc55c7f0d9@redhat.com> <87d1hfp5z4.fsf@linux-m68k.org> <1a112b98-f3e2-c3eb-e4e6-e0298f04aa59@redhat.com> <3a26a56b-46f3-0c45-cb01-80867d2fa610@redhat.com> Cc: GNU C Library From: Florian Weimer Message-ID: Date: Mon, 5 Dec 2016 16:57:23 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.4.0 MIME-Version: 1.0 In-Reply-To: <3a26a56b-46f3-0c45-cb01-80867d2fa610@redhat.com> On 12/02/2016 08:21 PM, Carlos O'Donell wrote: > My only subconscious fear is to stay way from anything that looks as > complicated as TET/VSXGen from the Open Group. Your additional infrastructure > is nowhere near that point, but we should be conscious of an overall design > goal which is to remain as small as possible. But we need something to view changes in subtest failures more easily. > Have you tested your changes with --enable-hardcoded-path-in-tests and made > sure nothing breaks? Ugh. There was some breakages, fixed in the attached patch. I had dropped the ld.so override accidentally. I don't see any regressions anymore. > (3) Implementation details. > > You need a README.txt which: > > * Describes the goals of the infrastructure, this will provide guidance > for what we should or should not consider adding. I think it's premature for that. > * It should also give an example minimal template for a test that users the > infrastructure. I added a dummy test for that. > * [optional] List _all_ functions that are part of the support infrastructure > in order to give a broad overview of what's available without having to > crawl all the headers. I don't like this because it will introduce additional merge conflicts while backporting new tests. I'm just listing the header files. > Notes: > > Is there any way to avoid needing to list $(libsupport) as a dependency > of the hand-built DSOs in the test framework? This is not a blocker, just > a question about how we might make it easier to use these functions from > all such DSOs without developers having to remember to add it as a dependency. I don't know where the pattern rule is located which builds test DSOs. > (b) ChangeLog typo. Fixed. > (c) Why do you set errno in xpthread_check_return? It's needed for %m. Most libpthread functions do not set errno. > (d) I noticed that the waitpid in signal_handler has a timeout that is > not in any way a function of TIMEOUTFACTOR, and it probably should be. > Nothing to do with your changes but I wanted to mention it. If you're > already refactoring and running tests it might be nice to make it > something that scales with TIMEOUTFACTOR. I'm not sure the timeout factor should apply in this case. There are non-async-signal-safe functions in there, too. If the process is stuck in a deadlock, calling exit (not _exit) from the signal handler is probably what we want to do. But I would avoid that scope creep here. > (e) xpthread_join should take a parameter "canceled" to indicate it should > verify the result of pthread_join was PTHREAD_CANCELED, and then this > should be used when refactoring to tighten up the expected cancellation > results e.g. tst-cancel7.c should be adjusted to use this. But very few callers will need this, so I don't think it makes sense. Maybe we can aim for something like this in the future: TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED); It's slightly more verbose, but you don't need to wonder what the Boolean argument to xpthread_join does. >> +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"); > > OK, but ugly IMO. I prefer a more verbose version. #bikeshed It was this way in the original. We could just use xasprintf nowadays. >> +/* This test skeleton is to support running existing tests. New tests >> + should use instead; see the documentation >> + in that file for instructions. */ > > OK. Should reference support/README.txt. I've added a reference to README-testing.c. I realized that I had to convert another test case (tst-secure-getenv). In the attached verion, I renamed signal.h to xsignal.h and thread.h to xthread.h, to avoid potential header name conflicts. Thanks, Florian support: Introduce new subdirectory for test infrastructure The new test driver in has feature parity with the old one. The main difference is that its hooking mechanism is based on functions and function pointers instead of macros. This commit also implements a new environment variable, TEST_COREDUMPS, which disables the code which disables coredumps (that is, it enables them if the invocation environment has not disabled them). defines wrapper functions so that it is possible to use existing macros with the new-style hook functionality. This commit changes only a few test cases to the new test driver, to make sure that it works as expected. 2016-12-05 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. diff --git a/Makeconfig b/Makeconfig index a785860..36fe2b4 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 endif @@ -434,7 +437,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 @@ -462,8 +466,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 endif @@ -503,7 +507,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) link-libc-tests = $(link-libc-tests-rpath-link) \ $(link-libc-before-gnulib) $(gnulib-tests) # 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 @@ -850,7 +854,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 deab96e..713e555 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 aba7720..ed33347 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 f57927f..330397e 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 b10748d..2552049 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 9242d62..23fa819 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 2f15a5d..3073ffe 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 9bb0d7f..1a81740 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 3aee7fd..1f1f0e8 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 94549ca..cdef225 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 fa6ebf9..9f92318 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 7f20862..8eff3a8 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 011e5a6..601ad73 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 bb04c61..38dc0ce 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 36fb9eb..95a4f9b 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 58208db..ce8e73c 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 0000000..bd425af --- /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 0000000..476cfcd --- /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 0000000..9d289c3 --- /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 0000000..7fe8c49 --- /dev/null +++ b/support/check.c @@ -0,0 +1,54 @@ +/* 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 0000000..ff2652c --- /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 0000000..d5b2e10 --- /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 0000000..1b35d06 --- /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 0000000..b28c5b4 --- /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 0000000..76c4a7d --- /dev/null +++ b/support/set_fortify_handler.c @@ -0,0 +1,35 @@ +/* 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 0000000..fc7fba9 --- /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 0000000..72771bf --- /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 0000000..1da9c4f --- /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 0000000..a67ab0b --- /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 0000000..1955f7b --- /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 0000000..3a61b7b --- /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 0000000..7787e9c --- /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 0000000..56d2a41 --- /dev/null +++ b/support/write_message.c @@ -0,0 +1,30 @@ +/* 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 0000000..b9dc91b --- /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 0000000..0ba5061 --- /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 0000000..8b0fc62 --- /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 0000000..f9ce97c --- /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 0000000..1eba8c9 --- /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 0000000..45139f4 --- /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 0000000..dfbcf68 --- /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 0000000..8781ee1 --- /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 0000000..844ae58 --- /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 0000000..96d2d09 --- /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 0000000..971cb72 --- /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 0000000..1ab8620 --- /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 0000000..3a72cab --- /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 0000000..640bf31 --- /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 0000000..6a938c8 --- /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 0000000..3e7b0b8 --- /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 0000000..7a5047b --- /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 0000000..6c5a5a3 --- /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 0000000..b105214 --- /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 0000000..f0dc0fa --- /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 d98bf4a..590b7a8 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 499a234..4a2dacf 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,6 @@ do_test (void) return 0; } + +#include + diff --git a/test-skeleton.c b/test-skeleton.c index 154096f..55ded17 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; +#ifdef TEST_FUNCTION + return TEST_FUNCTION; +# undef TEST_FUNCTION +#else + return do_test (argc, argv); +#endif } +#define TEST_FUNCTION_ARGV legacy_test_function -/* Timeout handler. We kill the child and exit with an error. */ +/* PREPARE is a function name in the new skeleton. */ +#ifdef PREPARE static void -__attribute__ ((noreturn)) -signal_handler (int sig __attribute__ ((unused))) +legacy_prepare_function (int argc __attribute__ ((unused)), + char **argv __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); - } + PREPARE (argc, argv); +} +# undef PREPARE +# define PREPARE legacy_prepare_function +#endif +/* CLEANUP_HANDLER is a function name in the new skeleton. */ #ifdef CLEANUP_HANDLER +static void +legacy_cleanup_handler_function (void) +{ CLEANUP_HANDLER; -#endif - - if (sig == SIGINT) - { - signal (sig, SIG_DFL); - raise (sig); - } - - /* If we expected this signal: good! */ -#ifdef EXPECTED_SIGNAL - if (EXPECTED_SIGNAL == SIGALRM) - 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); -} - -/* 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); +# undef CLEANUP_HANDLER +# define CLEANUP_HANDLER legacy_cleanup_handler_function #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; +/* CMDLINE_PROCESS is a function name in the new skeleton. */ #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) +static void +legacy_cmdline_process_function (int c) +{ + switch (c) { - 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. */ -#ifdef PREPARE - PREPARE (argc, argv); -#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 - } -#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) - { - /* 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 3d68cf2..9afafba 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