From 447c70a5dc04e85f96c2ae477ce851fdfdd8c719 Mon Sep 17 00:00:00 2001 From: Salvatore Cro Date: Fri, 10 Sep 2010 10:55:43 +0200 Subject: tests: Added new nptl tests tests: Added several nptl tests from glibc 2.10.1 Signed-off-by: Salvatore Cro Signed-off-by: Carmelo Amoroso --- test/nptl/Makefile.in | 70 +- test/nptl/tst-align3.c | 57 + test/nptl/tst-basic7.c | 75 ++ test/nptl/tst-cancel18.c | 174 +++ test/nptl/tst-cancel23.c | 1 + test/nptl/tst-cancel25.c | 171 +++ test/nptl/tst-cancel4.c | 2374 +++++++++++++++++++++++++++++++++++ test/nptl/tst-cancel5.c | 1 + test/nptl/tst-cancelx10.c | 1 + test/nptl/tst-cancelx11.c | 1 + test/nptl/tst-cancelx12.c | 1 + test/nptl/tst-cancelx13.c | 1 + test/nptl/tst-cancelx14.c | 1 + test/nptl/tst-cancelx15.c | 1 + test/nptl/tst-cancelx16.c | 1 + test/nptl/tst-cancelx18.c | 1 + test/nptl/tst-cancelx2.c | 1 + test/nptl/tst-cancelx20.c | 1 + test/nptl/tst-cancelx21.c | 1 + test/nptl/tst-cancelx3.c | 1 + test/nptl/tst-cancelx4.c | 1 + test/nptl/tst-cancelx6.c | 1 + test/nptl/tst-cancelx7.c | 1 + test/nptl/tst-cancelx8.c | 1 + test/nptl/tst-cancelx9.c | 1 + test/nptl/tst-cleanupx0.c | 1 + test/nptl/tst-cleanupx1.c | 1 + test/nptl/tst-cleanupx2.c | 1 + test/nptl/tst-cleanupx3.c | 1 + test/nptl/tst-cleanupx4.c | 1 + test/nptl/tst-cond22.c | 160 +++ test/nptl/tst-cond23.c | 184 +++ test/nptl/tst-dlsym1.c | 66 + test/nptl/tst-fini1.c | 35 + test/nptl/tst-fini1mod.c | 72 ++ test/nptl/tst-getpid1.c | 122 ++ test/nptl/tst-getpid2.c | 2 + test/nptl/tst-getpid3.c | 114 ++ test/nptl/tst-initializers1-c89.c | 1 + test/nptl/tst-initializers1-c99.c | 1 + test/nptl/tst-initializers1-gnu89.c | 1 + test/nptl/tst-initializers1-gnu99.c | 1 + test/nptl/tst-join6.c | 2 + test/nptl/tst-oddstacklimit.c | 1 + test/nptl/tst-oncex3.c | 1 + test/nptl/tst-oncex4.c | 1 + test/nptl/tst-rwlock2a.c | 2 + test/nptl/tst-sem10.c | 88 ++ test/nptl/tst-sem11.c | 76 ++ test/nptl/tst-sem12.c | 14 + test/nptl/tst-signal7.c | 59 + test/nptl/tst-tsd6.c | 89 ++ test/nptl/tst-typesizes.c | 96 ++ test/nptl/tst-unload.c | 47 + test/nptl/tst-vfork1.c | 150 +++ test/nptl/tst-vfork1x.c | 150 +++ test/nptl/tst-vfork2.c | 199 +++ test/nptl/tst-vfork2x.c | 199 +++ 58 files changed, 4877 insertions(+), 1 deletion(-) create mode 100644 test/nptl/tst-align3.c create mode 100644 test/nptl/tst-basic7.c create mode 100644 test/nptl/tst-cancel18.c create mode 100644 test/nptl/tst-cancel23.c create mode 100644 test/nptl/tst-cancel25.c create mode 100644 test/nptl/tst-cancel4.c create mode 100644 test/nptl/tst-cancel5.c create mode 100644 test/nptl/tst-cancelx10.c create mode 100644 test/nptl/tst-cancelx11.c create mode 100644 test/nptl/tst-cancelx12.c create mode 100644 test/nptl/tst-cancelx13.c create mode 100644 test/nptl/tst-cancelx14.c create mode 100644 test/nptl/tst-cancelx15.c create mode 100644 test/nptl/tst-cancelx16.c create mode 100644 test/nptl/tst-cancelx18.c create mode 100644 test/nptl/tst-cancelx2.c create mode 100644 test/nptl/tst-cancelx20.c create mode 100644 test/nptl/tst-cancelx21.c create mode 100644 test/nptl/tst-cancelx3.c create mode 100644 test/nptl/tst-cancelx4.c create mode 100644 test/nptl/tst-cancelx6.c create mode 100644 test/nptl/tst-cancelx7.c create mode 100644 test/nptl/tst-cancelx8.c create mode 100644 test/nptl/tst-cancelx9.c create mode 100644 test/nptl/tst-cleanupx0.c create mode 100644 test/nptl/tst-cleanupx1.c create mode 100644 test/nptl/tst-cleanupx2.c create mode 100644 test/nptl/tst-cleanupx3.c create mode 100644 test/nptl/tst-cleanupx4.c create mode 100644 test/nptl/tst-cond22.c create mode 100644 test/nptl/tst-cond23.c create mode 100644 test/nptl/tst-dlsym1.c create mode 100644 test/nptl/tst-fini1.c create mode 100644 test/nptl/tst-fini1mod.c create mode 100644 test/nptl/tst-getpid1.c create mode 100644 test/nptl/tst-getpid2.c create mode 100644 test/nptl/tst-getpid3.c create mode 100644 test/nptl/tst-initializers1-c89.c create mode 100644 test/nptl/tst-initializers1-c99.c create mode 100644 test/nptl/tst-initializers1-gnu89.c create mode 100644 test/nptl/tst-initializers1-gnu99.c create mode 100644 test/nptl/tst-join6.c create mode 100644 test/nptl/tst-oddstacklimit.c create mode 100644 test/nptl/tst-oncex3.c create mode 100644 test/nptl/tst-oncex4.c create mode 100644 test/nptl/tst-rwlock2a.c create mode 100644 test/nptl/tst-sem10.c create mode 100644 test/nptl/tst-sem11.c create mode 100644 test/nptl/tst-sem12.c create mode 100644 test/nptl/tst-signal7.c create mode 100644 test/nptl/tst-tsd6.c create mode 100644 test/nptl/tst-typesizes.c create mode 100644 test/nptl/tst-unload.c create mode 100644 test/nptl/tst-vfork1.c create mode 100644 test/nptl/tst-vfork1x.c create mode 100644 test/nptl/tst-vfork2.c create mode 100644 test/nptl/tst-vfork2x.c (limited to 'test/nptl') diff --git a/test/nptl/Makefile.in b/test/nptl/Makefile.in index 8ad952a91..b6a279ebf 100644 --- a/test/nptl/Makefile.in +++ b/test/nptl/Makefile.in @@ -31,7 +31,19 @@ TESTS := tst-align tst-align2 tst-atfork1 tst-attr1 tst-attr2 tst-attr3 \ tst-signal5 tst-signal6 tst-spin1 tst-spin2 tst-spin3 \ tst-stack1 tst-stack2 tst-stdio1 tst-stdio2 tst-sysconf \ tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tsd1 tst-tsd2 \ - tst-tsd3 tst-tsd4 tst-tsd5 tst-umask1 + tst-tsd3 tst-tsd4 tst-tsd5 tst-umask1 \ + tst-align3 tst-cancel4 tst-cancel5 tst-cancel18 tst-cancel23 \ + tst-cancel25 tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx6 \ + tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 tst-cancelx11 \ + tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15 tst-cancelx16 \ + tst-cancelx18 tst-cancelx20 tst-cancelx21 tst-cleanupx0 tst-cleanupx1 \ + tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 tst-cond22 tst-cond23 \ + tst-dlsym1 tst-getpid1 tst-getpid2 tst-getpid3 tst-join6 tst-tsd6 \ + tst-oddstacklimit tst-oncex3 tst-oncex4 tst-rwlock2a \ + tst-basic7 tst-fini1 tst-signal7 \ + tst-unload tst-vfork1x tst-vfork2x tst-sem10 tst-sem11 tst-sem12 \ + tst-typesizes tst-initializers1-c89 tst-initializers1-c99 \ + tst-initializers1-gnu89 tst-initializers1-gnu99 # # These are for the RT library and POSIX timers. @@ -97,9 +109,60 @@ CFLAGS_tst-tls5modd.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc CFLAGS_tst-tls5mode.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc CFLAGS_tst-tls5modf.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-fini1mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +LDFLAGS_tst-cond11 = -lrt +LDFLAGS_tst-cond19 = -lrt +LDFLAGS_tst-cancel18 = -lrt +LDFLAGS_tst-cancelx18 = -lrt +LDFLAGS_tst-clock2 = -lrt +LDFLAGS_tst-rwlock14 = -lrt +LDFLAGS_tst-fini1 = -Wl,-rpath=./ tst-fini1mod.so +LDFLAGS_tst-fini1mod.so = -Wl,-soname=tst-fini1mod.so +LDFLAGS_tst-unload = -ldl +LDFLAGS_tst-cancel5 := -lpthread -lpthread_nonshared +LDFLAGS_tst-cancel23 := -lc -lpthread +LDFLAGS_tst-vfork1x := -lc -lpthread +LDFLAGS_tst-vfork2x := -lc -lpthread + +CFLAGS_tst-cancelx2 += -fexceptions +CFLAGS_tst-cancelx3 += -fexceptions +CFLAGS_tst-cancelx4 += -fexceptions +CFLAGS_tst-cancelx6 += -fexceptions +CFLAGS_tst-cancelx7 += -fexceptions +CFLAGS_tst-cancelx8 += -fexceptions +CFLAGS_tst-cancelx9 += -fexceptions +CFLAGS_tst-cancelx10 += -fexceptions +CFLAGS_tst-cancelx11 += -fexceptions +CFLAGS_tst-cancelx12 += -fexceptions +CFLAGS_tst-cancelx13 += -fexceptions +CFLAGS_tst-cancelx14 += -fexceptions +CFLAGS_tst-cancelx15 += -fexceptions +CFLAGS_tst-cancelx16 += -fexceptions +CFLAGS_tst-cancelx18 += -fexceptions +CFLAGS_tst-cancelx20 += -fexceptions -fasynchronous-unwind-tables +CFLAGS_tst-cancelx21 += -fexceptions -fasynchronous-unwind-tables +CFLAGS_tst-cleanupx0 += -fexceptions -fasynchronous-unwind-tables +CFLAGS_tst-cleanupx1 += -fexceptions -fasynchronous-unwind-tables +CFLAGS_tst-cleanupx2 += -fexceptions +CFLAGS_tst-cleanupx3 += -fexceptions + +CFLAGS_tst-oncex3 += -fexceptions +CFLAGS_tst-oncex4 += -fexceptions +CFLAGS_tst-align += $(stack-align-test-flags) +CFLAGS_tst-align3 += $(stack-align-test-flags) +CFLAGS_tst-initializers1 = -W -Wall -Werror +CFLAGS_tst-sem11 += -fexceptions -fasynchronous-unwind-tables +CFLAGS_tst-sem12 += -fexceptions -fasynchronous-unwind-tables +CFLAGS_tst-initializers1 = -W -Wall -Werror +CFLAGS_tst-initializers1-c89 = $(CFLAGS-tst-initializers1) -std=c89 +CFLAGS_tst-initializers1-c99 = $(CFLAGS-tst-initializers1) -std=c99 +CFLAGS_tst-initializers1-gnu89 = $(CFLAGS-tst-initializers1) -std=gnu89 +CFLAGS_tst-initializers1-gnu99 = $(CFLAGS-tst-initializers1) -std=gnu99 + EXTRA_LDFLAGS = $(if $(findstring -lpthread,$(LDFLAGS_$@)),,-lpthread) LDFLAGS_tst-cleanup4 := tst-cleanup4aux.o +LDFLAGS_tst-cleanupx4 := tst-cleanup4aux.o LDFLAGS_tst-clock2 := -lrt LDFLAGS_tst-cond11 := -lrt LDFLAGS_tst-cond19 := -lrt @@ -127,6 +190,7 @@ LDFLAGS_tst-timer2 := -lrt -lpthread LDFLAGS_tst-timer3 := -lrt -lpthread LDFLAGS_tst-timer4 := -lrt -lpthread LDFLAGS_tst-timer5 := -lrt -lpthread +LDFLAGS_tst-dlsym1 := -ldl -rdynamic LDFLAGS_tst-tls3mod.so := -shared -static-libgcc -lpthread LDFLAGS_tst-tls4moda.so := -shared -static-libgcc LDFLAGS_tst-tls4modb.so := -shared -static-libgcc @@ -137,6 +201,7 @@ LDFLAGS_tst-tls5modc.so := -shared -static-libgcc LDFLAGS_tst-tls5modd.so := -shared -static-libgcc LDFLAGS_tst-tls5mode.so := -shared -static-libgcc LDFLAGS_tst-tls5modf.so := -shared -static-libgcc +LDFLAGS_tst-cleanupx4 := tst-cleanup4aux.o # # Special case @@ -149,6 +214,9 @@ tst-tls3: tst-tls3mod.so tst-tls4: tst-tls4moda.so tst-tls4modb.so tst-tls5: tst-tls5mod.so +tst-cleanupx4 : tst-cleanup4aux.o +tst-fini1: tst-fini1mod.so + OPTS_tst-cancel7 = --command ./tst-cancel7 OPTS_tst-mqueue7 = -- ./tst-mqueue7 OPTS_tst-exec4 = ./tst-exec4 diff --git a/test/nptl/tst-align3.c b/test/nptl/tst-align3.c new file mode 100644 index 000000000..f4507f2eb --- /dev/null +++ b/test/nptl/tst-align3.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2005. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include "tst-stack-align.h" + +static bool ok = true; +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static void +once_test (void) +{ + puts ("in once_test"); + + if (TEST_STACK_ALIGN ()) + ok = false; +} + +static int +do_test (void) +{ + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + if (pthread_once (&once, once_test)) + { + puts ("pthread once failed"); + return 1; + } + + return ok ? 0 : 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic7.c b/test/nptl/tst-basic7.c new file mode 100644 index 000000000..15b618786 --- /dev/null +++ b/test/nptl/tst-basic7.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void use_stack (size_t needed); + +void (*use_stack_ptr) (size_t) = use_stack; + +static void +use_stack (size_t needed) +{ + size_t sz = sysconf (_SC_PAGESIZE); + char *buf = alloca (sz); + memset (buf, '\0', sz); + + if (needed > sz) + use_stack_ptr (needed - sz); +} + +static void +use_up_memory (void) +{ + struct rlimit rl; + getrlimit (RLIMIT_AS, &rl); + rl.rlim_cur = 10 * 1024 * 1024; + setrlimit (RLIMIT_AS, &rl); + + char *c; + int PAGESIZE = getpagesize (); + while (1) + { + c = mmap (NULL, PAGESIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (c == MAP_FAILED) + break; + } +} + +static void * +child (void *arg) +{ + sleep (1); + return arg; +} + +static int +do_test (void) +{ + int err; + pthread_t tid; + + /* Allocate the memory needed for the stack. */ + use_stack_ptr (PTHREAD_STACK_MIN); + + use_up_memory (); + + err = pthread_create (&tid, NULL, child, NULL); + if (err != 0) + { + printf ("pthread_create returns %d: %s\n", err, + err == EAGAIN ? "OK" : "FAIL"); + return err != EAGAIN; + } + + /* We did not fail to allocate memory despite the preparation. Oh well. */ + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel18.c b/test/nptl/tst-cancel18.c new file mode 100644 index 000000000..15e9ddfbb --- /dev/null +++ b/test/nptl/tst-cancel18.c @@ -0,0 +1,174 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2003. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include + + +static pthread_barrier_t b; + + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 }; + TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts)); + + pthread_cleanup_pop (0); + + puts ("clock_nanosleep returned"); + + exit (1); +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + puts ("going to cancel in-time"); + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + return 1; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("1st join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + puts ("cleanup handler not called"); + return 1; + } + if (cl_called > 1) + { + puts ("cleanup handler called more than once"); + return 1; + } + + puts ("in-time cancellation succeeded"); + + + cl_called = 0; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("2nd create failed"); + return 1; + } + + puts ("going to cancel early"); + if (pthread_cancel (th) != 0) + { + puts ("2nd cancel failed"); + return 1; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_join (th, &status) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called\n"); + return 1; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once\n"); + return 1; + } + + puts ("early cancellation succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel23.c b/test/nptl/tst-cancel23.c new file mode 100644 index 000000000..211168748 --- /dev/null +++ b/test/nptl/tst-cancel23.c @@ -0,0 +1 @@ +#include "tst-cancel22.c" diff --git a/test/nptl/tst-cancel25.c b/test/nptl/tst-cancel25.c new file mode 100644 index 000000000..00b99ad55 --- /dev/null +++ b/test/nptl/tst-cancel25.c @@ -0,0 +1,171 @@ +#include +#include +#include +#include + + +static pthread_barrier_t b; +static pthread_t th2; + + +static void * +tf2 (void *arg) +{ + sigset_t mask; + if (pthread_sigmask (SIG_SETMASK, NULL, &mask) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + if (sigismember (&mask, SIGCANCEL)) + { + puts ("SIGCANCEL blocked in new thread"); + exit (1); + } + + /* Sync with the main thread so that we do not test anything else. */ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + while (1) + { + /* Just a cancelable call. */ + struct timespec ts = { 10000, 0 }; + nanosleep (&ts, 0); + } + + return NULL; +} + + +static void +unwhand (void *arg) +{ + if (pthread_create (&th2, NULL, tf2, NULL) != 0) + { + puts ("unwhand: create failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (unwhand, NULL); + + /* Sync with the main thread so that we do not test anything else. */ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + while (1) + { + /* Just a cancelable call. */ + struct timespec ts = { 10000, 0 }; + nanosleep (&ts, 0); + } + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th1; + if (pthread_create (&th1, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + /* Make sure tf1 enters nanosleep. */ + struct timespec ts = { 0, 500000000 }; + while (nanosleep (&ts, &ts) != 0) + ; + + if (pthread_cancel (th1) != 0) + { + puts ("1st cancel failed"); + return 1; + } + + void *res; + if (pthread_join (th1, &res) != 0) + { + puts ("1st join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + /* Make sure tf2 enters nanosleep. */ + ts.tv_sec = 0; + ts.tv_nsec = 500000000; + while (nanosleep (&ts, &ts) != 0) + ; + + puts ("calling pthread_cancel the second time"); + if (pthread_cancel (th2) != 0) + { + puts ("2nd cancel failed"); + return 1; + } + + puts ("calling pthread_join the second time"); + if (pthread_join (th2, &res) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 0; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel4.c b/test/nptl/tst-cancel4.c new file mode 100644 index 000000000..12d40d5bd --- /dev/null +++ b/test/nptl/tst-cancel4.c @@ -0,0 +1,2374 @@ +/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2002. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +/* NOTE: this tests functionality beyond POSIX. POSIX does not allow + exit to be called more than once. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pthreadP.h" + + +/* Since STREAMS are not supported in the standard Linux kernel and + there we don't advertise STREAMS as supported is no need to test + the STREAMS related functions. This affects + getmsg() getpmsg() putmsg() + putpmsg() + + lockf() and fcntl() are tested in tst-cancel16. + + pthread_join() is tested in tst-join5. + + pthread_testcancel()'s only purpose is to allow cancellation. This + is tested in several places. + + sem_wait() and sem_timedwait() are checked in tst-cancel1[2345] tests. + + mq_send(), mq_timedsend(), mq_receive() and mq_timedreceive() are checked + in tst-mqueue8{,x} tests. + + aio_suspend() is tested in tst-cancel17. + + clock_nanosleep() is tested in tst-cancel18. +*/ + +/* Pipe descriptors. */ +static int fds[2]; + +/* Temporary file descriptor, to be closed after each round. */ +static int tempfd = -1; +static int tempfd2 = -1; +/* Name of temporary file to be removed after each round. */ +static char *tempfname; +/* Temporary message queue. */ +static int tempmsg = -1; + +/* Often used barrier for two threads. */ +static pthread_barrier_t b2; + + +#ifndef IPC_ADDVAL +# define IPC_ADDVAL 0 +#endif + +#define WRITE_BUFFER_SIZE 4096 + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + + + +static void * +tf_read (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[100]; + s = read (fd, buf, sizeof (buf)); + + pthread_cleanup_pop (0); + + printf ("%s: read returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_readv (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[100]; + struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } }; + s = readv (fd, iov, 1); + + pthread_cleanup_pop (0); + + printf ("%s: readv returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_write (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[1]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[WRITE_BUFFER_SIZE]; + memset (buf, '\0', sizeof (buf)); + s = write (fd, buf, sizeof (buf)); + + pthread_cleanup_pop (0); + + printf ("%s: write returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_writev (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[1]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + ssize_t s; + pthread_cleanup_push (cl, NULL); + + char buf[WRITE_BUFFER_SIZE]; + memset (buf, '\0', sizeof (buf)); + struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } }; + s = writev (fd, iov, 1); + + pthread_cleanup_pop (0); + + printf ("%s: writev returns with %zd\n", __FUNCTION__, s); + + exit (1); +} + + +static void * +tf_sleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + sleep (arg == NULL ? 1000000 : 0); + + pthread_cleanup_pop (0); + + printf ("%s: sleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_usleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + usleep (arg == NULL ? (useconds_t) ULONG_MAX : 0); + + pthread_cleanup_pop (0); + + printf ("%s: usleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_nanosleep (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + pthread_cleanup_pop (0); + + printf ("%s: nanosleep returns\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_select (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + fd_set rfs; + FD_ZERO (&rfs); + FD_SET (fd, &rfs); + + int s; + pthread_cleanup_push (cl, NULL); + + s = select (fd + 1, &rfs, NULL, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: select returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_pselect (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + fd_set rfs; + FD_ZERO (&rfs); + FD_SET (fd, &rfs); + + int s; + pthread_cleanup_push (cl, NULL); + + s = pselect (fd + 1, &rfs, NULL, NULL, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: pselect returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_poll (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } }; + + int s; + pthread_cleanup_push (cl, NULL); + + s = poll (rfs, 1, -1); + + pthread_cleanup_pop (0); + + printf ("%s: poll returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_ppoll (void *arg) +{ + int fd; + int r; + + if (arg == NULL) + fd = fds[0]; + else + { + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = fd = mkstemp (fname); + if (fd == -1) + printf ("%s: mkstemp failed\n", __FUNCTION__); + unlink (fname); + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } }; + + int s; + pthread_cleanup_push (cl, NULL); + + s = ppoll (rfs, 1, NULL, NULL); + + pthread_cleanup_pop (0); + + printf ("%s: ppoll returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_wait (void *arg) +{ + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + if (arg == NULL) + sleep (10); + exit (0); + } + + int r; + if (arg != NULL) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + int s; + pthread_cleanup_push (cl, NULL); + + s = wait (NULL); + + pthread_cleanup_pop (0); + + printf ("%s: wait returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_waitpid (void *arg) +{ + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + if (arg == NULL) + sleep (10); + exit (0); + } + + int r; + if (arg != NULL) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + int s; + pthread_cleanup_push (cl, NULL); + + s = waitpid (-1, NULL, 0); + + pthread_cleanup_pop (0); + + printf ("%s: waitpid returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_waitid (void *arg) +{ + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Make the program disappear after a while. */ + if (arg == NULL) + sleep (10); + exit (0); + } + + int r; + if (arg != NULL) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + int s; + pthread_cleanup_push (cl, NULL); + +#ifndef WEXITED +# define WEXITED 0 +#endif + siginfo_t si; + s = waitid (P_PID, pid, &si, WEXITED); + + pthread_cleanup_pop (0); + + printf ("%s: waitid returns with %d (%s)\n", __FUNCTION__, s, + strerror (errno)); + + exit (1); +} + + +static void * +tf_sigpause (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Just for fun block the cancellation signal. We need to use + __xpg_sigpause since otherwise we will get the BSD version. */ + //__xpg_sigpause (SIGCANCEL); + + __sigpause (SIGCANCEL, 1); + + pthread_cleanup_pop (0); + + printf ("%s: sigpause returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sigsuspend (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Just for fun block all signals. */ + sigset_t mask; + sigfillset (&mask); + sigsuspend (&mask); + + pthread_cleanup_pop (0); + + printf ("%s: sigsuspend returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sigwait (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + /* Block SIGUSR1. */ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0) + { + printf ("%s: pthread_sigmask failed\n", __FUNCTION__); + exit (1); + } + + int sig; + pthread_cleanup_push (cl, NULL); + + /* Wait for SIGUSR1. */ + sigwait (&mask, &sig); + + pthread_cleanup_pop (0); + + printf ("%s: sigwait returned with signal %d\n", __FUNCTION__, sig); + + exit (1); +} + + +static void * +tf_sigwaitinfo (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + /* Block SIGUSR1. */ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0) + { + printf ("%s: pthread_sigmask failed\n", __FUNCTION__); + exit (1); + } + + siginfo_t info; + pthread_cleanup_push (cl, NULL); + + /* Wait for SIGUSR1. */ + sigwaitinfo (&mask, &info); + + pthread_cleanup_pop (0); + + printf ("%s: sigwaitinfo returned with signal %d\n", __FUNCTION__, + info.si_signo); + + exit (1); +} + + +static void * +tf_sigtimedwait (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + /* Block SIGUSR1. */ + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0) + { + printf ("%s: pthread_sigmask failed\n", __FUNCTION__); + exit (1); + } + + /* Wait for SIGUSR1. */ + siginfo_t info; + struct timespec ts = { .tv_sec = 60, .tv_nsec = 0 }; + pthread_cleanup_push (cl, NULL); + + sigtimedwait (&mask, &info, &ts); + + pthread_cleanup_pop (0); + + printf ("%s: sigtimedwait returned with signal %d\n", __FUNCTION__, + info.si_signo); + + exit (1); +} + + +static void * +tf_pause (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + pause (); + + pthread_cleanup_pop (0); + + printf ("%s: pause returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_accept (void *arg) +{ + struct sockaddr_un sun; + /* To test a non-blocking accept call we make the call file by using + a datagrame socket. */ + int pf = arg == NULL ? SOCK_STREAM : SOCK_DGRAM; + + tempfd = socket (AF_UNIX, pf, 0); + if (tempfd == -1) + { + printf ("%s: socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-1-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + unlink (sun.sun_path); + + listen (tempfd, 5); + + socklen_t len = sizeof (sun); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + accept (tempfd, (struct sockaddr *) &sun, &len); + + pthread_cleanup_pop (0); + + printf ("%s: accept returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_send (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-2-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + listen (tempfd, 5); + + tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + if (connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)) != 0) + { + printf ("%s: connect failed\n", __FUNCTION__); + exit(1); + } + + unlink (sun.sun_path); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Very large block, so that the send call blocks. */ + char mem[700000]; + + send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0); + + pthread_cleanup_pop (0); + + printf ("%s: send returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_recv (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-3-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + listen (tempfd, 5); + + tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + if (connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)) != 0) + { + printf ("%s: connect failed\n", __FUNCTION__); + exit(1); + } + + unlink (sun.sun_path); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + + recv (tempfd2, mem, arg == NULL ? sizeof (mem) : 0, 0); + + pthread_cleanup_pop (0); + + printf ("%s: recv returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_recvfrom (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-4-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + socklen_t len = sizeof (sun); + + recvfrom (tempfd2, mem, arg == NULL ? sizeof (mem) : 0, 0, + (struct sockaddr *) &sun, &len); + + pthread_cleanup_pop (0); + + printf ("%s: recvfrom returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_recvmsg (void *arg) +{ + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-5-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + char mem[70]; + struct iovec iov[1]; + iov[0].iov_base = mem; + iov[0].iov_len = arg == NULL ? sizeof (mem) : 0; + + struct msghdr m; + m.msg_name = &sun; + m.msg_namelen = sizeof (sun); + m.msg_iov = iov; + m.msg_iovlen = 1; + m.msg_control = NULL; + m.msg_controllen = 0; + + recvmsg (tempfd2, &m, 0); + + pthread_cleanup_pop (0); + + printf ("%s: recvmsg returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_open (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which open() + // blocks we can enable this test to run in both rounds. + abort (); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + open ("Makefile", O_RDONLY); + + pthread_cleanup_pop (0); + + printf ("%s: open returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_close (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which close() + // blocks we can enable this test to run in both rounds. + abort (); + + char fname[] = "/tmp/tst-cancel-fd-XXXXXX"; + tempfd = mkstemp (fname); + if (tempfd == -1) + { + printf ("%s: mkstemp failed\n", __FUNCTION__); + exit (1); + } + unlink (fname); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + close (tempfd); + + pthread_cleanup_pop (0); + + printf ("%s: close returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_pread (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which pread() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[10]; + pread (tempfd, mem, sizeof (mem), 0); + + pthread_cleanup_pop (0); + + printf ("%s: pread returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_pwrite (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which pwrite() + // blocks we can enable this test to run in both rounds. + abort (); + + char fname[] = "/tmp/tst-cancel4-fd-XXXXXX"; + tempfd = mkstemp (fname); + if (tempfd == -1) + { + printf ("%s: mkstemp failed\n", __FUNCTION__); + exit (1); + } + unlink (fname); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[10]; + pwrite (tempfd, mem, sizeof (mem), 0); + + pthread_cleanup_pop (0); + + printf ("%s: pwrite returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_fsync (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which fsync() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + fsync (tempfd); + + pthread_cleanup_pop (0); + + printf ("%s: fsync returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_fdatasync (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which fdatasync() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + fdatasync (tempfd); + + pthread_cleanup_pop (0); + + printf ("%s: fdatasync returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_msync (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which msync() + // blocks we can enable this test to run in both rounds. + abort (); + + tempfd = open ("Makefile", O_RDONLY); + if (tempfd == -1) + { + printf ("%s: cannot open Makefile\n", __FUNCTION__); + exit (1); + } + void *p = mmap (NULL, 10, PROT_READ, MAP_SHARED, tempfd, 0); + if (p == MAP_FAILED) + { + printf ("%s: mmap failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + msync (p, 10, 0); + + pthread_cleanup_pop (0); + + printf ("%s: msync returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sendto (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendto() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-6-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[1]; + + sendto (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0, + (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + strlen (sun.sun_path) + 1); + + pthread_cleanup_pop (0); + + printf ("%s: sendto returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_sendmsg (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendmsg() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-7-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char mem[1]; + struct iovec iov[1]; + iov[0].iov_base = mem; + iov[0].iov_len = 1; + + struct msghdr m; + m.msg_name = &sun; + m.msg_namelen = (offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1); + m.msg_iov = iov; + m.msg_iovlen = 1; + m.msg_control = NULL; + m.msg_controllen = 0; + + sendmsg (tempfd2, &m, 0); + + pthread_cleanup_pop (0); + + printf ("%s: sendmsg returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_creat (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which sendmsg() + // blocks we can enable this test to run in both rounds. + abort (); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + creat ("tmp/tst-cancel-4-should-not-exist", 0666); + + pthread_cleanup_pop (0); + + printf ("%s: creat returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_connect (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which connect() + // blocks we can enable this test to run in both rounds. + abort (); + + struct sockaddr_un sun; + + tempfd = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd == -1) + { + printf ("%s: first socket call failed\n", __FUNCTION__); + exit (1); + } + + int tries = 0; + do + { + if (++tries > 10) + { + printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__); + } + + strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-2-XXXXXX"); + if (mktemp (sun.sun_path) == NULL) + { + printf ("%s: cannot generate temp file name\n", __FUNCTION__); + exit (1); + } + + sun.sun_family = AF_UNIX; + } + while (bind (tempfd, (struct sockaddr *) &sun, + offsetof (struct sockaddr_un, sun_path) + + strlen (sun.sun_path) + 1) != 0); + tempfname = strdup (sun.sun_path); + + listen (tempfd, 5); + + tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0); + if (tempfd2 == -1) + { + printf ("%s: second socket call failed\n", __FUNCTION__); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)); + + pthread_cleanup_pop (0); + + printf ("%s: connect returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_tcdrain (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which tcdrain() + // blocks we can enable this test to run in both rounds. + abort (); + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + pthread_cleanup_push (cl, NULL); + + /* Regardless of stderr being a terminal, the tcdrain call should be + canceled. */ + tcdrain (STDERR_FILENO); + + pthread_cleanup_pop (0); + + printf ("%s: tcdrain returned\n", __FUNCTION__); + + exit (1); +} + + +static void * +tf_msgrcv (void *arg) +{ + tempmsg = msgget (IPC_PRIVATE, 0666 | IPC_CREAT); + if (tempmsg == -1) + { + printf ("%s: msgget failed: %s\n", __FUNCTION__, strerror (errno)); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + if (arg != NULL) + { + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + } + + ssize_t s; + + pthread_cleanup_push (cl, NULL); + + struct + { + long int type; + char mem[10]; + } m; + int randnr; + /* We need a positive random number. */ + do + randnr = random () % 64000; + while (randnr <= 0); + do + { + errno = 0; + s = msgrcv (tempmsg, (struct msgbuf *) &m, 10, randnr, 0); + } + while (errno == EIDRM || errno == EINTR); + + pthread_cleanup_pop (0); + + printf ("%s: msgrcv returned %zd with errno = %m\n", __FUNCTION__, s); + + msgctl (tempmsg, IPC_RMID, NULL); + + exit (1); +} + + +static void * +tf_msgsnd (void *arg) +{ + if (arg == NULL) + // XXX If somebody can provide a portable test case in which msgsnd() + // blocks we can enable this test to run in both rounds. + abort (); + + tempmsg = msgget (IPC_PRIVATE, 0666 | IPC_CREAT); + if (tempmsg == -1) + { + printf ("%s: msgget failed: %s\n", __FUNCTION__, strerror (errno)); + exit (1); + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + struct + { + long int type; + char mem[1]; + } m; + /* We need a positive random number. */ + do + m.type = random () % 64000; + while (m.type <= 0); + msgsnd (tempmsg, (struct msgbuf *) &m, sizeof (m.mem), 0); + + pthread_cleanup_pop (0); + + printf ("%s: msgsnd returned\n", __FUNCTION__); + + msgctl (tempmsg, IPC_RMID, NULL); + + exit (1); +} + + +static struct +{ + const char *name; + void *(*tf) (void *); + int nb; + int only_early; +} tests[] = +{ +#define ADD_TEST(name, nbar, early) { #name, tf_##name, nbar, early } + ADD_TEST (read, 2, 0), + ADD_TEST (readv, 2, 0), + ADD_TEST (select, 2, 0), + ADD_TEST (pselect, 2, 0), + ADD_TEST (poll, 2, 0), + ADD_TEST (ppoll, 2, 0), + ADD_TEST (write, 2, 0), + ADD_TEST (writev, 2, 0), + ADD_TEST (sleep, 2, 0), + ADD_TEST (usleep, 2, 0), + ADD_TEST (nanosleep, 2, 0), + ADD_TEST (wait, 2, 0), + ADD_TEST (waitid, 2, 0), + ADD_TEST (waitpid, 2, 0), + ADD_TEST (sigpause, 2, 0), + ADD_TEST (sigsuspend, 2, 0), + ADD_TEST (sigwait, 2, 0), + ADD_TEST (sigwaitinfo, 2, 0), + ADD_TEST (sigtimedwait, 2, 0), + ADD_TEST (pause, 2, 0), + ADD_TEST (accept, 2, 0), + ADD_TEST (send, 2, 0), + ADD_TEST (recv, 2, 0), + ADD_TEST (recvfrom, 2, 0), + ADD_TEST (recvmsg, 2, 0), + ADD_TEST (open, 2, 1), + ADD_TEST (close, 2, 1), + ADD_TEST (pread, 2, 1), + ADD_TEST (pwrite, 2, 1), + ADD_TEST (fsync, 2, 1), + ADD_TEST (fdatasync, 2, 1), + ADD_TEST (msync, 2, 1), + ADD_TEST (sendto, 2, 1), + ADD_TEST (sendmsg, 2, 1), + ADD_TEST (creat, 2, 1), + ADD_TEST (connect, 2, 1), + ADD_TEST (tcdrain, 2, 1), + ADD_TEST (msgrcv, 2, 0), + ADD_TEST (msgsnd, 2, 1), +}; +#define ntest_tf (sizeof (tests) / sizeof (tests[0])) + + +static int +do_test (void) +{ + int val; + socklen_t len; + + if (socketpair (AF_UNIX, SOCK_STREAM, PF_UNIX, fds) != 0) + { + perror ("socketpair"); + exit (1); + } + + val = 1; + len = sizeof(val); + setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); + if (getsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, &len) < 0) + { + perror ("getsockopt"); + exit (1); + } + if (val >= WRITE_BUFFER_SIZE) + { + puts ("minimum write buffer size too large"); + exit (1); + } + setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val)); + + int result = 0; + size_t cnt; + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + if (tests[cnt].only_early) + continue; + + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + /* Reset the counter for the cleanup handler. */ + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0) + { + printf ("create for '%s' test failed\n", tests[cnt].name); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + if (pthread_cancel (th) != 0) + { + printf ("cancel for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("thread for '%s' not canceled\n", tests[cnt].name); + result = 1; + continue; + } + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called for '%s'\n", tests[cnt].name); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once for '%s'\n", + tests[cnt].name); + result = 1; + continue; + } + + printf ("in-time cancel test of '%s' successful\n", tests[cnt].name); + + if (tempfd != -1) + { + close (tempfd); + tempfd = -1; + } + if (tempfd2 != -1) + { + close (tempfd2); + tempfd2 = -1; + } + if (tempfname != NULL) + { + unlink (tempfname); + free (tempfname); + tempfname = NULL; + } + if (tempmsg != -1) + { + msgctl (tempmsg, IPC_RMID, NULL); + tempmsg = -1; + } + } + + for (cnt = 0; cnt < ntest_tf; ++cnt) + { + if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + /* Reset the counter for the cleanup handler. */ + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tests[cnt].tf, (void *) 1l) != 0) + { + printf ("create for '%s' test failed\n", tests[cnt].name); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + if (pthread_cancel (th) != 0) + { + printf ("cancel for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("join for '%s' failed\n", tests[cnt].name); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("thread for '%s' not canceled\n", tests[cnt].name); + result = 1; + continue; + } + + if (pthread_barrier_destroy (&b2) != 0) + { + puts ("barrier_destroy failed"); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("cleanup handler not called for '%s'\n", tests[cnt].name); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("cleanup handler called more than once for '%s'\n", + tests[cnt].name); + result = 1; + continue; + } + + printf ("early cancel test of '%s' successful\n", tests[cnt].name); + + if (tempfd != -1) + { + close (tempfd); + tempfd = -1; + } + if (tempfd2 != -1) + { + close (tempfd2); + tempfd2 = -1; + } + if (tempfname != NULL) + { + unlink (tempfname); + free (tempfname); + tempfname = NULL; + } + if (tempmsg != -1) + { + msgctl (tempmsg, IPC_RMID, NULL); + tempmsg = -1; + } + } + + return result; +} + +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel5.c b/test/nptl/tst-cancel5.c new file mode 100644 index 000000000..1c879eba8 --- /dev/null +++ b/test/nptl/tst-cancel5.c @@ -0,0 +1 @@ +#include "tst-cancel4.c" diff --git a/test/nptl/tst-cancelx10.c b/test/nptl/tst-cancelx10.c new file mode 100644 index 000000000..e5bbb34e6 --- /dev/null +++ b/test/nptl/tst-cancelx10.c @@ -0,0 +1 @@ +#include "tst-cancel10.c" diff --git a/test/nptl/tst-cancelx11.c b/test/nptl/tst-cancelx11.c new file mode 100644 index 000000000..ffcc2eefc --- /dev/null +++ b/test/nptl/tst-cancelx11.c @@ -0,0 +1 @@ +#include "tst-cancel11.c" diff --git a/test/nptl/tst-cancelx12.c b/test/nptl/tst-cancelx12.c new file mode 100644 index 000000000..f90ae61ba --- /dev/null +++ b/test/nptl/tst-cancelx12.c @@ -0,0 +1 @@ +#include "tst-cancel12.c" diff --git a/test/nptl/tst-cancelx13.c b/test/nptl/tst-cancelx13.c new file mode 100644 index 000000000..37c4c39c3 --- /dev/null +++ b/test/nptl/tst-cancelx13.c @@ -0,0 +1 @@ +#include "tst-cancel13.c" diff --git a/test/nptl/tst-cancelx14.c b/test/nptl/tst-cancelx14.c new file mode 100644 index 000000000..ba4e77584 --- /dev/null +++ b/test/nptl/tst-cancelx14.c @@ -0,0 +1 @@ +#include "tst-cancel14.c" diff --git a/test/nptl/tst-cancelx15.c b/test/nptl/tst-cancelx15.c new file mode 100644 index 000000000..005c1f6e3 --- /dev/null +++ b/test/nptl/tst-cancelx15.c @@ -0,0 +1 @@ +#include "tst-cancel15.c" diff --git a/test/nptl/tst-cancelx16.c b/test/nptl/tst-cancelx16.c new file mode 100644 index 000000000..99af3b197 --- /dev/null +++ b/test/nptl/tst-cancelx16.c @@ -0,0 +1 @@ +#include "tst-cancel16.c" diff --git a/test/nptl/tst-cancelx18.c b/test/nptl/tst-cancelx18.c new file mode 100644 index 000000000..56da18f38 --- /dev/null +++ b/test/nptl/tst-cancelx18.c @@ -0,0 +1 @@ +#include "tst-cancel18.c" diff --git a/test/nptl/tst-cancelx2.c b/test/nptl/tst-cancelx2.c new file mode 100644 index 000000000..95dc8a857 --- /dev/null +++ b/test/nptl/tst-cancelx2.c @@ -0,0 +1 @@ +#include "tst-cancel2.c" diff --git a/test/nptl/tst-cancelx20.c b/test/nptl/tst-cancelx20.c new file mode 100644 index 000000000..6bd86376c --- /dev/null +++ b/test/nptl/tst-cancelx20.c @@ -0,0 +1 @@ +#include "tst-cancel20.c" diff --git a/test/nptl/tst-cancelx21.c b/test/nptl/tst-cancelx21.c new file mode 100644 index 000000000..2a01061ea --- /dev/null +++ b/test/nptl/tst-cancelx21.c @@ -0,0 +1 @@ +#include "tst-cancel21.c" diff --git a/test/nptl/tst-cancelx3.c b/test/nptl/tst-cancelx3.c new file mode 100644 index 000000000..3937f10b9 --- /dev/null +++ b/test/nptl/tst-cancelx3.c @@ -0,0 +1 @@ +#include "tst-cancel3.c" diff --git a/test/nptl/tst-cancelx4.c b/test/nptl/tst-cancelx4.c new file mode 100644 index 000000000..1c879eba8 --- /dev/null +++ b/test/nptl/tst-cancelx4.c @@ -0,0 +1 @@ +#include "tst-cancel4.c" diff --git a/test/nptl/tst-cancelx6.c b/test/nptl/tst-cancelx6.c new file mode 100644 index 000000000..6926e21c2 --- /dev/null +++ b/test/nptl/tst-cancelx6.c @@ -0,0 +1 @@ +#include "tst-cancel6.c" diff --git a/test/nptl/tst-cancelx7.c b/test/nptl/tst-cancelx7.c new file mode 100644 index 000000000..4df1a5881 --- /dev/null +++ b/test/nptl/tst-cancelx7.c @@ -0,0 +1 @@ +#include "tst-cancel7.c" diff --git a/test/nptl/tst-cancelx8.c b/test/nptl/tst-cancelx8.c new file mode 100644 index 000000000..0555c7ceb --- /dev/null +++ b/test/nptl/tst-cancelx8.c @@ -0,0 +1 @@ +#include "tst-cancel8.c" diff --git a/test/nptl/tst-cancelx9.c b/test/nptl/tst-cancelx9.c new file mode 100644 index 000000000..9d84663d7 --- /dev/null +++ b/test/nptl/tst-cancelx9.c @@ -0,0 +1 @@ +#include "tst-cancel9.c" diff --git a/test/nptl/tst-cleanupx0.c b/test/nptl/tst-cleanupx0.c new file mode 100644 index 000000000..0012ab1b2 --- /dev/null +++ b/test/nptl/tst-cleanupx0.c @@ -0,0 +1 @@ +#include "tst-cleanup0.c" diff --git a/test/nptl/tst-cleanupx1.c b/test/nptl/tst-cleanupx1.c new file mode 100644 index 000000000..21e9e58bd --- /dev/null +++ b/test/nptl/tst-cleanupx1.c @@ -0,0 +1 @@ +#include "tst-cleanup1.c" diff --git a/test/nptl/tst-cleanupx2.c b/test/nptl/tst-cleanupx2.c new file mode 100644 index 000000000..8b9e35093 --- /dev/null +++ b/test/nptl/tst-cleanupx2.c @@ -0,0 +1 @@ +#include "tst-cleanup2.c" diff --git a/test/nptl/tst-cleanupx3.c b/test/nptl/tst-cleanupx3.c new file mode 100644 index 000000000..90baf904f --- /dev/null +++ b/test/nptl/tst-cleanupx3.c @@ -0,0 +1 @@ +#include "tst-cleanup3.c" diff --git a/test/nptl/tst-cleanupx4.c b/test/nptl/tst-cleanupx4.c new file mode 100644 index 000000000..8dea954b5 --- /dev/null +++ b/test/nptl/tst-cleanupx4.c @@ -0,0 +1 @@ +#include "tst-cleanup4.c" diff --git a/test/nptl/tst-cond22.c b/test/nptl/tst-cond22.c new file mode 100644 index 000000000..bd978e50c --- /dev/null +++ b/test/nptl/tst-cond22.c @@ -0,0 +1,160 @@ +#include +#include +#include + + +static pthread_barrier_t b; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + + +static void +cl (void *arg) +{ + pthread_mutex_unlock (&m); +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&m) != 0) + { + printf ("%s: mutex_lock failed\n", __func__); + exit (1); + } + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } + pthread_cleanup_push (cl, NULL); + /* We have to loop here because the cancellation might come after + the cond_wait call left the cancelable area and is then waiting + on the mutex. In this case the beginning of the second cond_wait + call will cause the cancellation to happen. */ + do + if (pthread_cond_wait (&c, &m) != 0) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + while (arg == NULL); + pthread_cleanup_pop (0); + if (pthread_mutex_unlock (&m) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + return NULL; +} + + +static int +do_test (void) +{ + int status = 0; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + return 1; + } + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + return 1; + } + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + if (pthread_cond_signal (&c) != 0) + { + puts ("1st cond_signal failed"); + return 1; + } + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + if (pthread_mutex_unlock (&m) != 0) + { + puts ("1st mutex_unlock failed"); + return 1; + } + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("1st join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("first thread not canceled"); + status = 1; + } + + printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n", + c.__data.__lock, c.__data.__futex, c.__data.__total_seq, + c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex, + c.__data.__nwaiters, c.__data.__broadcast_seq); + + if (pthread_create (&th, NULL, tf, (void *) 1l) != 0) + { + puts ("2nd create failed"); + return 1; + } + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + return 1; + } + if (pthread_mutex_lock (&m) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + if (pthread_cond_signal (&c) != 0) + { + puts ("2nd cond_signal failed"); + return 1; + } + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + return 1; + } + if (pthread_join (th, &res) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (res != NULL) + { + puts ("2nd thread canceled"); + status = 1; + } + + printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n", + c.__data.__lock, c.__data.__futex, c.__data.__total_seq, + c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex, + c.__data.__nwaiters, c.__data.__broadcast_seq); + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond23.c b/test/nptl/tst-cond23.c new file mode 100644 index 000000000..254d821cc --- /dev/null +++ b/test/nptl/tst-cond23.c @@ -0,0 +1,184 @@ +/* Copyright (C) 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2008. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include + + +#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 +static int +check (pthread_condattr_t *condattr, int pshared, clockid_t cl) +{ + clockid_t cl2; + if (pthread_condattr_getclock (condattr, &cl2) != 0) + { + puts ("condattr_getclock failed"); + return 1; + } + if (cl != cl2) + { + printf ("condattr_getclock returned wrong value: %d, expected %d\n", + (int) cl2, (int) cl); + return 1; + } + + int p; + if (pthread_condattr_getpshared (condattr, &p) != 0) + { + puts ("condattr_getpshared failed"); + return 1; + } + else if (p != pshared) + { + printf ("condattr_getpshared returned wrong value: %d, expected %d\n", + p, pshared); + return 1; + } + + return 0; +} + +static int +run_test (clockid_t cl) +{ + pthread_condattr_t condattr; + + printf ("clock = %d\n", (int) cl); + + if (pthread_condattr_init (&condattr) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("1st condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("1st condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, cl)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("2nd condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl)) + return 1; + + if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0) + { + puts ("2nd condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("3rd condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("3rd condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, cl)) + return 1; + + if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0) + { + puts ("4th condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_destroy (&condattr) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + return 0; +} +#endif + + +static int +do_test (void) +{ +#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1 + + puts ("_POSIX_CLOCK_SELECTION not supported, test skipped"); + return 0; + +#else + + int res = run_test (CLOCK_REALTIME); + +# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0 +# if _POSIX_MONOTONIC_CLOCK == 0 + int e = sysconf (_SC_MONOTONIC_CLOCK); + if (e < 0) + puts ("CLOCK_MONOTONIC not supported"); + else if (e == 0) + { + puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0"); + res = 1; + } + else +# endif + res |= run_test (CLOCK_MONOTONIC); +# else + puts ("_POSIX_MONOTONIC_CLOCK not defined"); +# endif + + return res; +#endif +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-dlsym1.c b/test/nptl/tst-dlsym1.c new file mode 100644 index 000000000..3744570c7 --- /dev/null +++ b/test/nptl/tst-dlsym1.c @@ -0,0 +1,66 @@ +/* Test case by Hui Huang . */ +#include +#include +#include +#include + + +static void * +start_routine (void *args) +{ + int i; + void **addrs = (void **) args; + for (i = 0; i < 10000; ++i) + addrs[i % 1024] = dlsym (NULL, "does_not_exist"); + + return addrs; +} + + +static int +do_test (void) +{ + pthread_t tid1, tid2, tid3; + + void *addrs1[1024]; + void *addrs2[1024]; + void *addrs3[1024]; + + if (pthread_create (&tid1, NULL, start_routine, addrs1) != 0) + { + puts ("1st create failed"); + exit (1); + } + if (pthread_create (&tid2, NULL, start_routine, addrs2) != 0) + { + puts ("2nd create failed"); + exit (1); + } + if (pthread_create (&tid3, NULL, start_routine, addrs3) != 0) + { + puts ("3rd create failed"); + exit (1); + } + + if (pthread_join (tid1, NULL) != 0) + { + puts ("1st join failed"); + exit (1); + } + if (pthread_join (tid2, NULL) != 0) + { + puts ("2nd join failed"); + exit (1); + } + if (pthread_join (tid3, NULL) != 0) + { + puts ("2rd join failed"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-fini1.c b/test/nptl/tst-fini1.c new file mode 100644 index 000000000..bec4be1d3 --- /dev/null +++ b/test/nptl/tst-fini1.c @@ -0,0 +1,35 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include + +extern void m (void); + +int +main (void) +{ + alarm (5); + + m (); + + /* The destructor is supposed to run now. Make sure that if it is + not we will notice it by using 42 as the exit code. In case the + destructor is run it will terminate with status zero. */ + return 42; +} diff --git a/test/nptl/tst-fini1mod.c b/test/nptl/tst-fini1mod.c new file mode 100644 index 000000000..492d9ffb8 --- /dev/null +++ b/test/nptl/tst-fini1mod.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + + +static void * +tf (void *arg) +{ + int fds[2]; + if (pipe (fds) != 0) + { + puts ("pipe failed"); + exit (1); + } + + char buf[10]; + read (fds[0], buf, sizeof (buf)); + + puts ("read returned"); + exit (1); +} + +static pthread_t th; + +static void +__attribute ((destructor)) +dest (void) +{ + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + _exit (1); + } + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + _exit (1); + } + /* Exit successfully. */ + _exit (0); +} + +void +m (void) +{ + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + _exit (1); + } +} diff --git a/test/nptl/tst-getpid1.c b/test/nptl/tst-getpid1.c new file mode 100644 index 000000000..4d25b0de7 --- /dev/null +++ b/test/nptl/tst-getpid1.c @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TEST_CLONE_FLAGS +#define TEST_CLONE_FLAGS 0 +#endif + +static int sig; + +static int +f (void *a) +{ + puts ("in f"); + union sigval sival; + sival.sival_int = getpid (); + printf ("pid = %d\n", sival.sival_int); + if (sigqueue (getppid (), sig, sival) != 0) + return 1; + return 0; +} + + +static int +do_test (void) +{ + int mypid = getpid (); + + sig = SIGRTMIN; + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, sig); + if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0) + { + printf ("sigprocmask failed: %m\n"); + return 1; + } + +#ifdef __ia64__ + extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, + size_t __child_stack_size, int __flags, + void *__arg, ...); + char st[256 * 1024] __attribute__ ((aligned)); + pid_t p = __clone2 (f, st, sizeof (st), TEST_CLONE_FLAGS, 0); +#else + char st[128 * 1024] __attribute__ ((aligned)); +# if _STACK_GROWS_DOWN + pid_t p = clone (f, st + sizeof (st), TEST_CLONE_FLAGS, 0); +# elif _STACK_GROWS_UP + pid_t p = clone (f, st, TEST_CLONE_FLAGS, 0); +# else +# error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" +# endif +#endif + if (p == -1) + { + printf("clone failed: %m\n"); + return 1; + } + printf ("new thread: %d\n", (int) p); + + siginfo_t si; + do + if (sigwaitinfo (&ss, &si) < 0) + { + printf("sigwaitinfo failed: %m\n"); + kill (p, SIGKILL); + return 1; + } + while (si.si_signo != sig || si.si_code != SI_QUEUE); + + int e; + if (waitpid (p, &e, __WCLONE) != p) + { + puts ("waitpid failed"); + kill (p, SIGKILL); + return 1; + } + if (!WIFEXITED (e)) + { + if (WIFSIGNALED (e)) + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); + else + puts ("did not terminate correctly"); + return 1; + } + if (WEXITSTATUS (e) != 0) + { + printf ("exit code %d\n", WEXITSTATUS (e)); + return 1; + } + + if (si.si_int != (int) p) + { + printf ("expected PID %d, got si_int %d\n", (int) p, si.si_int); + kill (p, SIGKILL); + return 1; + } + + if (si.si_pid != p) + { + printf ("expected PID %d, got si_pid %d\n", (int) p, (int) si.si_pid); + kill (p, SIGKILL); + return 1; + } + + if (getpid () != mypid) + { + puts ("my PID changed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-getpid2.c b/test/nptl/tst-getpid2.c new file mode 100644 index 000000000..fc98cb60d --- /dev/null +++ b/test/nptl/tst-getpid2.c @@ -0,0 +1,2 @@ +#define TEST_CLONE_FLAGS CLONE_VM +#include "tst-getpid1.c" diff --git a/test/nptl/tst-getpid3.c b/test/nptl/tst-getpid3.c new file mode 100644 index 000000000..f1e77f6b1 --- /dev/null +++ b/test/nptl/tst-getpid3.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include +#include +#include +#include + + +static pid_t pid; + +static void * +pid_thread (void *arg) +{ + if (pid != getpid ()) + { + printf ("pid wrong in thread: should be %d, is %d\n", + (int) pid, (int) getpid ()); + return (void *) 1L; + } + + return NULL; +} + +static int +do_test (void) +{ + pid = getpid (); + + pthread_t thr; + int ret = pthread_create (&thr, NULL, pid_thread, NULL); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + + void *thr_ret; + ret = pthread_join (thr, &thr_ret); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + else if (thr_ret) + { + printf ("thread getpid failed\n"); + return 1; + } + + pid_t child = fork (); + if (child == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + else if (child == 0) + { + if (pid == getpid ()) + { + puts ("pid did not change after fork"); + exit (1); + } + + pid = getpid (); + ret = pthread_create (&thr, NULL, pid_thread, NULL); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + + ret = pthread_join (thr, &thr_ret); + if (ret) + { + printf ("pthread_create failed: %d\n", ret); + return 1; + } + else if (thr_ret) + { + printf ("thread getpid failed\n"); + return 1; + } + + return 0; + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child) + { + puts ("waitpid failed"); + kill (child, SIGKILL); + return 1; + } + + if (!WIFEXITED (status)) + { + if (WIFSIGNALED (status)) + printf ("died from signal %s\n", strsignal (WTERMSIG (status))); + else + puts ("did not terminate correctly"); + return 1; + } + if (WEXITSTATUS (status) != 0) + { + printf ("exit code %d\n", WEXITSTATUS (status)); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-initializers1-c89.c b/test/nptl/tst-initializers1-c89.c new file mode 100644 index 000000000..7c27c1d54 --- /dev/null +++ b/test/nptl/tst-initializers1-c89.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" diff --git a/test/nptl/tst-initializers1-c99.c b/test/nptl/tst-initializers1-c99.c new file mode 100644 index 000000000..7c27c1d54 --- /dev/null +++ b/test/nptl/tst-initializers1-c99.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" diff --git a/test/nptl/tst-initializers1-gnu89.c b/test/nptl/tst-initializers1-gnu89.c new file mode 100644 index 000000000..7c27c1d54 --- /dev/null +++ b/test/nptl/tst-initializers1-gnu89.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" diff --git a/test/nptl/tst-initializers1-gnu99.c b/test/nptl/tst-initializers1-gnu99.c new file mode 100644 index 000000000..7c27c1d54 --- /dev/null +++ b/test/nptl/tst-initializers1-gnu99.c @@ -0,0 +1 @@ +#include "tst-initializers1.c" diff --git a/test/nptl/tst-join6.c b/test/nptl/tst-join6.c new file mode 100644 index 000000000..0c9e7c056 --- /dev/null +++ b/test/nptl/tst-join6.c @@ -0,0 +1,2 @@ +#define WAIT_IN_CHILD 1 +#include "tst-join5.c" diff --git a/test/nptl/tst-oddstacklimit.c b/test/nptl/tst-oddstacklimit.c new file mode 100644 index 000000000..9fbef1889 --- /dev/null +++ b/test/nptl/tst-oddstacklimit.c @@ -0,0 +1 @@ +#include "tst-basic1.c" diff --git a/test/nptl/tst-oncex3.c b/test/nptl/tst-oncex3.c new file mode 100644 index 000000000..08225b88d --- /dev/null +++ b/test/nptl/tst-oncex3.c @@ -0,0 +1 @@ +#include "tst-once3.c" diff --git a/test/nptl/tst-oncex4.c b/test/nptl/tst-oncex4.c new file mode 100644 index 000000000..9b4d98f3f --- /dev/null +++ b/test/nptl/tst-oncex4.c @@ -0,0 +1 @@ +#include "tst-once4.c" diff --git a/test/nptl/tst-rwlock2a.c b/test/nptl/tst-rwlock2a.c new file mode 100644 index 000000000..615de5c01 --- /dev/null +++ b/test/nptl/tst-rwlock2a.c @@ -0,0 +1,2 @@ +#define TYPE PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP +#include "tst-rwlock2.c" diff --git a/test/nptl/tst-sem10.c b/test/nptl/tst-sem10.c new file mode 100644 index 000000000..9f6e870a8 --- /dev/null +++ b/test/nptl/tst-sem10.c @@ -0,0 +1,88 @@ +/* Copyright (C) 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek , 2007. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include + + +static int +do_test (void) +{ + sem_t s; + if (sem_init (&s, 0, 0) == -1) + { + puts ("sem_init failed"); + return 1; + } + + struct timeval tv; + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + return 1; + } + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* Set ts to yesterday. */ + ts.tv_sec -= 86400; + + int type_before; + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_before) != 0) + { + puts ("first pthread_setcanceltype failed"); + return 1; + } + + errno = 0; + if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1) + { + puts ("sem_timedwait succeeded"); + return 1; + } + if (errno != ETIMEDOUT) + { + printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n", + errno); + return 1; + } + + int type_after; + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_after) != 0) + { + puts ("second pthread_setcanceltype failed"); + return 1; + } + if (type_after != PTHREAD_CANCEL_DEFERRED) + { + puts ("sem_timedwait changed cancellation type"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem11.c b/test/nptl/tst-sem11.c new file mode 100644 index 000000000..6633ddd1f --- /dev/null +++ b/test/nptl/tst-sem11.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include + +#ifndef SEM_WAIT +# define SEM_WAIT(s) sem_wait (s) +#endif + +static void * +tf (void *arg) +{ +#ifdef PREPARE + PREPARE +#endif + SEM_WAIT (arg); + return NULL; +} + +int +main (void) +{ + int tries = 5; + pthread_t th; + sem_t s; + again: + if (sem_init (&s, 0, 0) != 0) + { + puts ("sem_init failed"); + return 1; + } + + struct new_sem *is = (struct new_sem *) &s; + + if (is->nwaiters != 0) + { + puts ("nwaiters not initialized"); + return 1; + } + + if (pthread_create (&th, NULL, tf, &s) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + sleep (1); + + 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; + } + if (r != PTHREAD_CANCELED && --tries > 0) + { + /* Maybe we get the scheduling right the next time. */ + sem_destroy (&s); + goto again; + } + + if (is->nwaiters != 0) + { + puts ("nwaiters not reset"); + return 1; + } + + return 0; +} diff --git a/test/nptl/tst-sem12.c b/test/nptl/tst-sem12.c new file mode 100644 index 000000000..71d02b70e --- /dev/null +++ b/test/nptl/tst-sem12.c @@ -0,0 +1,14 @@ +#include +#include + + +#define PREPARE \ + struct timespec ts; \ + struct timeval tv; \ + gettimeofday (&tv, NULL); \ + TIMEVAL_TO_TIMESPEC (&tv, &ts); \ + ts.tv_sec += 60; + +#define SEM_WAIT(s) sem_timedwait (s, &ts) + +#include "tst-sem11.c" diff --git a/test/nptl/tst-signal7.c b/test/nptl/tst-signal7.c new file mode 100644 index 000000000..82ef11c2d --- /dev/null +++ b/test/nptl/tst-signal7.c @@ -0,0 +1,59 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2005. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include + + +static int +do_test (void) +{ + int result = 0; + + errno = 0; + if (sigaction (SIGCANCEL, NULL, NULL) == 0) + { + puts ("sigaction(SIGCANCEL) did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + puts ("sigaction(SIGCANCEL) did not set errno to EINVAL"); + result = 1; + } + + errno = 0; + if (sigaction (SIGSETXID, NULL, NULL) == 0) + { + puts ("sigaction(SIGSETXID) did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + puts ("sigaction(SIGSETXID) did not set errno to EINVAL"); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd6.c b/test/nptl/tst-tsd6.c new file mode 100644 index 000000000..debb1dd36 --- /dev/null +++ b/test/nptl/tst-tsd6.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include + +#define NKEYS 100 +static pthread_key_t keys[NKEYS]; +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + void *res = NULL; + for (int i = 0; i < NKEYS; ++i) + { + void *p = pthread_getspecific (keys[i]); + pthread_setspecific (keys[i], (void *) 7); + if (p != NULL) + res = p; + } + if (arg != NULL) + { + pthread_barrier_wait (arg); + pthread_barrier_wait (arg); + } + return res; +} + + +static int +do_test (void) +{ + pthread_barrier_init (&b, NULL, 2); + + for (int i = 0; i < NKEYS; ++i) + if (pthread_key_create (&keys[i], NULL) != 0) + { + puts ("cannot create keys"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &b) != 0) + { + puts ("cannot create thread in parent"); + return 1; + } + + pthread_barrier_wait (&b); + + pid_t pid = fork (); + if (pid == 0) + { + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("cannot create thread in child"); + exit (1); + } + + void *res; + pthread_join (th, &res); + + exit (res != NULL); + } + else if (pid == -1) + { + puts ("cannot create child process"); + return 1; + } + + int s; + if (TEMP_FAILURE_RETRY (waitpid (pid, &s, 0)) != pid) + { + puts ("failing to wait for child process"); + return 1; + } + + pthread_barrier_wait (&b); + pthread_join (th, NULL); + + return !WIFEXITED (s) ? 2 : WEXITSTATUS (s); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-typesizes.c b/test/nptl/tst-typesizes.c new file mode 100644 index 000000000..545cee6bd --- /dev/null +++ b/test/nptl/tst-typesizes.c @@ -0,0 +1,96 @@ +/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2005. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include + +static const struct +{ + const char *name; + size_t expected; + size_t is; +} types[] = + { +#define T(t, c) \ + { #t, c, sizeof (t) } + T (pthread_attr_t, __SIZEOF_PTHREAD_ATTR_T), + T (pthread_mutex_t, __SIZEOF_PTHREAD_MUTEX_T), + T (pthread_mutexattr_t, __SIZEOF_PTHREAD_MUTEXATTR_T), + T (pthread_cond_t, __SIZEOF_PTHREAD_COND_T), + T (pthread_condattr_t, __SIZEOF_PTHREAD_CONDATTR_T), + T (pthread_rwlock_t, __SIZEOF_PTHREAD_RWLOCK_T), + T (pthread_rwlockattr_t, __SIZEOF_PTHREAD_RWLOCKATTR_T), + T (pthread_barrier_t, __SIZEOF_PTHREAD_BARRIER_T), + T (pthread_barrierattr_t, __SIZEOF_PTHREAD_BARRIERATTR_T) + }; + +static int +do_test (void) +{ + int result = 0; + +#define TEST_TYPE(name) \ + printf ("%s: ", #name); \ + if (sizeof (name) != sizeof (((name *) 0)->__size)) \ + { \ + printf ("expected %zu, is %zu\n", \ + sizeof (((name *) 0)->__size), sizeof (name)); \ + result = 1; \ + } \ + else \ + puts ("OK") + + TEST_TYPE (pthread_mutex_t); + TEST_TYPE (pthread_cond_t); + TEST_TYPE (pthread_rwlock_t); + +#define TEST_TYPE2(name, internal) \ + printf ("%s: ", #name); \ + if (sizeof (((name *) 0)->__size) < sizeof (internal)) \ + { \ + printf ("expected %zu, is %zu\n", \ + sizeof (((name *) 0)->__size), sizeof (internal)); \ + result = 1; \ + } \ + else \ + puts ("OK") + + TEST_TYPE2 (pthread_attr_t, struct pthread_attr); + TEST_TYPE2 (pthread_mutexattr_t, struct pthread_mutexattr); + TEST_TYPE2 (pthread_condattr_t, struct pthread_condattr); + TEST_TYPE2 (pthread_rwlockattr_t, struct pthread_rwlockattr); + TEST_TYPE2 (pthread_barrier_t, struct pthread_barrier); + TEST_TYPE2 (pthread_barrierattr_t, struct pthread_barrierattr); + TEST_TYPE2 (sem_t, struct new_sem); + TEST_TYPE2 (sem_t, struct old_sem); + + for (size_t i = 0; i < sizeof (types) / sizeof (types[0]); ++i) + if (types[i].expected != types[i].is) + { + printf ("%s: expected %zu, is %zu\n", + types[i].name, types[i].expected, types[i].is); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-unload.c b/test/nptl/tst-unload.c new file mode 100644 index 000000000..5c552e22a --- /dev/null +++ b/test/nptl/tst-unload.c @@ -0,0 +1,47 @@ +/* Tests for non-unloading of libpthread. + Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Ulrich Drepper , 2000. + + 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include + +static int +do_test (void) +{ + void *p = dlopen ("libpthread.so.0", RTLD_LAZY); + + if (p == NULL) + { + puts ("failed to load libpthread.so.0"); + return 1; + } + + if (dlclose (p) != 0) + { + puts ("dlclose (libpthread.so.0) failed"); + return 1; + } + + puts ("seems to work"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-vfork1.c b/test/nptl/tst-vfork1.c new file mode 100644 index 000000000..1f36f1ff2 --- /dev/null +++ b/test/nptl/tst-vfork1.c @@ -0,0 +1,150 @@ +/* Test for vfork functions. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include + +/* This test relies on non-POSIX functionality since the child + processes call write and getpid. */ +static int +do_test (void) +{ + int result = 0; + int fd[2]; + + if (pipe (fd) == -1) + { + puts ("pipe failed"); + return 1; + } + + /* First vfork() without previous getpid(). */ + pid_t p1; + if ((p1 = vfork ()) == 0) + { + pid_t p = getpid (); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("1st vfork failed"); + result = 1; + } + + pid_t p2 = 0; + if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("1st read failed"); + result = 1; + } + int r; + if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) + { + puts ("1st waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 1st child failed"); + result = 1; + } + + /* Main process' ID. */ + pid_t p0 = getpid (); + + /* vfork() again, but after a getpid() in the main process. */ + pid_t p3; + if ((p3 = vfork ()) == 0) + { + pid_t p = getpid (); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("2nd vfork failed"); + result = 1; + } + + pid_t p4; + if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("2nd read failed"); + result = 1; + } + if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3) + { + puts ("2nd waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 2nd child failed"); + result = 1; + } + + /* And getpid in the main process again. */ + pid_t p5 = getpid (); + + /* Analysis of the results. */ + if (p0 != p5) + { + printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5); + result = 1; + } + + if (p0 == p1) + { + printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1); + result = 1; + } + + if (p1 != p2) + { + printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2); + result = 1; + } + + if (p0 == p3) + { + printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3); + result = 1; + } + + if (p3 != p4) + { + printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4); + result = 1; + } + + close (fd[0]); + close (fd[1]); + + if (result == 0) + puts ("All OK"); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-vfork1x.c b/test/nptl/tst-vfork1x.c new file mode 100644 index 000000000..1f36f1ff2 --- /dev/null +++ b/test/nptl/tst-vfork1x.c @@ -0,0 +1,150 @@ +/* Test for vfork functions. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include + +/* This test relies on non-POSIX functionality since the child + processes call write and getpid. */ +static int +do_test (void) +{ + int result = 0; + int fd[2]; + + if (pipe (fd) == -1) + { + puts ("pipe failed"); + return 1; + } + + /* First vfork() without previous getpid(). */ + pid_t p1; + if ((p1 = vfork ()) == 0) + { + pid_t p = getpid (); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("1st vfork failed"); + result = 1; + } + + pid_t p2 = 0; + if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("1st read failed"); + result = 1; + } + int r; + if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) + { + puts ("1st waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 1st child failed"); + result = 1; + } + + /* Main process' ID. */ + pid_t p0 = getpid (); + + /* vfork() again, but after a getpid() in the main process. */ + pid_t p3; + if ((p3 = vfork ()) == 0) + { + pid_t p = getpid (); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("2nd vfork failed"); + result = 1; + } + + pid_t p4; + if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("2nd read failed"); + result = 1; + } + if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3) + { + puts ("2nd waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 2nd child failed"); + result = 1; + } + + /* And getpid in the main process again. */ + pid_t p5 = getpid (); + + /* Analysis of the results. */ + if (p0 != p5) + { + printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5); + result = 1; + } + + if (p0 == p1) + { + printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1); + result = 1; + } + + if (p1 != p2) + { + printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2); + result = 1; + } + + if (p0 == p3) + { + printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3); + result = 1; + } + + if (p3 != p4) + { + printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4); + result = 1; + } + + close (fd[0]); + close (fd[1]); + + if (result == 0) + puts ("All OK"); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-vfork2.c b/test/nptl/tst-vfork2.c new file mode 100644 index 000000000..1d096e14a --- /dev/null +++ b/test/nptl/tst-vfork2.c @@ -0,0 +1,199 @@ +/* Test for vfork functions. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int raise_fail; + +static void +alrm (int sig) +{ + if (raise (SIGUSR1) < 0) + raise_fail = 1; +} + +/* This test relies on non-POSIX functionality since the child + processes call write, nanosleep and getpid. */ +static int +do_test (void) +{ + int result = 0; + int fd[2]; + + signal (SIGUSR1, SIG_IGN); + + struct sigaction sa; + sa.sa_handler = alrm; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (SIGALRM, &sa, NULL) < 0) + { + puts ("couldn't set up SIGALRM handler"); + return 1; + } + + if (pipe (fd) == -1) + { + puts ("pipe failed"); + return 1; + } + + struct itimerval it; + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 200 * 1000; + it.it_interval = it.it_value; + if (setitimer (ITIMER_REAL, &it, NULL) < 0) + { + puts ("couldn't set up timer"); + return 1; + } + + /* First vfork() without previous getpid(). */ + pid_t p1; + if ((p1 = vfork ()) == 0) + { + pid_t p = getpid (); + + struct timespec ts; + ts.tv_sec = 1; + ts.tv_nsec = 0; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("1st vfork failed"); + result = 1; + } + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + pid_t p2 = 0; + if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("1st read failed"); + result = 1; + } + int r; + if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) + { + puts ("1st waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 1st child failed"); + result = 1; + } + + /* Main process' ID. */ + pid_t p0 = getpid (); + + /* vfork() again, but after a getpid() in the main process. */ + pid_t p3; + if ((p3 = vfork ()) == 0) + { + pid_t p = getpid (); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("2nd vfork failed"); + result = 1; + } + + pid_t p4; + if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("2nd read failed"); + result = 1; + } + if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3) + { + puts ("2nd waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 2nd child failed"); + result = 1; + } + + /* And getpid in the main process again. */ + pid_t p5 = getpid (); + + /* Analysis of the results. */ + if (p0 != p5) + { + printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5); + result = 1; + } + + if (p0 == p1) + { + printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1); + result = 1; + } + + if (p1 != p2) + { + printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2); + result = 1; + } + + if (p0 == p3) + { + printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3); + result = 1; + } + + if (p3 != p4) + { + printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4); + result = 1; + } + + close (fd[0]); + close (fd[1]); + + if (raise_fail) + { + puts ("raise failed"); + result = 1; + } + + if (result == 0) + puts ("All OK"); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-vfork2x.c b/test/nptl/tst-vfork2x.c new file mode 100644 index 000000000..1d096e14a --- /dev/null +++ b/test/nptl/tst-vfork2x.c @@ -0,0 +1,199 @@ +/* Test for vfork functions. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 2004. + + 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, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int raise_fail; + +static void +alrm (int sig) +{ + if (raise (SIGUSR1) < 0) + raise_fail = 1; +} + +/* This test relies on non-POSIX functionality since the child + processes call write, nanosleep and getpid. */ +static int +do_test (void) +{ + int result = 0; + int fd[2]; + + signal (SIGUSR1, SIG_IGN); + + struct sigaction sa; + sa.sa_handler = alrm; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (SIGALRM, &sa, NULL) < 0) + { + puts ("couldn't set up SIGALRM handler"); + return 1; + } + + if (pipe (fd) == -1) + { + puts ("pipe failed"); + return 1; + } + + struct itimerval it; + it.it_value.tv_sec = 0; + it.it_value.tv_usec = 200 * 1000; + it.it_interval = it.it_value; + if (setitimer (ITIMER_REAL, &it, NULL) < 0) + { + puts ("couldn't set up timer"); + return 1; + } + + /* First vfork() without previous getpid(). */ + pid_t p1; + if ((p1 = vfork ()) == 0) + { + pid_t p = getpid (); + + struct timespec ts; + ts.tv_sec = 1; + ts.tv_nsec = 0; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("1st vfork failed"); + result = 1; + } + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + pid_t p2 = 0; + if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("1st read failed"); + result = 1; + } + int r; + if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1) + { + puts ("1st waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 1st child failed"); + result = 1; + } + + /* Main process' ID. */ + pid_t p0 = getpid (); + + /* vfork() again, but after a getpid() in the main process. */ + pid_t p3; + if ((p3 = vfork ()) == 0) + { + pid_t p = getpid (); + _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p)); + } + else if (p1 == -1) + { + puts ("2nd vfork failed"); + result = 1; + } + + pid_t p4; + if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t)) + { + puts ("2nd read failed"); + result = 1; + } + if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3) + { + puts ("2nd waitpid failed"); + result = 1; + } + else if (r != 0) + { + puts ("write in 2nd child failed"); + result = 1; + } + + /* And getpid in the main process again. */ + pid_t p5 = getpid (); + + /* Analysis of the results. */ + if (p0 != p5) + { + printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5); + result = 1; + } + + if (p0 == p1) + { + printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1); + result = 1; + } + + if (p1 != p2) + { + printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2); + result = 1; + } + + if (p0 == p3) + { + printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3); + result = 1; + } + + if (p3 != p4) + { + printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4); + result = 1; + } + + close (fd[0]); + close (fd[1]); + + if (raise_fail) + { + puts ("raise failed"); + result = 1; + } + + if (result == 0) + puts ("All OK"); + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" -- cgit v1.2.3