diff options
Diffstat (limited to 'test')
258 files changed, 30039 insertions, 9 deletions
diff --git a/test/.gitignore b/test/.gitignore index f4fc7c743..464130d57 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -163,7 +163,7 @@ nptl/tst-detach1 nptl/tst-eintr[1-5] nptl/tst-exec[2-4] nptl/tst-exit[1-3] -nptl/tst-flock1 +nptl/tst-flock[1-2] nptl/tst-fork[1-4] nptl/tst-initializers1 nptl/tst-join[1-5] diff --git a/test/Makefile b/test/Makefile index bd68884d3..857ac8ad9 100644 --- a/test/Makefile +++ b/test/Makefile @@ -26,6 +26,9 @@ endif ifneq ($(UCLIBC_HAS_REGEX),y) DIRS := $(filter-out regex,$(DIRS)) endif +ifneq ($(UCLIBC_HAS_THREADS_NATIVE),y) + DIRS := $(filter-out tls nptl,$(DIRS)) +endif ifneq ($(UCLIBC_HAS_WCHAR),y) DIRS := $(filter-out locale-mbwc,$(DIRS)) endif @@ -41,7 +44,7 @@ endif test check all: run -run: subdirs_run +run: compile subdirs_run compile: $(top_builddir)/$(LOCAL_INSTALL_PATH) subdirs_compile diff --git a/test/Rules.mak b/test/Rules.mak index 6acc13ffa..7c15bae1f 100644 --- a/test/Rules.mak +++ b/test/Rules.mak @@ -63,9 +63,9 @@ CFLAGS += $(OPTIMIZATION) $(CPU_CFLAGS) $(XWARNINGS) # Can't add $(OPTIMIZATION) here, it may be target-specific. # Just adding -Os for now. -HOST_CFLAGS += $(XCOMMON_CFLAGS) -Os $(XWARNINGS) +HOST_CFLAGS += $(XCOMMON_CFLAGS) -Os $(XWARNINGS) -std=gnu99 -LDFLAGS := $(CPU_LDFLAGS-y) -Wl,-z,defs -Wl,-z,now +LDFLAGS := $(CPU_LDFLAGS-y) -Wl,-z,now ifeq ($(DODEBUG),y) CFLAGS += -g HOST_CFLAGS += -g diff --git a/test/Test.mak b/test/Test.mak index ce8906208..43562f2d7 100644 --- a/test/Test.mak +++ b/test/Test.mak @@ -21,6 +21,10 @@ endif U_TARGETS := $(TESTS) G_TARGETS := $(addsuffix _glibc,$(U_TARGETS)) +ifneq ($(GLIBC_TESTS_DISABLED),) +G_TARGETS := $(filter-out $(GLIBC_TESTS_DISABLED),$(G_TARGETS)) +endif + ifeq ($(GLIBC_ONLY),) TARGETS += $(U_TARGETS) endif @@ -29,12 +33,12 @@ TARGETS += $(G_TARGETS) endif CLEAN_TARGETS := $(U_TARGETS) $(G_TARGETS) -CLEAN_TARGETS += $(TESTS_DISABLED) $(addsuffix _glibc,$(TESTS_DISABLED)) +CLEAN_TARGETS += $(TESTS_DISABLED) $(addsuffix _glibc,$(TESTS_DISABLED)) $(GLIBC_TESTS_DISABLED) COMPILE_TARGETS := $(TARGETS) RUN_TARGETS := $(addsuffix .exe,$(TARGETS)) # provide build rules even for disabled tests: U_TARGETS += $(TESTS_DISABLED) -G_TARGETS += $(addsuffix _glibc,$(TESTS_DISABLED)) +G_TARGETS += $(addsuffix _glibc,$(TESTS_DISABLED)) $(GLIBC_TESTS_DISABLED) TARGETS += $(SHELL_TESTS) CFLAGS += $(CFLAGS_$(notdir $(CURDIR))) @@ -76,9 +80,8 @@ define exec_test endef test check all: run -run: $(RUN_TARGETS) compile - -$(RUN_TARGETS): $(TARGETS) +run: $(RUN_TARGETS) +$(RUN_TARGETS): $(exec_test) $(diff_test) ifeq ($(UCLIBC_ONLY),) diff --git a/test/dlopen/Makefile b/test/dlopen/Makefile index ef15d861d..92d14b90e 100644 --- a/test/dlopen/Makefile +++ b/test/dlopen/Makefile @@ -4,4 +4,9 @@ top_builddir=../../ include ../Rules.mak -include Makefile.in +ifneq ($(HAVE_SHARED),y) +TESTS_DISABLED := test3 +LDFLAGS_libtest.so := -lpthread +endif + include ../Test.mak diff --git a/test/nptl/Makefile b/test/nptl/Makefile new file mode 100644 index 000000000..a99c5d16f --- /dev/null +++ b/test/nptl/Makefile @@ -0,0 +1,7 @@ +# uClibc NPTL tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +top_builddir=../../ +include ../Rules.mak +-include Makefile.in +include ../Test.mak diff --git a/test/nptl/Makefile.in b/test/nptl/Makefile.in new file mode 100644 index 000000000..c6d832b9b --- /dev/null +++ b/test/nptl/Makefile.in @@ -0,0 +1,153 @@ +# uClibc NPTL tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +TESTS := tst-align tst-align2 tst-atfork1 tst-attr1 tst-attr2 tst-attr3 \ + tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 tst-basic1 \ + tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ + tst-cancel1 tst-cancel2 tst-cancel3 tst-cancel6 tst-cancel7 \ + tst-cancel8 tst-cancel9 tst-cancel10 tst-cancel11 tst-cancel12 \ + tst-cancel13 tst-cancel14 tst-cancel15 tst-cancel16 \ + tst-cancel19 tst-cancel20 tst-cancel21 tst-cancel22 \ + tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 \ + tst-cleanup4 tst-clock1 tst-clock2 tst-cond1 tst-cond2 \ + tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 tst-cond8 \ + tst-cond9 tst-cond10 tst-cond11 tst-cond12 tst-cond13 \ + tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 \ + tst-cond19 tst-cond20 tst-cond21 tst-detach1 tst-eintr1 \ + tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 tst-exec2 tst-exec3 \ + tst-exec4 tst-exit1 tst-exit2 tst-exit3 tst-flock1 tst-flock2 \ + tst-fork1 tst-fork2 tst-fork3 tst-fork4 tst-initializers1 \ + tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-key1 \ + tst-key2 tst-key3 tst-key4 tst-kill1 tst-kill2 tst-kill3 \ + tst-kill4 tst-kill5 tst-kill6 tst-mutex1 tst-mutex2 tst-mutex3 \ + tst-mutex4 tst-mutex5 tst-mutex6 tst-mutex7 tst-mutex8 \ + tst-mutex9 tst-mutex5a tst-mutex7a tst-once1 tst-once2 \ + tst-once3 tst-once4 tst-popen1 tst-raise1 tst-rwlock1 \ + tst-rwlock2 tst-rwlock3 tst-rwlock4 tst-rwlock5 tst-rwlock6 \ + tst-rwlock7 tst-rwlock8 tst-rwlock9 tst-rwlock10 tst-rwlock11 \ + tst-rwlock12 tst-rwlock13 tst-rwlock14 tst-sched1 tst-sem1 \ + tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 tst-sem8 \ + tst-sem9 tst-signal1 tst-signal2 tst-signal3 tst-signal4 \ + 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 + +# +# These are for the RT library and POSIX timers. +# +TESTS += tst-clock tst-clock_nanosleep tst-cpuclock1 tst-cpuclock2 \ + tst-cputimer1 tst-cputimer2 tst-cputimer3 tst-mqueue1 \ + tst-mqueue2 tst-mqueue3 tst-mqueue4 tst-mqueue5 tst-mqueue6 \ + tst-mqueue7 tst-mqueue8 tst-mqueue9 tst-timer2 tst-timer3 \ + tst-timer4 tst-timer5 + +ifeq ($(UCLIBC_HAS_OBSOLETE_BSD_SIGNAL),) +TESTS_DISABLED := tst-exec2 tst-exec3 tst-exec4 +endif + +GLIBC_TESTS_DISABLED := tst-eintr1_glibc tst-eintr2_glibc \ + tst-eintr3_glibc tst-eintr4_glibc tst-eintr5_glibc \ + tst-tls1_glibc tst-tls2_glibc tst-tls3_glibc \ + tst-tls4_glibc tst-tls5_glibc + + +PTDIR := $(top_builddir)libpthread/nptl + +EXTRA_CFLAGS := -DNOT_IN_libc=1 -D_LIBC -D__USE_GNU -std=gnu99 \ + -I$(PTDIR) -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux \ + -I$(PTDIR)/sysdeps/pthread \ + -I$(PTDIR)/sysdeps/pthread/bits \ + -I$(PTDIR)/sysdeps/generic \ + -I$(top_builddir)ldso/include \ + -I$(top_builddir)ldso/ldso/$(TARGET_ARCH) \ + -I$(top_builddir)include \ + -include $(top_builddir)include/libc-symbols.h + +ifeq ($(TARGET_ARCH),i386) +CFLAGS_tst-align.o := -malign-double -mpreferred-stack-boundary=4 +endif +ifeq ($(TARGET_ARCH),i686) +CFLAGS_tst-align.o := -malign-double -mpreferred-stack-boundary=4 -msse +endif +CFLAGS_tst-cleanup4aux.o := -W -Wall -sjh +CFLAGS_tst-initializers1.o := -W -Wall -Werror +CFLAGS_tst-tls3.o := tst-tls3mod.so +CFLAGS_tst-tls4.o := tst-tls4moda.so tst-tls4modb.so +CFLAGS_tst-tls5.o := tst-tls5mod.so +CFLAGS_tst-tls3mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls4moda.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls4modb.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5moda.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5modb.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +CFLAGS_tst-tls5modc.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc +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 + +EXTRA_LDFLAGS := -lpthread + +LDFLAGS_tst-cleanup4 := tst-cleanup4aux.o +LDFLAGS_tst-clock2 := -lrt +LDFLAGS_tst-cond11 := -lrt +LDFLAGS_tst-cond19 := -lrt +LDFLAGS_tst-rwlock14 := -lrt +LDFLAGS_tst-tls3 := -ldl -rdynamic tst-tls3mod.so +LDFLAGS_tst-tls4 := -ldl +LDFLAGS_tst-tls5 := tst-tls5mod.so +LDFLAGS_tst-clock := -lrt +LDFLAGS_tst-clock_nanosleep := -lrt +LDFLAGS_tst-cpuclock1 := -lrt +LDFLAGS_tst-cpuclock2 := -lrt +LDFLAGS_tst-cputimer1 := -lrt +LDFLAGS_tst-cputimer2 := -lrt +LDFLAGS_tst-cputimer3 := -lrt +LDFLAGS_tst-mqueue1 := -lrt +LDFLAGS_tst-mqueue2 := -lrt +LDFLAGS_tst-mqueue3 := -lrt +LDFLAGS_tst-mqueue4 := -lrt +LDFLAGS_tst-mqueue5 := -lrt +LDFLAGS_tst-mqueue6 := -lrt +LDFLAGS_tst-mqueue7 := -lrt +LDFLAGS_tst-mqueue8 := -lrt +LDFLAGS_tst-mqueue9 := -lrt +LDFLAGS_tst-timer2 := -lrt +LDFLAGS_tst-timer3 := -lrt +LDFLAGS_tst-timer4 := -lrt +LDFLAGS_tst-timer5 := -lrt +LDFLAGS_tst-tls3mod.so := -shared -static-libgcc -lpthread +LDFLAGS_tst-tls4moda.so := -shared -static-libgcc +LDFLAGS_tst-tls4modb.so := -shared -static-libgcc +LDFLAGS_tst-tls5mod.so := -shared -static-libgcc -Wl,-soname,tst-tls5mod.so +LDFLAGS_tst-tls5moda.so := -shared -static-libgcc +LDFLAGS_tst-tls5modb.so := -shared -static-libgcc +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 + +# +# Special case +# +tst-cleanup4aux.o: + $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) -c tst-cleanup4aux.c -o $@ + +tst-cleanup4: tst-cleanup4aux.o +tst-tls3: tst-tls3mod.so +tst-tls4: tst-tls4moda.so tst-tls4modb.so +tst-tls5: tst-tls5mod.so tst-tls5moda.so tst-tls5modb.so \ + tst-tls5modc.so tst-tls5modd.so tst-tls5mode.so tst-tls5modf.so + +OPTS_tst-cancel7 = --command ./tst-cancel7 +OPTS_tst-mqueue7 = -- ./tst-mqueue7 +OPTS_tst-exec4 = ./tst-exec4 + +RET_tst-clock2 := 1 +RET_tst-cputimer1 := 1 +RET_tst-cputimer2 := 1 +RET_tst-cputimer3 := 1 + +WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" TIMEOUTFACTOR=100 diff --git a/test/nptl/tst-align.c b/test/nptl/tst-align.c new file mode 100644 index 000000000..381db8f4e --- /dev/null +++ b/test/nptl/tst-align.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include "tst-stack-align.h" + +static void * +tf (void *arg) +{ + bool ok = true; + + puts ("in thread"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? NULL : (void *) -1l; +} + +static int +do_test (void) +{ + bool ok = true; + + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("join failed"); + return 1; + } + + if (res != NULL) + ok = false; + + return ok ? 0 : 1; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-align2.c b/test/nptl/tst-align2.c new file mode 100644 index 000000000..7d8be53da --- /dev/null +++ b/test/nptl/tst-align2.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <sched.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <sys/wait.h> +#include <unistd.h> +#include "tst-stack-align.h" + +static int +f (void *arg) +{ + bool ok = true; + + if (TEST_STACK_ALIGN ()) + ok = false; + + return ok ? 0 : 1; +} + +static int +do_test (void) +{ + bool ok = true; + + puts ("in main"); + + if (TEST_STACK_ALIGN ()) + ok = false; + +#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]; + pid_t p = __clone2 (f, st, sizeof (st), 0, 0); +#else + char st[128 * 1024]; + pid_t p = clone (f, st + sizeof (st), 0, 0); +#endif + if (p == -1) + { + printf("clone failed: %m\n"); + return 1; + } + + 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) + ok = false; + + return ok ? 0 : 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-atfork1.c b/test/nptl/tst-atfork1.c new file mode 100644 index 000000000..b42ab4246 --- /dev/null +++ b/test/nptl/tst-atfork1.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static int val; + + +static void +prepare1 (void) +{ + val *= 2; +} + +static void +prepare2 (void) +{ + ++val; +} + +static void +parent1 (void) +{ + val += 4; +} + +static void +parent2 (void) +{ + val *= 4; +} + +static void +child1 (void) +{ + val += 8; +} + +static void +child2 (void) +{ + val *= 8; +} + + +static int +do_test (void) +{ + pid_t pid; + int status = 0; + + if (pthread_atfork (prepare1, parent1, child1) != 0) + { + puts ("1st atfork failed"); + exit (1); + } + if (pthread_atfork (prepare2, parent2, child2) != 0) + { + puts ("2nd atfork failed"); + exit (1); + } + + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid != 0) + { + /* Parent. */ + if (val != 24) + { + printf ("expected val=%d, got %d\n", 24, val); + exit (1); + } + + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + exit (1); + } + } + else + { + /* Child. */ + if (val != 80) + { + printf ("expected val=%d, got %d\n", 80, val); + exit (2); + } + } + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-attr1.c b/test/nptl/tst-attr1.c new file mode 100644 index 000000000..13b62a69d --- /dev/null +++ b/test/nptl/tst-attr1.c @@ -0,0 +1,306 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +int +do_test (void) +{ + int i; + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + pthread_mutexattr_t ma; + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + pthread_rwlockattr_t rwa; + + if (pthread_rwlockattr_init (&rwa) != 0) + { + puts ("rwlockattr_init failed"); + exit (1); + } + + /* XXX Remove if default value is clear. */ + pthread_attr_setinheritsched (&a, PTHREAD_INHERIT_SCHED); + pthread_attr_setschedpolicy (&a, SCHED_OTHER); + pthread_attr_setscope (&a, PTHREAD_SCOPE_SYSTEM); + + for (i = 0; i < 10000; ++i) + { + long int r = random (); + + if (r != PTHREAD_CREATE_DETACHED && r != PTHREAD_CREATE_JOINABLE) + { + int e = pthread_attr_setdetachstate (&a, r); + + if (e == 0) + { + printf ("attr_setdetachstate with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setdetachstate didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("attr_getdetachstate failed"); + exit (1); + } + + if (s != PTHREAD_CREATE_JOINABLE) + { + printf ("\ +detach state changed to %d by invalid setdetachstate call\n", s); + exit (1); + } + } + + if (r != PTHREAD_INHERIT_SCHED && r != PTHREAD_EXPLICIT_SCHED) + { + int e = pthread_attr_setinheritsched (&a, r); + + if (e == 0) + { + printf ("attr_setinheritsched with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setinheritsched didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("attr_getinheritsched failed"); + exit (1); + } + + if (s != PTHREAD_INHERIT_SCHED) + { + printf ("\ +inheritsched changed to %d by invalid setinheritsched call\n", s); + exit (1); + } + } + + if (r != SCHED_OTHER && r != SCHED_RR && r != SCHED_FIFO) + { + int e = pthread_attr_setschedpolicy (&a, r); + + if (e == 0) + { + printf ("attr_setschedpolicy with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setschedpolicy didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("attr_getschedpolicy failed"); + exit (1); + } + + if (s != SCHED_OTHER) + { + printf ("\ +schedpolicy changed to %d by invalid setschedpolicy call\n", s); + exit (1); + } + } + + if (r != PTHREAD_SCOPE_SYSTEM && r != PTHREAD_SCOPE_PROCESS) + { + int e = pthread_attr_setscope (&a, r); + + if (e == 0) + { + printf ("attr_setscope with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("attr_setscope didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("attr_getscope failed"); + exit (1); + } + + if (s != PTHREAD_SCOPE_SYSTEM) + { + printf ("\ +contentionscope changed to %d by invalid setscope call\n", s); + exit (1); + } + } + + if (r != PTHREAD_PROCESS_PRIVATE && r != PTHREAD_PROCESS_SHARED) + { + int e = pthread_mutexattr_setpshared (&ma, r); + + if (e == 0) + { + printf ("mutexattr_setpshared with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("mutexattr_setpshared didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_mutexattr_getpshared (&ma, &s) != 0) + { + puts ("mutexattr_getpshared failed"); + exit (1); + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + printf ("\ +pshared changed to %d by invalid mutexattr_setpshared call\n", s); + exit (1); + } + + e = pthread_rwlockattr_setpshared (&rwa, r); + + if (e == 0) + { + printf ("rwlockattr_setpshared with value %ld succeeded\n", r); + exit (1); + } + if (e != EINVAL) + { + puts ("rwlockattr_setpshared didn't return EINVAL"); + exit (1); + } + + if (pthread_rwlockattr_getpshared (&rwa, &s) != 0) + { + puts ("rwlockattr_getpshared failed"); + exit (1); + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + printf ("\ +pshared changed to %d by invalid rwlockattr_setpshared call\n", s); + exit (1); + } + } + + if (r != PTHREAD_CANCEL_ENABLE && r != PTHREAD_CANCEL_DISABLE) + { + int e = pthread_setcancelstate (r, NULL); + + if (e == 0) + { + printf ("setcancelstate with value %ld succeeded\n", r); + exit (1); + } + + if (e != EINVAL) + { + puts ("setcancelstate didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, &s) != 0) + { + puts ("setcancelstate failed for PTHREAD_CANCEL_ENABLE"); + exit (1); + } + + if (s != PTHREAD_CANCEL_ENABLE) + { + puts ("invalid setcancelstate changed state"); + exit (1); + } + } + + if (r != PTHREAD_CANCEL_DEFERRED && r != PTHREAD_CANCEL_ASYNCHRONOUS) + { + int e = pthread_setcanceltype (r, NULL); + + if (e == 0) + { + printf ("setcanceltype with value %ld succeeded\n", r); + exit (1); + } + + if (e != EINVAL) + { + puts ("setcanceltype didn't return EINVAL"); + exit (1); + } + + int s; + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &s) != 0) + { + puts ("setcanceltype failed for PTHREAD_CANCEL_DEFERRED"); + exit (1); + } + + if (s != PTHREAD_CANCEL_DEFERRED) + { + puts ("invalid setcanceltype changed state"); + exit (1); + } + } + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-attr2.c b/test/nptl/tst-attr2.c new file mode 100644 index 000000000..a60598dd7 --- /dev/null +++ b/test/nptl/tst-attr2.c @@ -0,0 +1,317 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +int +do_test (void) +{ + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + /* Check default value of detach state. */ + int s; + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("1st attr_getdestachstate failed"); + exit (1); + } + if (s != PTHREAD_CREATE_JOINABLE) + { + printf ("\ +default detach state wrong: %d, expected %d (PTHREAD_CREATE_JOINABLE)\n", + s, PTHREAD_CREATE_JOINABLE); + exit (1); + } + + int e = pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED); + if (e != 0) + { + puts ("1st attr_setdetachstate failed"); + exit (1); + } + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("2nd attr_getdestachstate failed"); + exit (1); + } + if (s != PTHREAD_CREATE_DETACHED) + { + puts ("PTHREAD_CREATE_DETACHED set, but not given back"); + exit (1); + } + + e = pthread_attr_setdetachstate (&a, PTHREAD_CREATE_JOINABLE); + if (e != 0) + { + puts ("2nd attr_setdetachstate failed"); + exit (1); + } + if (pthread_attr_getdetachstate (&a, &s) != 0) + { + puts ("3rd attr_getdestachstate failed"); + exit (1); + } + if (s != PTHREAD_CREATE_JOINABLE) + { + puts ("PTHREAD_CREATE_JOINABLE set, but not given back"); + exit (1); + } + + + size_t g; + if (pthread_attr_getguardsize (&a, &g) != 0) + { + puts ("1st attr_getguardsize failed"); + exit (1); + } + if (g != (size_t) sysconf (_SC_PAGESIZE)) + { + printf ("default guardsize %zu, expected %ld (PAGESIZE)\n", + g, sysconf (_SC_PAGESIZE)); + exit (1); + } + + e = pthread_attr_setguardsize (&a, 0); + if (e != 0) + { + puts ("1st attr_setguardsize failed"); + exit (1); + } + if (pthread_attr_getguardsize (&a, &g) != 0) + { + puts ("2nd attr_getguardsize failed"); + exit (1); + } + if (g != 0) + { + printf ("guardsize set to zero but %zu returned\n", g); + exit (1); + } + + e = pthread_attr_setguardsize (&a, 1); + if (e != 0) + { + puts ("2nd attr_setguardsize failed"); + exit (1); + } + if (pthread_attr_getguardsize (&a, &g) != 0) + { + puts ("3rd attr_getguardsize failed"); + exit (1); + } + if (g != 1) + { + printf ("guardsize set to 1 but %zu returned\n", g); + exit (1); + } + + + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("1st attr_getinheritsched failed"); + exit (1); + } + /* XXX What is the correct default value. */ + if (s != PTHREAD_INHERIT_SCHED && s != PTHREAD_EXPLICIT_SCHED) + { + puts ("incorrect default value for inheritsched"); + exit (1); + } + + e = pthread_attr_setinheritsched (&a, PTHREAD_EXPLICIT_SCHED); + if (e != 0) + { + puts ("1st attr_setinheritsched failed"); + exit (1); + } + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("2nd attr_getinheritsched failed"); + exit (1); + } + if (s != PTHREAD_EXPLICIT_SCHED) + { + printf ("inheritsched set to PTHREAD_EXPLICIT_SCHED, but got %d\n", s); + exit (1); + } + + e = pthread_attr_setinheritsched (&a, PTHREAD_INHERIT_SCHED); + if (e != 0) + { + puts ("2nd attr_setinheritsched failed"); + exit (1); + } + if (pthread_attr_getinheritsched (&a, &s) != 0) + { + puts ("3rd attr_getinheritsched failed"); + exit (1); + } + if (s != PTHREAD_INHERIT_SCHED) + { + printf ("inheritsched set to PTHREAD_INHERIT_SCHED, but got %d\n", s); + exit (1); + } + + + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("1st attr_getschedpolicy failed"); + exit (1); + } + /* XXX What is the correct default value. */ + if (s != SCHED_OTHER && s != SCHED_FIFO && s != SCHED_RR) + { + puts ("incorrect default value for schedpolicy"); + exit (1); + } + + e = pthread_attr_setschedpolicy (&a, SCHED_RR); + if (e != 0) + { + puts ("1st attr_setschedpolicy failed"); + exit (1); + } + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("2nd attr_getschedpolicy failed"); + exit (1); + } + if (s != SCHED_RR) + { + printf ("schedpolicy set to SCHED_RR, but got %d\n", s); + exit (1); + } + + e = pthread_attr_setschedpolicy (&a, SCHED_FIFO); + if (e != 0) + { + puts ("2nd attr_setschedpolicy failed"); + exit (1); + } + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("3rd attr_getschedpolicy failed"); + exit (1); + } + if (s != SCHED_FIFO) + { + printf ("schedpolicy set to SCHED_FIFO, but got %d\n", s); + exit (1); + } + + e = pthread_attr_setschedpolicy (&a, SCHED_OTHER); + if (e != 0) + { + puts ("3rd attr_setschedpolicy failed"); + exit (1); + } + if (pthread_attr_getschedpolicy (&a, &s) != 0) + { + puts ("4th attr_getschedpolicy failed"); + exit (1); + } + if (s != SCHED_OTHER) + { + printf ("schedpolicy set to SCHED_OTHER, but got %d\n", s); + exit (1); + } + + + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("1st attr_getscope failed"); + exit (1); + } + /* XXX What is the correct default value. */ + if (s != PTHREAD_SCOPE_SYSTEM && s != PTHREAD_SCOPE_PROCESS) + { + puts ("incorrect default value for contentionscope"); + exit (1); + } + + e = pthread_attr_setscope (&a, PTHREAD_SCOPE_PROCESS); + if (e != ENOTSUP) + { + if (e != 0) + { + puts ("1st attr_setscope failed"); + exit (1); + } + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("2nd attr_getscope failed"); + exit (1); + } + if (s != PTHREAD_SCOPE_PROCESS) + { + printf ("\ +contentionscope set to PTHREAD_SCOPE_PROCESS, but got %d\n", s); + exit (1); + } + } + + e = pthread_attr_setscope (&a, PTHREAD_SCOPE_SYSTEM); + if (e != 0) + { + puts ("2nd attr_setscope failed"); + exit (1); + } + if (pthread_attr_getscope (&a, &s) != 0) + { + puts ("3rd attr_getscope failed"); + exit (1); + } + if (s != PTHREAD_SCOPE_SYSTEM) + { + printf ("contentionscope set to PTHREAD_SCOPE_SYSTEM, but got %d\n", s); + exit (1); + } + + char buf[1]; + e = pthread_attr_setstack (&a, buf, 1); + if (e != EINVAL) + { + puts ("setstack with size 1 did not produce EINVAL"); + exit (1); + } + + e = pthread_attr_setstacksize (&a, 1); + if (e != EINVAL) + { + puts ("setstacksize with size 1 did not produce EINVAL"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-attr3.c b/test/nptl/tst-attr3.c new file mode 100644 index 000000000..29b4bbe37 --- /dev/null +++ b/test/nptl/tst-attr3.c @@ -0,0 +1,420 @@ +/* pthread_getattr_np test. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void * +tf (void *arg) +{ + pthread_attr_t a, *ap, a2; + int err; + void *result = NULL; + + if (arg == NULL) + { + ap = &a2; + err = pthread_attr_init (ap); + if (err) + { + error (0, err, "pthread_attr_init failed"); + return tf; + } + } + else + ap = (pthread_attr_t *) arg; + + err = pthread_getattr_np (pthread_self (), &a); + if (err) + { + error (0, err, "pthread_getattr_np failed"); + result = tf; + } + + int detachstate1, detachstate2; + err = pthread_attr_getdetachstate (&a, &detachstate1); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = tf; + } + else + { + err = pthread_attr_getdetachstate (ap, &detachstate2); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = tf; + } + else if (detachstate1 != detachstate2) + { + error (0, 0, "detachstate differs %d != %d", + detachstate1, detachstate2); + result = tf; + } + } + + void *stackaddr; + size_t stacksize; + err = pthread_attr_getstack (&a, &stackaddr, &stacksize); + if (err) + { + error (0, err, "pthread_attr_getstack failed"); + result = tf; + } + else if ((void *) &a < stackaddr + || (void *) &a >= stackaddr + stacksize) + { + error (0, 0, "pthread_attr_getstack returned range does not cover thread's stack"); + result = tf; + } + else + printf ("thread stack %p-%p (0x%zx)\n", stackaddr, stackaddr + stacksize, + stacksize); + + size_t guardsize1, guardsize2; + err = pthread_attr_getguardsize (&a, &guardsize1); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = tf; + } + else + { + err = pthread_attr_getguardsize (ap, &guardsize2); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = tf; + } + else if (guardsize1 != guardsize2) + { + error (0, 0, "guardsize differs %zd != %zd", + guardsize1, guardsize2); + result = tf; + } + else + printf ("thread guardsize %zd\n", guardsize1); + } + + int scope1, scope2; + err = pthread_attr_getscope (&a, &scope1); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = tf; + } + else + { + err = pthread_attr_getscope (ap, &scope2); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = tf; + } + else if (scope1 != scope2) + { + error (0, 0, "scope differs %d != %d", + scope1, scope2); + result = tf; + } + } + + int inheritsched1, inheritsched2; + err = pthread_attr_getinheritsched (&a, &inheritsched1); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = tf; + } + else + { + err = pthread_attr_getinheritsched (ap, &inheritsched2); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = tf; + } + else if (inheritsched1 != inheritsched2) + { + error (0, 0, "inheritsched differs %d != %d", + inheritsched1, inheritsched2); + result = tf; + } + } + + cpu_set_t c1, c2; + err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1); + if (err == 0) + { + err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2); + if (err) + { + error (0, err, "pthread_attr_getaffinity_np failed"); + result = tf; + } + else if (memcmp (&c1, &c2, sizeof (c1))) + { + error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np"); + result = tf; + } + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = tf; + } + + if (ap == &a2) + { + err = pthread_attr_destroy (ap); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = tf; + } + } + + return result; +} + + +static int +do_test (void) +{ + int result = 0; + pthread_attr_t a; + cpu_set_t c1, c2; + + int err = pthread_attr_init (&a); + if (err) + { + error (0, err, "pthread_attr_init failed"); + result = 1; + } + + err = pthread_attr_getaffinity_np (&a, sizeof (c1), &c1); + if (err && err != ENOSYS) + { + error (0, err, "pthread_attr_getaffinity_np failed"); + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + err = pthread_getattr_np (pthread_self (), &a); + if (err) + { + error (0, err, "pthread_getattr_np failed"); + result = 1; + } + + int detachstate; + err = pthread_attr_getdetachstate (&a, &detachstate); + if (err) + { + error (0, err, "pthread_attr_getdetachstate failed"); + result = 1; + } + else if (detachstate != PTHREAD_CREATE_JOINABLE) + { + error (0, 0, "initial thread not joinable"); + result = 1; + } + + void *stackaddr; + size_t stacksize; + err = pthread_attr_getstack (&a, &stackaddr, &stacksize); + if (err) + { + error (0, err, "pthread_attr_getstack failed"); + result = 1; + } + else if ((void *) &a < stackaddr + || (void *) &a >= stackaddr + stacksize) + { + error (0, 0, "pthread_attr_getstack returned range does not cover main's stack"); + result = 1; + } + else + printf ("initial thread stack %p-%p (0x%zx)\n", stackaddr, + stackaddr + stacksize, stacksize); + + size_t guardsize; + err = pthread_attr_getguardsize (&a, &guardsize); + if (err) + { + error (0, err, "pthread_attr_getguardsize failed"); + result = 1; + } + else if (guardsize != 0) + { + error (0, 0, "pthread_attr_getguardsize returned %zd != 0", + guardsize); + result = 1; + } + + int scope; + err = pthread_attr_getscope (&a, &scope); + if (err) + { + error (0, err, "pthread_attr_getscope failed"); + result = 1; + } + else if (scope != PTHREAD_SCOPE_SYSTEM) + { + error (0, 0, "pthread_attr_getscope returned %d != PTHREAD_SCOPE_SYSTEM", + scope); + result = 1; + } + + int inheritsched; + err = pthread_attr_getinheritsched (&a, &inheritsched); + if (err) + { + error (0, err, "pthread_attr_getinheritsched failed"); + result = 1; + } + else if (inheritsched != PTHREAD_INHERIT_SCHED) + { + error (0, 0, "pthread_attr_getinheritsched returned %d != PTHREAD_INHERIT_SCHED", + inheritsched); + result = 1; + } + + err = pthread_getaffinity_np (pthread_self (), sizeof (c1), &c1); + if (err == 0) + { + err = pthread_attr_getaffinity_np (&a, sizeof (c2), &c2); + if (err) + { + error (0, err, "pthread_attr_getaffinity_np failed"); + result = 1; + } + else if (memcmp (&c1, &c2, sizeof (c1))) + { + error (0, 0, "pthread_attr_getaffinity_np returned different CPU mask than pthread_getattr_np"); + result = 1; + } + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + pthread_t th; + err = pthread_create (&th, NULL, tf, NULL); + if (err) + { + error (0, err, "pthread_create #1 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #1 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_init (&a); + if (err) + { + error (0, err, "pthread_attr_init failed"); + result = 1; + } + + err = pthread_create (&th, &a, tf, &a); + if (err) + { + error (0, err, "pthread_create #2 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #2 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_setguardsize (&a, 16 * sysconf (_SC_PAGESIZE)); + if (err) + { + error (0, err, "pthread_attr_setguardsize failed"); + result = 1; + } + + err = pthread_create (&th, &a, tf, &a); + if (err) + { + error (0, err, "pthread_create #3 failed"); + result = 1; + } + else + { + void *ret; + err = pthread_join (th, &ret); + if (err) + { + error (0, err, "pthread_join #3 failed"); + result = 1; + } + else if (ret != NULL) + result = 1; + } + + err = pthread_attr_destroy (&a); + if (err) + { + error (0, err, "pthread_attr_destroy failed"); + result = 1; + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier1.c b/test/nptl/tst-barrier1.c new file mode 100644 index 000000000..2859fb4ca --- /dev/null +++ b/test/nptl/tst-barrier1.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_barrier_t b; + int e; + int cnt; + + e = pthread_barrier_init (&b, NULL, 0); + if (e == 0) + { + puts ("barrier_init with count 0 succeeded"); + return 1; + } + if (e != EINVAL) + { + puts ("barrier_init with count 0 didn't return EINVAL"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 1) != 0) + { + puts ("real barrier_init failed"); + return 1; + } + + for (cnt = 0; cnt < 10; ++cnt) + { + e = pthread_barrier_wait (&b); + + if (e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait didn't return PTHREAD_BARRIER_SERIAL_THREAD"); + return 1; + } + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier2.c b/test/nptl/tst-barrier2.c new file mode 100644 index 000000000..7f588694d --- /dev/null +++ b/test/nptl/tst-barrier2.c @@ -0,0 +1,185 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-barrier2.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_barrier_t *b; + pthread_barrierattr_t a; + pid_t pid; + int serials = 0; + int cnt; + int status; + int p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_getpshared (&a, &p) != 0) + { + puts ("1st barrierattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + return 1; + } + + if (pthread_barrierattr_getpshared (&a, &p) != 0) + { + puts ("2nd barrierattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_barrier_init (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + /* Just to be sure we don't hang forever. */ + alarm (4); + +#define N 30 + for (cnt = 0; cnt < N; ++cnt) + { + int e; + + e = pthread_barrier_wait (b); + if (e == PTHREAD_BARRIER_SERIAL_THREAD) + ++serials; + else if (e != 0) + { + printf ("%s: barrier_wait returned value %d != 0 and PTHREAD_BARRIER_SERIAL_THREAD\n", + pid == 0 ? "child" : "parent", e); + return 1; + } + } + + alarm (0); + + printf ("%s: was %d times the serial thread\n", + pid == 0 ? "child" : "parent", serials); + + if (pid == 0) + /* The child. Pass the number of times we had the serializing + thread back to the parent. */ + exit (serials); + + if (waitpid (pid, &status, 0) != pid) + { + puts ("waitpid failed"); + return 1; + } + + if (!WIFEXITED (status)) + { + puts ("child exited abnormally"); + return 1; + } + + if (WEXITSTATUS (status) + serials != N) + { + printf ("total number of serials is %d, expected %d\n", + WEXITSTATUS (status) + serials, N); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier3.c b/test/nptl/tst-barrier3.c new file mode 100644 index 000000000..b5478f827 --- /dev/null +++ b/test/nptl/tst-barrier3.c @@ -0,0 +1,154 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +/* Test of POSIX barriers. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define NTHREADS 20 + +#define ROUNDS 20 + +static pthread_barrier_t barriers[NTHREADS]; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static int counters[NTHREADS]; +static int serial[NTHREADS]; + +static void * +worker (void *arg) +{ + void *result = NULL; + int nr = (long int) arg; + int i; + + for (i = 0; i < ROUNDS; ++i) + { + int j; + int retval; + + if (nr == 0) + { + memset (counters, '\0', sizeof (counters)); + memset (serial, '\0', sizeof (serial)); + } + + retval = pthread_barrier_wait (&barriers[NTHREADS - 1]); + if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d failed to wait for all the others\n", nr); + result = (void *) 1; + } + + for (j = nr; j < NTHREADS; ++j) + { + /* Increment the counter for this round. */ + pthread_mutex_lock (&lock); + ++counters[j]; + pthread_mutex_unlock (&lock); + + /* Wait for the rest. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Test the result. */ + if (nr == 0 && counters[j] != j + 1) + { + printf ("barrier in round %d released but count is %d\n", + j, counters[j]); + result = (void *) 1; + } + + if (retval != 0) + { + if (retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n", + nr, j); + result = (void *) 1; + } + else + { + pthread_mutex_lock (&lock); + ++serial[j]; + pthread_mutex_unlock (&lock); + } + } + + /* Wait for the rest again. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Now we can check whether exactly one thread was serializing. */ + if (nr == 0 && serial[j] != 1) + { + printf ("not exactly one serial thread in round %d\n", j); + result = (void *) 1; + } + } + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 60 +static int +do_test (void) +{ + pthread_t threads[NTHREADS]; + int i; + void *res; + int result = 0; + + /* Initialized the barrier variables. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0) + { + printf ("Failed to initialize barrier %d\n", i); + exit (1); + } + + /* Start the threads. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0) + { + printf ("Failed to start thread %d\n", i); + exit (1); + } + + /* And wait for them. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_join (threads[i], &res) != 0 || res != NULL) + { + printf ("thread %d returned a failure\n", i); + result = 1; + } + else + printf ("joined threads %d\n", i); + + if (result == 0) + puts ("all OK"); + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-barrier4.c b/test/nptl/tst-barrier4.c new file mode 100644 index 000000000..efc27551c --- /dev/null +++ b/test/nptl/tst-barrier4.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +/* This is a test for behavior not guaranteed by POSIX. */ +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t b1; +static pthread_barrier_t b2; + + +#define N 20 + +static void * +tf (void *arg) +{ + int round = 0; + + while (round++ < 30) + { + if (pthread_barrier_wait (&b1) == PTHREAD_BARRIER_SERIAL_THREAD) + { + pthread_barrier_destroy (&b1); + if (pthread_barrier_init (&b1, NULL, N) != 0) + { + puts ("tf: 1st barrier_init failed"); + exit (1); + } + } + + if (pthread_barrier_wait (&b2) == PTHREAD_BARRIER_SERIAL_THREAD) + { + pthread_barrier_destroy (&b2); + if (pthread_barrier_init (&b2, NULL, N) != 0) + { + puts ("tf: 2nd barrier_init failed"); + exit (1); + } + } + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + int cnt; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + if (pthread_barrier_init (&b1, NULL, N) != 0) + { + puts ("1st barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (&b2, NULL, N) != 0) + { + puts ("2nd barrier_init failed"); + return 1; + } + + pthread_t th[N - 1]; + for (cnt = 0; cnt < N - 1; ++cnt) + if (pthread_create (&th[cnt], &at, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + tf (NULL); + + for (cnt = 0; cnt < N - 1; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic1.c b/test/nptl/tst-basic1.c new file mode 100644 index 000000000..7637c8e49 --- /dev/null +++ b/test/nptl/tst-basic1.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> + + +static pid_t pid; + +static void * +tf (void *a) +{ + if (getpid () != pid) + { + write (2, "pid mismatch\n", 13); + _exit (1); + } + + return a; +} + + +int +do_test (void) +{ + pid = getpid (); + +#define N 2 + pthread_t t[N]; + int i; + + for (i = 0; i < N; ++i) + if (pthread_create (&t[i], NULL, tf, (void *) (long int) (i + 1)) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + else + printf ("created thread %d\n", i); + + for (i = 0; i < N; ++i) + { + void *r; + int e; + if ((e = pthread_join (t[i], &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + else if (r != (void *) (long int) (i + 1)) + { + write (2, "result wrong\n", 13); + _exit (1); + } + else + printf ("joined thread %d\n", i); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic2.c b/test/nptl/tst-basic2.c new file mode 100644 index 000000000..1c4632ceb --- /dev/null +++ b/test/nptl/tst-basic2.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> + + +#define N 20 + +static pthread_t th[N]; +static pthread_mutex_t lock[N]; + + +static void *tf (void *a) +{ + uintptr_t idx = (uintptr_t) a; + + pthread_mutex_lock (&lock[idx]); + + return pthread_equal (pthread_self (), th[idx]) ? NULL : (void *) 1l; +} + + +int +do_test (void) +{ + if (pthread_equal (pthread_self (), pthread_self ()) == 0) + { + puts ("pthread_equal (pthread_self (), pthread_self ()) failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + for (i = 0; i < N; ++i) + { + if (pthread_mutex_init (&lock[i], NULL) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + if (pthread_mutex_lock (&lock[i]) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if (pthread_create (&th[i], &at, tf, (void *) (long int) i) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_mutex_unlock (&lock[i]) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + printf ("created thread %d\n", i); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + int result = 0; + for (i = 0; i < N; ++i) + { + void *r; + int e; + if ((e = pthread_join (th[i], &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + else if (r != NULL) + result = 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic3.c b/test/nptl/tst-basic3.c new file mode 100644 index 000000000..cb4816d2a --- /dev/null +++ b/test/nptl/tst-basic3.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int nrunning = 1; + + +static void +final_test (void) +{ + puts ("final_test has been called"); + +#define THE_SIGNAL SIGUSR1 + kill (getpid (), SIGUSR1); +} + + +static void * +tf (void *a) +{ + if (pthread_join ((pthread_t) a, NULL) != 0) + { + printf ("join failed while %d are running\n", nrunning); + _exit (1); + } + + printf ("%2d left\n", --nrunning); + + return NULL; +} + + +int +do_test (void) +{ +#define N 20 + pthread_t t[N]; + pthread_t last = pthread_self (); + int i; + + atexit (final_test); + + printf ("starting %d + 1 threads\n", N); + for (i = 0; i < N; ++i) + { + if (pthread_create (&t[i], NULL, tf, (void *) last) != 0) + { + puts ("create failed"); + _exit (1); + } + + ++nrunning; + + last = t[i]; + } + + printf ("%2d left\n", --nrunning); + + pthread_exit (NULL); +} + + +#define EXPECTED_SIGNAL THE_SIGNAL +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic4.c b/test/nptl/tst-basic4.c new file mode 100644 index 000000000..6eb6ea9f1 --- /dev/null +++ b/test/nptl/tst-basic4.c @@ -0,0 +1,101 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static void +final_test (void) +{ + puts ("final_test has been called"); + +#define THE_SIGNAL SIGUSR1 + kill (getpid (), SIGUSR1); +} + + +static void * +tf (void *a) +{ + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + atexit (final_test); + + pthread_exit (NULL); + } + + int r; + int e = TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)); + if (e != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (! WIFSIGNALED (r)) + { + puts ("child not signled"); + exit (1); + } + + if (WTERMSIG (r) != THE_SIGNAL) + { + puts ("child's termination signal wrong"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + _exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic5.c b/test/nptl/tst-basic5.c new file mode 100644 index 000000000..83a8810f1 --- /dev/null +++ b/test/nptl/tst-basic5.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + + +int +do_test (void) +{ + int c = pthread_getconcurrency (); + if (c != 0) + { + puts ("initial concurrencylevel wrong"); + exit (1); + } + + if (pthread_setconcurrency (1) != 0) + { + puts ("setconcurrency failed"); + exit (1); + } + + c = pthread_getconcurrency (); + if (c != 1) + { + puts ("getconcurrency didn't return the value previous set"); + exit (1); + } + + int e = pthread_setconcurrency (-1); + if (e == 0) + { + puts ("setconcurrency of negative value didn't failed"); + exit (1); + } + if (e != EINVAL) + { + puts ("setconcurrency didn't return EINVAL for negative value"); + exit (1); + } + + c = pthread_getconcurrency (); + if (c != 1) + { + puts ("invalid getconcurrency changed level"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-basic6.c b/test/nptl/tst-basic6.c new file mode 100644 index 000000000..413ae034b --- /dev/null +++ b/test/nptl/tst-basic6.c @@ -0,0 +1,132 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static char *p; + +static pthread_barrier_t b; +#define BT \ + e = pthread_barrier_wait (&b); \ + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) \ + { \ + puts ("barrier_wait failed"); \ + exit (1); \ + } + + +static void * +tf (void *a) +{ + int e; + + BT; + + char *p2 = getcwd (NULL, 0); + if (p2 == NULL) + { + puts ("2nd getcwd failed"); + exit (1); + } + + if (strcmp (p, p2) != 0) + { + printf ("initial cwd mismatch: \"%s\" vs \"%s\"\n", p, p2); + exit (1); + } + + free (p); + free (p2); + + if (chdir ("..") != 0) + { + puts ("chdir failed"); + exit (1); + } + + p = getcwd (NULL, 0); + if (p == NULL) + { + puts ("getcwd failed"); + exit (1); + } + + return a; +} + + +int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + p = getcwd (NULL, 0); + if (p == NULL) + { + puts ("getcwd failed"); + exit (1); + } + + int e; + BT; + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + char *p2 = getcwd (NULL, 0); + if (p2 == NULL) + { + puts ("2nd getcwd failed"); + exit (1); + } + + if (strcmp (p, p2) != 0) + { + printf ("cwd after chdir mismatch: \"%s\" vs \"%s\"\n", p, p2); + exit (1); + } + + free (p); + free (p2); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel1.c b/test/nptl/tst-cancel1.c new file mode 100644 index 000000000..690319d8c --- /dev/null +++ b/test/nptl/tst-cancel1.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + +static int cntr; + + +static void +cleanup (void *arg) +{ + if (arg != (void *) 42l) + cntr = 42; + else + cntr = 1; +} + + +static void * +tf (void *arg) +{ + /* Ignore all signals. This must not have any effect on delivering + the cancellation signal. */ + sigset_t ss; + + sigfillset (&ss); + + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + pthread_cleanup_push (cleanup, (void *) 42l); + + int err = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + if (err != 0) + { + printf ("setcanceltype failed: %s\n", strerror (err)); + exit (1); + } + /* The following code is not standard compliant: the mutex functions + must not be called with asynchronous cancellation enabled. */ + + err = pthread_mutex_unlock (&m2); + if (err != 0) + { + printf ("child: mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("child: 1st mutex_lock failed: %s\n", strerror (err)); + exit (1); + } + + /* We should never come here. */ + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + pthread_t th; + int result = 0; + void *retval; + + /* Get the mutexes. */ + err = pthread_mutex_lock (&m1); + if (err != 0) + { + printf ("parent: 1st mutex_lock failed: %s\n", strerror (err)); + return 1; + } + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 2nd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("create failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_mutex_lock (&m2); + if (err != 0) + { + printf ("parent: 3rd mutex_lock failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_cancel (th); + if (err != 0) + { + printf ("cancel failed: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, &retval); + if (err != 0) + { + printf ("join failed: %s\n", strerror (err)); + return 1; + } + + if (retval != PTHREAD_CANCELED) + { + printf ("wrong return value: %p\n", retval); + result = 1; + } + + if (cntr == 42) + { + puts ("cleanup handler called with wrong argument"); + result = 1; + } + else if (cntr != 1) + { + puts ("cleanup handling not called"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel10.c b/test/nptl/tst-cancel10.c new file mode 100644 index 000000000..7af0f2f84 --- /dev/null +++ b/test/nptl/tst-cancel10.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +static void +cleanup (void *arg) +{ + /* Just for fun. */ + if (pthread_cancel (pthread_self ()) != 0) + { + puts ("cleanup: cancel failed"); + exit (1); + } + + printf ("cleanup for %ld\n", (long int) arg); +} + + +static void * +tf (void *arg) +{ + long int n = (long int) arg; + + pthread_cleanup_push (cleanup, arg); + + if (pthread_setcanceltype ((n & 1) == 0 + ? PTHREAD_CANCEL_DEFERRED + : PTHREAD_CANCEL_ASYNCHRONOUS, NULL) != 0) + { + puts ("setcanceltype failed"); + exit (1); + } + + if (pthread_cancel (pthread_self ()) != 0) + { + puts ("cancel failed"); + exit (1); + } + + pthread_testcancel (); + + /* We should never come here. */ + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + +#define N 20 + int i; + pthread_t th[N]; + + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &at, tf, (void *) (long int) i) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + void *r; + if (pthread_join (th[i], &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel11.c b/test/nptl/tst-cancel11.c new file mode 100644 index 000000000..235aef5c4 --- /dev/null +++ b/test/nptl/tst-cancel11.c @@ -0,0 +1,123 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t bar; +static int fd[2]; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + /* This call should block and be cancelable. */ + char buf[20]; + read (fd[0], buf, sizeof (buf)); + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel12.c b/test/nptl/tst-cancel12.c new file mode 100644 index 000000000..6fdf5cf5f --- /dev/null +++ b/test/nptl/tst-cancel12.c @@ -0,0 +1,127 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + /* This call should block and be cancelable. */ + sem_wait (&sem); + + pthread_cleanup_pop (0); + + puts ("sem_wait returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 1) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + /* Check whether cancellation is honored even before sem_wait does + anything. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel13.c b/test/nptl/tst-cancel13.c new file mode 100644 index 000000000..66ab45509 --- /dev/null +++ b/test/nptl/tst-cancel13.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + /* This call should block and be cancelable. */ + sem_wait (&sem); + + pthread_cleanup_pop (0); + + puts ("sem_wait returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + /* Give the child a chance to go to sleep in sem_wait. */ + sleep (1); + + /* Check whether cancellation is honored when waiting in sem_wait. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel14.c b/test/nptl/tst-cancel14.c new file mode 100644 index 000000000..592c0864f --- /dev/null +++ b/test/nptl/tst-cancel14.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* Timeout in 5 seconds. */ + ts.tv_sec += 5; + + /* This call should block and be cancelable. */ + sem_timedwait (&sem, &ts); + + pthread_cleanup_pop (0); + + puts ("sem_timedwait returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 1) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + /* Check whether cancellation is honored even before sem_timedwait does + anything. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel15.c b/test/nptl/tst-cancel15.c new file mode 100644 index 000000000..5fd95022b --- /dev/null +++ b/test/nptl/tst-cancel15.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_barrier_t bar; +static sem_t sem; + + +static void +cleanup (void *arg) +{ + static int ncall; + + if (++ncall != 1) + { + puts ("second call to cleanup"); + exit (1); + } + + printf ("cleanup call #%d\n", ncall); +} + + +static void * +tf (void *arg) +{ + int e; + + pthread_cleanup_push (cleanup, NULL); + + e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: 1st barrier_wait failed"); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* Timeout in 5 seconds. */ + ts.tv_sec += 5; + + /* This call should block and be cancelable. */ + errno = 0; + e = sem_timedwait (&sem, &ts); + + pthread_cleanup_pop (0); + + printf ("sem_timedwait returned, e = %d, errno = %d\n", e, errno); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&sem, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + /* Give the child a chance to go to sleep in sem_wait. */ + sleep (1); + + /* Check whether cancellation is honored when waiting in sem_timedwait. */ + if (pthread_cancel (th) != 0) + { + puts ("1st cancel failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel16.c b/test/nptl/tst-cancel16.c new file mode 100644 index 000000000..709902e97 --- /dev/null +++ b/test/nptl/tst-cancel16.c @@ -0,0 +1,231 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static pthread_barrier_t b2; +static int fd; +static int called; + + +static void +cl (void *arg) +{ + called = 1; +} + + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + /* This call should never return. */ + (void) lockf (fd, F_LOCK, 0); + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + char fname[] = "/tmp/cancel16XXXXXX"; + fd = mkstemp (fname); + if (fd == -1) + { + puts ("mkstemp failed"); + return 1; + } + unlink (fname); + + char mem[sizeof (pthread_barrier_t)]; + memset (mem, '\0', sizeof (mem)); + if (TEMP_FAILURE_RETRY (pwrite (fd, mem, sizeof (mem), 0)) != sizeof (mem)) + { + puts ("pwrite failed"); + return 1; + } + + void *p = mmap (NULL, sizeof (mem), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + { + puts ("mmap failed"); + return 1; + } + pthread_barrier_t *b = (pthread_barrier_t *) p; + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + if (pthread_barrierattr_setpshared (&ba, 1) != 0) + { + puts ("barrierattr_setshared failed"); + return 1; + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("1st barrier_init failed"); + return 1; + } + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + pid_t pid = fork (); + if (pid == 0) + { + /* Child. Lock the file and wait. */ + if (lockf (fd, F_LOCK, 0) != 0) + { + puts ("child process: lockf failed"); + _exit (1); + } + + int r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child process: 1st barrier_wait failed"); + _exit (1); + } + + /* Make sure the process dies. */ + alarm (5); + + r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child process: 2nd barrier_wait failed"); + _exit (1); + } + + _exit (0); + } + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + int r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("main: 1st barrier_wait failed"); + _exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("2nd barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("main: 2nd barrier_wait failed"); + return 1; + } + + /* Delay. */ + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("join failed"); + return 1; + } + if (result != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + if (called == 0) + { + puts ("cleanup handler not called"); + return 1; + } + + r = pthread_barrier_wait (b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("main: 3rd barrier_wait failed"); + return 1; + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + if (WEXITSTATUS (status) != 0) + { + printf ("child process exits with %d\n", WEXITSTATUS (status)); + return 1; + } + + if (lockf (fd, F_LOCK, 0) != 0) + { + puts ("main: lockf failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel19.c b/test/nptl/tst-cancel19.c new file mode 100644 index 000000000..7c248ae0f --- /dev/null +++ b/test/nptl/tst-cancel19.c @@ -0,0 +1,287 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <error.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/time.h> +#include <unistd.h> + +static void * +tf (void *arg) +{ + return NULL; +} + +static void +handler (int sig) +{ +} + +static void __attribute__ ((noinline)) +clobber_lots_of_regs (void) +{ +#define X1(n) long r##n = 10##n; __asm __volatile ("" : "+r" (r##n)); +#define X2(n) X1(n##0) X1(n##1) X1(n##2) X1(n##3) X1(n##4) +#define X3(n) X2(n##0) X2(n##1) X2(n##2) X2(n##3) X2(n##4) + X3(0) X3(1) X3(2) X3(3) X3(4) +#undef X1 +#define X1(n) __asm __volatile ("" : : "r" (r##n)); + X3(0) X3(1) X3(2) X3(3) X3(4) +#undef X1 +#undef X2 +#undef X3 +} + +static int +do_test (void) +{ + pthread_t th; + int old, rc; + int ret = 0; + int fd[2]; + + rc = pipe (fd); + if (rc < 0) + error (EXIT_FAILURE, errno, "couldn't create pipe"); + + rc = pthread_create (&th, NULL, tf, NULL); + if (rc) + error (EXIT_FAILURE, rc, "couldn't create thread"); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "1st pthread_setcanceltype failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED && old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "1st pthread_setcanceltype returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + close (fd[0]); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after close failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after close returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + close (fd[1]); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd close failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd close returned invalid value %d", + old); + ret = 1; + } + + struct sigaction sa = { .sa_handler = handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it; + it.it_value.tv_sec = 1; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + setitimer (ITIMER_REAL, &it, NULL); + + clobber_lots_of_regs (); + pause (); + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after pause failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after pause returned invalid value %d", + old); + ret = 1; + } + + it.it_value.tv_sec = 1; + it.it_value.tv_usec = 0; + it.it_interval = it.it_value; + setitimer (ITIMER_REAL, &it, NULL); + + clobber_lots_of_regs (); + pause (); + + memset (&it, 0, sizeof (it)); + setitimer (ITIMER_REAL, &it, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd pause failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd pause returned invalid value %d", + old); + ret = 1; + } + + char fname[] = "/tmp/tst-cancel19-dir-XXXXXX\0foo/bar"; + char *enddir = strchr (fname, '\0'); + if (mkdtemp (fname) == NULL) + { + error (0, errno, "mkdtemp failed"); + ret = 1; + } + *enddir = '/'; + + clobber_lots_of_regs (); + creat (fname, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after creat failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after creat returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + creat (fname, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd creat failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd creat returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + open (fname, O_CREAT, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after open failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after open returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + open (fname, O_CREAT, 0400); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd open failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd open returned invalid value %d", + old); + ret = 1; + } + + *enddir = '\0'; + rmdir (fname); + + clobber_lots_of_regs (); + select (-1, NULL, NULL, NULL, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after select failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_DEFERRED) + { + error (0, 0, "pthread_setcanceltype after select returned invalid value %d", + old); + ret = 1; + } + + clobber_lots_of_regs (); + select (-1, NULL, NULL, NULL, NULL); + + rc = pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &old); + if (rc) + { + error (0, rc, "pthread_setcanceltype after 2nd select failed"); + ret = 1; + } + if (old != PTHREAD_CANCEL_ASYNCHRONOUS) + { + error (0, 0, "pthread_setcanceltype after 2nd select returned invalid value %d", + old); + ret = 1; + } + + pthread_join (th, NULL); + + return ret; +} + +#define TIMEOUT 20 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel2.c b/test/nptl/tst-cancel2.c new file mode 100644 index 000000000..6d80f8ae5 --- /dev/null +++ b/test/nptl/tst-cancel2.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + /* The buffer size must be larger than the pipe size so that the + write blocks. */ + char buf[100000]; + + if (write (fd[1], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("write succeeded"); + return (void *) 1l; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the write in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + printf ("result is wrong: expected %p, got %p\n", PTHREAD_CANCELED, r); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel20.c b/test/nptl/tst-cancel20.c new file mode 100644 index 000000000..d88cb9caf --- /dev/null +++ b/test/nptl/tst-cancel20.c @@ -0,0 +1,264 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int fd[4]; +static pthread_barrier_t b; +volatile int in_sh_body; +unsigned long cleanups; + +static void +cl (void *arg) +{ + cleanups = (cleanups << 4) | (long) arg; +} + + +static void __attribute__((noinline)) +sh_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 1L); + + in_sh_body = 1; + if (read (fd[2], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + pthread_cleanup_pop (0); +} + + +static void +sh (int sig) +{ + pthread_cleanup_push (cl, (void *) 2L); + sh_body (); + in_sh_body = 0; + + pthread_cleanup_pop (0); +} + + +static void __attribute__((noinline)) +tf_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 3L); + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + if (read (fd[0], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + read (fd[0], &c, 1); + + pthread_cleanup_pop (0); +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cl, (void *) 4L); + tf_body (); + pthread_cleanup_pop (0); + return NULL; +} + + +static int +do_one_test (void) +{ + in_sh_body = 0; + cleanups = 0; + if (pipe (fd) != 0 || pipe (fd + 2) != 0) + { + puts ("pipe failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent thread: barrier_wait failed"); + return 1; + } + + sleep (1); + + r = pthread_kill (th, SIGHUP); + if (r) + { + errno = r; + printf ("pthread_kill failed %m\n"); + return 1; + } + + while (in_sh_body == 0) + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + close (fd[1]); + close (fd[2]); + close (fd[3]); + + void *ret; + if (pthread_join (th, &ret) != 0) + { + puts ("join failed"); + return 1; + } + + if (ret != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + if (cleanups != 0x1234L) + { + printf ("called cleanups %lx\n", cleanups); + return 1; + } + + return 0; +} + + +static int +do_test (void) +{ + stack_t ss; + ss.ss_sp = malloc (2 * SIGSTKSZ); + if (ss.ss_sp == NULL) + { + puts ("failed to allocate alternate stack"); + return 1; + } + ss.ss_flags = 0; + ss.ss_size = 2 * SIGSTKSZ; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("sigaltstack failed %m\n"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = 0 test"); + if (do_one_test ()) + return 1; + + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + return 0; +} + +#define TIMEOUT 40 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel21.c b/test/nptl/tst-cancel21.c new file mode 100644 index 000000000..cc00cc168 --- /dev/null +++ b/test/nptl/tst-cancel21.c @@ -0,0 +1,294 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + + +static int fd[4]; +static pthread_barrier_t b; +volatile int in_sh_body; +unsigned long cleanups; + +static void +cl (void *arg) +{ + cleanups = (cleanups << 4) | (long) arg; +} + + +static void __attribute__((noinline)) +sh_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 1L); + + in_sh_body = 1; + if (read (fd[2], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + pthread_cleanup_pop (0); +} + + +static void +sh (int sig) +{ + pthread_cleanup_push (cl, (void *) 2L); + sh_body (); + in_sh_body = 0; + + pthread_cleanup_pop (0); +} + + +static void __attribute__((noinline)) +tf_body (void) +{ + char c; + + pthread_cleanup_push (cl, (void *) 3L); + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child thread: barrier_wait failed"); + exit (1); + } + + if (read (fd[0], &c, 1) == 1) + { + puts ("read succeeded"); + exit (1); + } + + read (fd[0], &c, 1); + + pthread_cleanup_pop (0); +} + + +static void * +tf (void *arg) +{ + pthread_t th = (pthread_t) arg; + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent thread: barrier_wait failed"); + exit (1); + } + + sleep (1); + + r = pthread_kill (th, SIGHUP); + if (r) + { + errno = r; + printf ("pthread_kill failed %m\n"); + exit (1); + } + + while (in_sh_body == 0) + sleep (1); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + exit (1); + } + + /* This will cause the read in the initial thread to return. */ + close (fd[0]); + close (fd[1]); + close (fd[2]); + close (fd[3]); + + void *ret; + if (pthread_join (th, &ret) != 0) + { + puts ("join failed"); + exit (1); + } + + if (ret != PTHREAD_CANCELED) + { + puts ("result is wrong"); + exit (1); + } + + if (cleanups != 0x1234L) + { + printf ("called cleanups %lx\n", cleanups); + exit (1); + } + + if (pthread_barrier_destroy (&b)) + { + puts ("barrier destroy failed"); + exit (1); + } + + exit (0); +} + + +static int +do_one_test (void) +{ + in_sh_body = 0; + + pid_t pid = fork (); + + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid) + { + int status; + if (waitpid (pid, &status, 0) < 0) + { + printf ("waitpid failed %m\n"); + return 1; + } + + return !WIFEXITED (status) || WEXITSTATUS (status); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + cleanups = 0; + if (pipe (fd) != 0 || pipe (fd + 2) != 0) + { + puts ("pipe failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + pthread_cleanup_push (cl, (void *) 4L); + tf_body (); + pthread_cleanup_pop (0); + exit (1); +} + + +static int +do_test (void) +{ + stack_t ss; + ss.ss_sp = malloc (2 * SIGSTKSZ); + if (ss.ss_sp == NULL) + { + puts ("failed to allocate alternate stack"); + return 1; + } + ss.ss_flags = 0; + ss.ss_size = 2 * SIGSTKSZ; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("sigaltstack failed %m\n"); + return 1; + } + + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = 0 test"); + if (do_one_test ()) + return 1; + + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO test"); + if (do_one_test ()) + return 1; + + sa.sa_sigaction = (void (*)(int, siginfo_t *, void *)) sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_ONSTACK; + + if (sigaction (SIGHUP, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + puts ("sa_flags = SA_SIGINFO|SA_ONSTACK test"); + if (do_one_test ()) + return 1; + + return 0; +} + +#define TIMEOUT 40 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel22.c b/test/nptl/tst-cancel22.c new file mode 100644 index 000000000..c47167b90 --- /dev/null +++ b/test/nptl/tst-cancel22.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +pthread_barrier_t b; +int seen; + +static void * +tf (void *arg) +{ + int i; + int old; + int r = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old); + if (r != 0) + { + puts ("setcancelstate failed"); + exit (1); + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + for (i = 0; i < 10; ++i) + { + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + } + + seen = 1; + pthread_setcancelstate (old, NULL); + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + 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 ("thread creation failed"); + return 1; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("join failed"); + return 1; + } + if (status != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + if (seen != 1) + { + puts ("thread cancelled when PTHREAD_CANCEL_DISABLED"); + return 1; + } + + return 0; +} + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel3.c b/test/nptl/tst-cancel3.c new file mode 100644 index 000000000..86c482bcc --- /dev/null +++ b/test/nptl/tst-cancel3.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int fd[2]; + + +static void * +tf (void *arg) +{ + char buf[100]; + + if (read (fd[0], buf, sizeof (buf)) == sizeof (buf)) + { + puts ("read succeeded"); + return (void *) 1l; + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + void *r; + struct sigaction sa; + + sa.sa_handler = SIG_IGN; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + + if (sigaction (SIGPIPE, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + /* This will cause the read in the child to return. */ + close (fd[0]); + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + + if (r != PTHREAD_CANCELED) + { + puts ("result is wrong"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel6.c b/test/nptl/tst-cancel6.c new file mode 100644 index 000000000..94de85830 --- /dev/null +++ b/test/nptl/tst-cancel6.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + char buf[100]; + fgets (buf, sizeof (buf), arg); + /* This call should never return. */ + return NULL; +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + return 1; + } + + FILE *fp = fdopen (fd[0], "r"); + if (fp == NULL) + { + puts ("fdopen failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, fp) != 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; + } + + return r != PTHREAD_CANCELED; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel7.c b/test/nptl/tst-cancel7.c new file mode 100644 index 000000000..16cc47cff --- /dev/null +++ b/test/nptl/tst-cancel7.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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. */ + +#include <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +const char *command; +const char *pidfile; +char pidfilename[] = "/tmp/tst-cancel7-XXXXXX"; + +static void * +tf (void *arg) +{ + const char *args = " --direct --pidfile "; + char *cmd = alloca (strlen (command) + strlen (args) + + strlen (pidfilename) + 1); + + strcpy (stpcpy (stpcpy (cmd, command), args), pidfilename); + system (cmd); + /* This call should never return. */ + return NULL; +} + + +static void +sl (void) +{ + FILE *f = fopen (pidfile, "w"); + if (f == NULL) + exit (1); + + fprintf (f, "%lld\n", (long long) getpid ()); + fflush (f); + + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 1 + }; + if (fcntl (fileno (f), F_SETLK, &fl) != 0) + exit (1); + + sigset_t ss; + sigfillset (&ss); + sigsuspend (&ss); + exit (0); +} + + +static void +do_prepare (int argc, char *argv[]) +{ + if (command == NULL) + command = argv[0]; + + if (pidfile) + sl (); + + int fd = mkstemp (pidfilename); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + write (fd, " ", 1); + close (fd); +} + + +static int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + do + sleep (1); + while (access (pidfilename, R_OK) != 0); + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + sleep (1); + + FILE *f = fopen (pidfilename, "r+"); + if (f == NULL) + { + puts ("no pidfile"); + return 1; + } + + long long ll; + if (fscanf (f, "%lld\n", &ll) != 1) + { + puts ("could not read pid"); + unlink (pidfilename); + return 1; + } + + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 1 + }; + if (fcntl (fileno (f), F_GETLK, &fl) != 0) + { + puts ("F_GETLK failed"); + unlink (pidfilename); + return 1; + } + + if (fl.l_type != F_UNLCK) + { + printf ("child %lld still running\n", (long long) fl.l_pid); + if (fl.l_pid == ll) + kill (fl.l_pid, SIGKILL); + + unlink (pidfilename); + return 1; + } + + fclose (f); + + unlink (pidfilename); + + return r != PTHREAD_CANCELED; +} + +#if 0 /* unused */ +static void +do_cleanup (void) +{ + FILE *f = fopen (pidfilename, "r+"); + long long ll; + + if (f != NULL && fscanf (f, "%lld\n", &ll) == 1) + { + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 1 + }; + if (fcntl (fileno (f), F_GETLK, &fl) == 0 && fl.l_type != F_UNLCK + && fl.l_pid == ll) + kill (fl.l_pid, SIGKILL); + + fclose (f); + } + + unlink (pidfilename); +} +#endif + +#define OPT_COMMAND 10000 +#define OPT_PIDFILE 10001 +#define CMDLINE_OPTIONS \ + { "command", required_argument, NULL, OPT_COMMAND }, \ + { "pidfile", required_argument, NULL, OPT_PIDFILE }, +#define CMDLINE_PROCESS \ + case OPT_COMMAND: \ + command = optarg; \ + break; \ + case OPT_PIDFILE: \ + pidfile = optarg; \ + break; +// #define CLEANUP_HANDLER do_cleanup () +#define PREPARE(argc, argv) do_prepare (argc, argv) +#define TEST_FUNCTION do_test () +#define TIMEOUT 5 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel8.c b/test/nptl/tst-cancel8.c new file mode 100644 index 000000000..fc836627d --- /dev/null +++ b/test/nptl/tst-cancel8.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_barrier_t bar; + +static int global; + + +static void +cleanup (void *arg) +{ + global = 1; +} + + +static void * +tf (void *arg) +{ + /* Enable cancellation, but defer it. */ + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0) + { + puts ("setcancelstate failed"); + exit (1); + } + if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("setcanceltype failed"); + exit (1); + } + + /* Add cleanup handler. */ + pthread_cleanup_push (cleanup, NULL); + + /* Synchronize with the main thread. */ + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: first barrier_wait failed"); + exit (1); + } + + /* And again. Once this is done the main thread should have canceled + this thread. */ + r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: second barrier_wait failed"); + exit (1); + } + + /* Remove the cleanup handler without executing it. */ + pthread_cleanup_pop (0); + + /* Now react on the cancellation. */ + pthread_testcancel (); + + /* This call should never return. */ + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("first barrier_wait failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("pthread_cancel failed"); + return 1; + } + + r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("second barrier_wait failed"); + exit (1); + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + if (result != PTHREAD_CANCELED) + { + puts ("thread was not canceled"); + exit (1); + } + + if (global != 0) + { + puts ("cancellation handler has been called"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cancel9.c b/test/nptl/tst-cancel9.c new file mode 100644 index 000000000..037ef30fd --- /dev/null +++ b/test/nptl/tst-cancel9.c @@ -0,0 +1,126 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <fcntl.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t b; + + +static void +cleanup (void *arg) +{ + fputs ("in cleanup\n", stdout); +} + + +static void * +tf (void *arg) +{ + int fd = open ("/dev/null", O_RDWR); + if (fd == -1) + { + puts ("cannot open /dev/null"); + exit (1); + } + FILE *fp = fdopen (fd, "w"); + if (fp == NULL) + { + puts ("fdopen failed"); + exit (1); + } + + pthread_cleanup_push (cleanup, NULL); + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + while (1) + /* fprintf() uses write() which is a cancallation point. */ + fprintf (fp, "foo"); + + pthread_cleanup_pop (0); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, 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"); + exit (1); + } + + sleep (1); + + puts ("cancel now"); + + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + exit (1); + } + + puts ("waiting for the child"); + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread wasn't canceled"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup0.c b/test/nptl/tst-cleanup0.c new file mode 100644 index 000000000..6fc2209cc --- /dev/null +++ b/test/nptl/tst-cleanup0.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int global; + + +static void +ch (void *arg) +{ + int val = (long int) arg; + + printf ("ch (%d)\n", val); + + global *= val; + global += val; +} + + +static void +endfct (void) +{ + /* We force exit right here. */ + _exit (global); +} + + +static int +do_test (void) +{ + atexit (endfct); + + pthread_cancel (pthread_self ()); + + pthread_cleanup_push (ch, (void *) 1l); + + pthread_cleanup_push (ch, (void *) 2l); + + pthread_cleanup_push (ch, (void *) 3l); + +// pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + return 100; +} + + +#define EXPECTED_STATUS 9 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup1.c b/test/nptl/tst-cleanup1.c new file mode 100644 index 000000000..2230e0fbe --- /dev/null +++ b/test/nptl/tst-cleanup1.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int global; + + +static void +ch (void *arg) +{ + int val = (long int) arg; + + printf ("ch (%d)\n", val); + + global *= val; + global += val; +} + + +static void * +tf (void *a) +{ + pthread_cancel (pthread_self ()); + + pthread_cleanup_push (ch, (void *) 1l); + + pthread_cleanup_push (ch, (void *) 2l); + + pthread_cleanup_push (ch, (void *) 3l); + + pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + void *r; + int e; + if ((e = pthread_join (th, &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + if (global != 9) + { + printf ("global = %d, expected 9\n", global); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup2.c b/test/nptl/tst-cleanup2.c new file mode 100644 index 000000000..30e10b120 --- /dev/null +++ b/test/nptl/tst-cleanup2.c @@ -0,0 +1,63 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Bao Duong <bduong@progress.com>, 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 <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> + +static sigjmp_buf jmpbuf; + +static void +sig_handler (int signo) +{ + siglongjmp (jmpbuf, 1); +} + +static int +do_test (void) +{ + char *p = NULL; + struct sigaction sa; + + sa.sa_handler = sig_handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_SIGINFO; + + if (sigaction (SIGSEGV, &sa, 0)) + { + perror ("installing SIGSEGV handler\n"); + exit (1); + } + + puts ("Attempting to sprintf to null ptr"); + if (setjmp (jmpbuf)) + { + puts ("Exiting main..."); + return 0; + } + + sprintf (p, "This should segv\n"); + + return 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup3.c b/test/nptl/tst-cleanup3.c new file mode 100644 index 000000000..c44277370 --- /dev/null +++ b/test/nptl/tst-cleanup3.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static int global; + + +static void +ch (void *arg) +{ + int val = (long int) arg; + + printf ("ch (%d)\n", val); + + global *= val; + global += val; +} + + +static void * +tf (void *a) +{ + pthread_cleanup_push (ch, (void *) 1l); + + pthread_cleanup_push (ch, (void *) 2l); + + pthread_cleanup_push (ch, (void *) 3l); + + pthread_exit ((void *) 1l); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + pthread_cleanup_pop (1); + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + void *r; + int e; + if ((e = pthread_join (th, &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + + if (r != (void *) 1l) + { + puts ("thread not canceled"); + exit (1); + } + + if (global != 9) + { + printf ("global = %d, expected 9\n", global); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup4.c b/test/nptl/tst-cleanup4.c new file mode 100644 index 000000000..1489fd31b --- /dev/null +++ b/test/nptl/tst-cleanup4.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* LinuxThreads pthread_cleanup_{push,pop} helpers. */ +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, + int __execute); + +static int fds[2]; +static pthread_barrier_t b2; +static int global; + +/* Defined in tst-cleanup4aux.c, never compiled with -fexceptions. */ +extern void fn5 (void); +extern void fn7 (void); +extern void fn9 (void); + +void +clh (void *arg) +{ + int val = (long int) arg; + + printf ("clh (%d)\n", val); + + global *= val; + global += val; +} + + +static __attribute__((noinline)) void +fn_read (void) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + char c; + read (fds[0], &c, 1); +} + + +__attribute__((noinline)) void +fn0 (void) +{ + pthread_cleanup_push (clh, (void *) 1l); + + fn_read (); + + pthread_cleanup_pop (1); +} + + +__attribute__((noinline)) void +fn1 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 2l); + + fn0 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn2 (void) +{ + pthread_cleanup_push (clh, (void *) 3l); + + fn1 (); + + pthread_cleanup_pop (1); +} + + +static void * +tf (void *a) +{ + switch ((long) a) + { + case 0: + fn2 (); + break; + case 1: + fn5 (); + break; + case 2: + fn7 (); + break; + case 3: + fn9 (); + break; + } + + return NULL; +} + + +int +do_test (void) +{ + int result = 0; + + if (pipe (fds) != 0) + { + puts ("pipe failed"); + exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("b2 init failed"); + exit (1); + } + + const int expect[] = + { + 15, /* 1 2 3 */ + 276, /* 1 4 5 6 */ + 120, /* 1 7 8 */ + 460 /* 1 2 9 10 */ + }; + + long i; + for (i = 0; i < 4; ++i) + { + global = 0; + + printf ("test %ld\n", i); + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) i) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __FUNCTION__); + exit (1); + } + + pthread_cancel (th); + + void *r; + if ((e = pthread_join (th, &r)) != 0) + { + printf ("join failed: %d\n", e); + _exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + exit (1); + } + + if (global != expect[i]) + { + printf ("global = %d, expected %d\n", global, expect[i]); + result = 1; + } + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cleanup4aux.c b/test/nptl/tst-cleanup4aux.c new file mode 100644 index 000000000..cd1a89ac1 --- /dev/null +++ b/test/nptl/tst-cleanup4aux.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +extern void _pthread_cleanup_push (struct _pthread_cleanup_buffer *__buffer, + void (*__routine) (void *), + void *__arg); +extern void _pthread_cleanup_pop (struct _pthread_cleanup_buffer *__buffer, + int __execute); + +extern void clh (void *arg); +extern void fn0 (void); +extern void fn1 (void); +extern void fn5 (void); +extern void fn7 (void); +extern void fn9 (void); + + +static __attribute__((noinline)) void +fn3 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 4l); + + fn0 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn4 (void) +{ + pthread_cleanup_push (clh, (void *) 5l); + + fn3 (); + + pthread_cleanup_pop (1); +} + + +void +fn5 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 6l); + + fn4 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn6 (void) +{ + pthread_cleanup_push (clh, (void *) 7l); + + fn0 (); + + pthread_cleanup_pop (1); +} + + +void +fn7 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 8l); + + fn6 (); + + _pthread_cleanup_pop (&b, 1); +} + + +static __attribute__((noinline)) void +fn8 (void) +{ + pthread_cleanup_push (clh, (void *) 9l); + + fn1 (); + + pthread_cleanup_pop (1); +} + + +void +fn9 (void) +{ + /* This is the old LinuxThreads pthread_cleanup_{push,pop}. */ + struct _pthread_cleanup_buffer b; + _pthread_cleanup_push (&b, clh, (void *) 10l); + + fn8 (); + + _pthread_cleanup_pop (&b, 1); +} diff --git a/test/nptl/tst-clock.c b/test/nptl/tst-clock.c new file mode 100644 index 000000000..f2f18874a --- /dev/null +++ b/test/nptl/tst-clock.c @@ -0,0 +1,124 @@ +/* Test program for POSIX clock_* functions. + Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 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; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <string.h> +#include <time.h> + + +/* We want to see output immediately. */ +#define STDOUT_UNBUFFERED + +/* We expect to run at least 10 seconds. */ +#define TIMEOUT 15 + +static int +clock_test (clockid_t cl) +{ + struct timespec old_ts; + struct timespec ts; + struct timespec waitit; + int result = 0; + int i; + + memset (&ts, '\0', sizeof ts); + + waitit.tv_sec = 0; + waitit.tv_nsec = 500000000; + + /* Get and print resolution of the clock. */ + if (clock_getres (cl, &ts) == 0) + { + if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) + { + printf ("clock %d: nanosecond value of resolution wrong\n", cl); + result = 1; + } + else + printf ("clock %d: resolution = %ld.%09ld secs\n", + cl, ts.tv_sec, ts.tv_nsec); + } + else + { + printf ("clock %d: cannot get resolution\n", cl); + result = 1; + } + + memset (&ts, '\0', sizeof ts); + memset (&old_ts, '\0', sizeof old_ts); + + /* Next get the current time value a few times. */ + for (i = 0; i < 10; ++i) + { + if (clock_gettime (cl, &ts) == 0) + { + if (ts.tv_nsec < 0 || ts.tv_nsec >= 1000000000) + { + printf ("clock %d: nanosecond value of time wrong (try %d)\n", + cl, i); + result = 1; + } + else + { + printf ("clock %d: time = %ld.%09ld secs\n", + cl, ts.tv_sec, ts.tv_nsec); + + if (memcmp (&ts, &old_ts, sizeof ts) == 0) + { + printf ("clock %d: time hasn't changed (try %d)\n", cl, i); + result = 1; + + old_ts = ts; + } + } + } + else + { + printf ("clock %d: cannot get time (try %d)\n", cl, i); + result = 1; + } + + /* Wait a bit before the next iteration. */ + nanosleep (&waitit, NULL); + } + + return result; +} + +static int +do_test (void) +{ + clockid_t cl; + int result; + + result = clock_test (CLOCK_REALTIME); + + if (clock_getcpuclockid (0, &cl) == 0) + /* XXX It's not yet a bug when this fails. */ + clock_test (cl); + else + printf("CPU clock unavailble, skipping test\n"); + + return result; +} +#define TEST_FUNCTION do_test () + + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock1.c b/test/nptl/tst-clock1.c new file mode 100644 index 000000000..0848d7701 --- /dev/null +++ b/test/nptl/tst-clock1.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +int +do_test (void) +{ +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 + clockid_t cl; + /* This is really only a linking-test here. */ + int e = pthread_getcpuclockid (pthread_self (), &cl); + if (e != 0) + { +# if _POSIX_THREAD_CPUTIME == 0 + if (sysconf (_SC_THREAD_CPUTIME) >= 0) +# endif + { + puts ("cpuclock advertized, but cannot get ID"); + exit (1); + } + } +#endif + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock2.c b/test/nptl/tst-clock2.c new file mode 100644 index 000000000..49a769bf4 --- /dev/null +++ b/test/nptl/tst-clock2.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +static pthread_barrier_t b2; +static pthread_barrier_t bN; + + +static void * +tf (void *arg) +{ + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&bN); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + return NULL; +} +#endif + + +int +do_test (void) +{ +#if defined _POSIX_THREAD_CPUTIME && _POSIX_THREAD_CPUTIME >= 0 +# define N 10 + +# if _POSIX_THREAD_CPUTIME == 0 + if (sysconf (_SC_THREAD_CPUTIME) < 0) + { + puts ("_POSIX_THREAD_CPUTIME option not available"); + return 1; + } +# endif + + if (pthread_barrier_init (&b2, NULL, 2) != 0 + || pthread_barrier_init (&bN, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + pthread_t th[N + 1]; + clockid_t cl[N + 1]; +# ifndef CLOCK_THREAD_CPUTIME_ID + if (pthread_getcpuclockid (pthread_self (), &cl[0]) != 0) + { + puts ("own pthread_getcpuclockid failed"); + return 1; + } +# else + cl[0] = CLOCK_THREAD_CPUTIME_ID; +# endif + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + int e; + for (i = 0; i < N; ++i) + { + if (pthread_create (&th[i], &at, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + TEMP_FAILURE_RETRY (nanosleep (&ts, &ts)); + + if (pthread_getcpuclockid (th[i], &cl[i + 1]) != 0) + { + puts ("pthread_getcpuclockid failed"); + return 1; + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + struct timespec t[N + 1]; + for (i = 0; i < N + 1; ++i) + if (clock_gettime (cl[i], &t[i]) != 0) + { + printf ("clock_gettime round %d failed\n", i); + return 1; + } + + for (i = 0; i < N; ++i) + { + struct timespec diff; + + diff.tv_sec = t[i].tv_sec - t[i + 1].tv_sec; + diff.tv_nsec = t[i].tv_nsec - t[i + 1].tv_nsec; + if (diff.tv_nsec < 0) + { + diff.tv_nsec += 1000000000; + --diff.tv_sec; + } + + if (diff.tv_sec < 0 || (diff.tv_sec == 0 && diff.tv_nsec < 100000000)) + { + printf ("\ +difference between thread %d and %d too small (%ld.%09ld)\n", + i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec); + return 1; + } + + printf ("diff %d->%d: %ld.%09ld\n", + i, i + 1, (long int) diff.tv_sec, (long int) diff.tv_nsec); + } + + ts.tv_sec = 0; + ts.tv_nsec = 0; + for (i = 0; i < N + 1; ++i) + if (clock_settime (cl[i], &ts) != 0) + { + printf ("clock_settime(%d) round %d failed\n", cl[i], i); + return 1; + } + + for (i = 0; i < N + 1; ++i) + { + if (clock_gettime (cl[i], &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + if (ts.tv_sec > t[i].tv_sec + || (ts.tv_sec == t[i].tv_sec && ts.tv_nsec > t[i].tv_nsec)) + { + puts ("clock_settime didn't reset clock"); + return 1; + } + } +#endif + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-clock_nanosleep.c b/test/nptl/tst-clock_nanosleep.c new file mode 100644 index 000000000..98a8b5f57 --- /dev/null +++ b/test/nptl/tst-clock_nanosleep.c @@ -0,0 +1,58 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + + +/* Test that clock_nanosleep() does sleep. */ +static int +do_test (void) +{ + /* Current time. */ + struct timeval tv1; + (void) gettimeofday (&tv1, NULL); + + struct timespec ts; + ts.tv_sec = 1; + ts.tv_nsec = 0; + TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts)); + + /* At least one second must have passed. */ + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + tv2.tv_sec -= tv1.tv_sec; + tv2.tv_usec -= tv1.tv_usec; + if (tv2.tv_usec < 0) + --tv2.tv_sec; + + if (tv2.tv_sec < 1) + { + puts ("clock_nanosleep didn't sleep long enough"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond1.c b/test/nptl/tst-cond1.c new file mode 100644 index 000000000..46085c2b7 --- /dev/null +++ b/test/nptl/tst-cond1.c @@ -0,0 +1,94 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *p) +{ + int err; + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot get mutex"); + + puts ("child: got mutex; signalling"); + + pthread_cond_signal (&cond); + + puts ("child: unlock"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot unlock"); + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot get mutex"); + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot create thread"); + + puts ("parent: wait for condition"); + + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot wait fir signal"); + + puts ("parent: got signal"); + + err = pthread_join (th, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: failed to join"); + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond10.c b/test/nptl/tst-cond10.c new file mode 100644 index 000000000..34956d468 --- /dev/null +++ b/test/nptl/tst-cond10.c @@ -0,0 +1,173 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <error.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +#define N 10 +#define ROUNDS 100 + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t bN1; +static pthread_barrier_t b2; + + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("child: 1st mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 1st barrier_wait failed"); + exit (1); + } + + if (pthread_cond_wait (&cond, &mut) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("child: mutex_unlock failed"); + exit (1); + } + + e = pthread_barrier_wait (&bN1); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 2nd barrier_wait failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bN1, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int r; + for (r = 0; r < ROUNDS; ++r) + { + printf ("round %d\n", r + 1); + + int i; + pthread_t th[N]; + for (i = 0; i < N; ++i) + { + if (pthread_create (&th[i], &at, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: 1st barrier_wait failed"); + exit (1); + } + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + /* N single signal calls. Without locking. This tests that no + signal gets lost. */ + for (i = 0; i < N; ++i) + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bN1); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: 2nd barrier_wait failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond11.c b/test/nptl/tst-cond11.c new file mode 100644 index 000000000..0de4d5613 --- /dev/null +++ b/test/nptl/tst-cond11.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> + + +#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 +static int +run_test (clockid_t cl) +{ + pthread_condattr_t condattr; + pthread_cond_t cond; + pthread_mutexattr_t mutattr; + pthread_mutex_t mut; + + printf ("clock = %d\n", (int) cl); + + if (pthread_condattr_init (&condattr) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("condattr_setclock failed"); + return 1; + } + + 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; + } + + if (pthread_cond_init (&cond, &condattr) != 0) + { + puts ("cond_init failed"); + return 1; + } + + if (pthread_condattr_destroy (&condattr) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + if (pthread_mutexattr_init (&mutattr) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (&mut, &mutattr) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&mutattr) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != EDEADLK) + { + puts ("2nd mutex_lock did not return EDEADLK"); + return 1; + } + + struct timespec ts; + if (clock_gettime (cl, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + /* Wait one second. */ + ++ts.tv_sec; + + int e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("cond_timedwait succeeded"); + return 1; + } + else if (e != ETIMEDOUT) + { + puts ("cond_timedwait did not return ETIMEDOUT"); + return 1; + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&mut) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_cond_destroy (&cond) != 0) + { + puts ("cond_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 TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond12.c b/test/nptl/tst-cond12.c new file mode 100644 index 000000000..03e4881c9 --- /dev/null +++ b/test/nptl/tst-cond12.c @@ -0,0 +1,196 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static char fname[] = "/tmp/tst-cond12-XXXXXX"; +static int fd; + + +static void prepare (void); +#define PREPARE(argc, argv) prepare () + +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + + +static void +prepare (void) +{ + fd = mkstemp (fname); + if (fd == -1) + { + printf ("mkstemp failed: %m\n"); + exit (1); + } + add_temp_file (fname); + if (ftruncate (fd, 1000) < 0) + { + printf ("ftruncate failed: %m\n"); + exit (1); + } +} + + +static int +do_test (void) +{ + struct + { + pthread_mutex_t m; + pthread_cond_t c; + int var; + } *p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + { + printf ("initial mmap failed: %m\n"); + return 1; + } + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setpshared (&ma, 1) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + if (pthread_mutex_init (&p->m, &ma) != 0) + { + puts ("mutex_init failed"); + return 1; + } + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + pthread_condattr_t ca; + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + return 1; + } + if (pthread_condattr_setpshared (&ca, 1) != 0) + { + puts ("condattr_setpshared failed"); + return 1; + } + if (pthread_cond_init (&p->c, &ca) != 0) + { + puts ("mutex_init failed"); + return 1; + } + if (pthread_condattr_destroy (&ca) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&p->m) != 0) + { + puts ("initial mutex_lock failed"); + return 1; + } + + p->var = 42; + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid == 0) + { + void *oldp = p; + p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + if (p == oldp) + { + puts ("child: mapped to same address"); + kill (getppid (), SIGKILL); + exit (1); + } + + munmap (oldp, sizeof (*p)); + + if (pthread_mutex_lock (&p->m) != 0) + { + puts ("child: mutex_lock failed"); + kill (getppid (), SIGKILL); + exit (1); + } + + p->var = 0; + +#ifndef USE_COND_SIGNAL + if (pthread_cond_broadcast (&p->c) != 0) + { + puts ("child: cond_broadcast failed"); + kill (getppid (), SIGKILL); + exit (1); + } +#else + if (pthread_cond_signal (&p->c) != 0) + { + puts ("child: cond_signal failed"); + kill (getppid (), SIGKILL); + exit (1); + } +#endif + + if (pthread_mutex_unlock (&p->m) != 0) + { + puts ("child: mutex_unlock failed"); + kill (getppid (), SIGKILL); + exit (1); + } + + exit (0); + } + + do + pthread_cond_wait (&p->c, &p->m); + while (p->var != 0); + + if (TEMP_FAILURE_RETRY (waitpid (pid, NULL, 0)) != pid) + { + printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); + return 1; + } + + return 0; +} diff --git a/test/nptl/tst-cond13.c b/test/nptl/tst-cond13.c new file mode 100644 index 000000000..29d79b533 --- /dev/null +++ b/test/nptl/tst-cond13.c @@ -0,0 +1,2 @@ +#define USE_COND_SIGNAL 1 +#include "tst-cond12.c" diff --git a/test/nptl/tst-cond14.c b/test/nptl/tst-cond14.c new file mode 100644 index 000000000..106fa8c21 --- /dev/null +++ b/test/nptl/tst-cond14.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 1st mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 2nd mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 3rd mutex_lock failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut2) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + + if (pthread_cond_wait (&cond, &mut) != 0) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + puts ("parent: create child"); + + pthread_t th; + int err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("parent: cannot create thread: %s\n", strerror (err)); + return 1; + } + + /* We have to synchronize with the child. */ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + /* Give the child to reach to pthread_cond_wait. */ + sleep (1); + + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 3 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond15.c b/test/nptl/tst-cond15.c new file mode 100644 index 000000000..e815e253b --- /dev/null +++ b/test/nptl/tst-cond15.c @@ -0,0 +1,160 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 1st mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 2nd mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 3rd mutex_lock failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut2) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += p == NULL ? 100 : 1; + + int err = pthread_cond_timedwait (&cond, &mut, &ts); + if ((err != 0 && p == NULL) || (err != ETIMEDOUT && p != NULL)) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 1st mutex_unlock failed\n", __func__); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 2nd mutex_unlock failed\n", __func__); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 3rd mutex_unlock failed\n", __func__); + exit (1); + } + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + puts ("parent: create 1st child"); + + pthread_t th; + int err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("parent: cannot 1st create thread: %s\n", strerror (err)); + return 1; + } + + /* We have to synchronize with the child. */ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + /* Give the child to reach to pthread_cond_wait. */ + sleep (1); + + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + + puts ("parent: create 2nd child"); + + err = pthread_create (&th, NULL, tf, (void *) 1l); + if (err != 0) + { + printf ("parent: cannot 2nd create thread: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 6 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond16.c b/test/nptl/tst-cond16.c new file mode 100644 index 000000000..00c27eced --- /dev/null +++ b/test/nptl/tst-cond16.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +bool n, exiting; +FILE *f; +int count; + +void * +tf (void *dummy) +{ + bool loop = true; + + while (loop) + { + pthread_mutex_lock (&lock); + while (n && !exiting) + pthread_cond_wait (&cv, &lock); + n = true; + pthread_mutex_unlock (&lock); + + fputs (".", f); + + pthread_mutex_lock (&lock); + n = false; + if (exiting) + loop = false; +#ifdef UNLOCK_AFTER_BROADCAST + pthread_cond_broadcast (&cv); + pthread_mutex_unlock (&lock); +#else + pthread_mutex_unlock (&lock); + pthread_cond_broadcast (&cv); +#endif + } + + return NULL; +} + +int +do_test (void) +{ + f = fopen ("/dev/null", "w"); + if (f == NULL) + { + printf ("couldn't open /dev/null, %m\n"); + return 1; + } + + count = sysconf (_SC_NPROCESSORS_ONLN); + if (count <= 0) + count = 1; + count *= 4; + + pthread_t th[count]; + int i, ret; + for (i = 0; i < count; ++i) + if ((ret = pthread_create (&th[i], NULL, tf, NULL)) != 0) + { + errno = ret; + printf ("pthread_create %d failed: %m\n", i); + return 1; + } + + struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0); + + pthread_mutex_lock (&lock); + exiting = true; + pthread_mutex_unlock (&lock); + + for (i = 0; i < count; ++i) + pthread_join (th[i], NULL); + + fclose (f); + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 40 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond17.c b/test/nptl/tst-cond17.c new file mode 100644 index 000000000..0586fa59a --- /dev/null +++ b/test/nptl/tst-cond17.c @@ -0,0 +1,2 @@ +#define UNLOCK_AFTER_BROADCAST 1 +#include "tst-cond16.c" diff --git a/test/nptl/tst-cond18.c b/test/nptl/tst-cond18.c new file mode 100644 index 000000000..9fd81d298 --- /dev/null +++ b/test/nptl/tst-cond18.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +bool exiting; +int fd, count, spins, nn; + +void * +tf (void *id) +{ + pthread_mutex_lock (&lock); + + if ((long) id == 0) + { + while (!exiting) + { + if ((spins++ % 1000) == 0) + write (fd, ".", 1); + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); + int njobs = rand () % (count + 1); + nn = njobs; + if ((rand () % 30) == 0) + pthread_cond_broadcast (&cv); + else + while (njobs--) + pthread_cond_signal (&cv); + } + + pthread_cond_broadcast (&cv); + } + else + { + while (!exiting) + { + while (!nn && !exiting) + pthread_cond_wait (&cv, &lock); + --nn; + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); + } + } + + pthread_mutex_unlock (&lock); + return NULL; +} + +int +do_test (void) +{ + fd = open ("/dev/null", O_WRONLY); + if (fd < 0) + { + printf ("couldn't open /dev/null, %m\n"); + return 1; + } + + count = sysconf (_SC_NPROCESSORS_ONLN); + if (count <= 0) + count = 1; + count *= 8; + + pthread_t th[count + 1]; + int i, ret; + + for (i = 0; i <= count; ++i) + if ((ret = pthread_create (&th[i], NULL, tf, (void *) (long) i)) != 0) + { + errno = ret; + printf ("pthread_create %d failed: %m\n", i); + return 1; + } + + struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0); + + pthread_mutex_lock (&lock); + exiting = true; + pthread_mutex_unlock (&lock); + + for (i = 0; i < count; ++i) + pthread_join (th[i], NULL); + + close (fd); + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 40 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond19.c b/test/nptl/tst-cond19.c new file mode 100644 index 000000000..1c9bb7dd7 --- /dev/null +++ b/test/nptl/tst-cond19.c @@ -0,0 +1,76 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static int +do_test (void) +{ + int result = 0; + struct timespec ts; + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + ts.tv_nsec = -1; + + int e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("first cond_timedwait did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first cond_timedwait did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 2000000000; + + e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("second cond_timedwait did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second cond_timedwait did not return EINVAL"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond2.c b/test/nptl/tst-cond2.c new file mode 100644 index 000000000..36f0f2941 --- /dev/null +++ b/test/nptl/tst-cond2.c @@ -0,0 +1,163 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +static pthread_barrier_t bar; + + +static void * +tf (void *a) +{ + int i = (long int) a; + int err; + + printf ("child %d: lock\n", i); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "locking in child failed"); + + printf ("child %d: sync\n", i); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + printf ("child %d: wait\n", i); + + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "child %d: failed to wait", i); + + printf ("child %d: woken up\n", i); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child %d: unlock[2] failed", i); + + printf ("child %d: done\n", i); + + return NULL; +} + + +#define N 10 + + +static int +do_test (void) +{ + pthread_t th[N]; + int i; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + printf ("create thread %d\n", i); + + err = pthread_create (&th[i], &at, tf, (void *) (long int) i); + if (err != 0) + error (EXIT_FAILURE, err, "cannot create thread %d", i); + + printf ("wait for child %d\n", i); + + /* Wait for the child to start up and get the mutex for the + conditional variable. */ + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + puts ("get lock outselves"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "mut locking failed"); + + puts ("broadcast"); + + /* Wake up all threads. */ + err = pthread_cond_broadcast (&cond); + if (err != 0) + error (EXIT_FAILURE, err, "parent: broadcast failed"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "mut unlocking failed"); + + /* Join all threads. */ + for (i = 0; i < N; ++i) + { + printf ("join thread %d\n", i); + + err = pthread_join (th[i], NULL); + if (err != 0) + error (EXIT_FAILURE, err, "join of child %d failed", i); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond20.c b/test/nptl/tst-cond20.c new file mode 100644 index 000000000..18918f32e --- /dev/null +++ b/test/nptl/tst-cond20.c @@ -0,0 +1,170 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define N 10 +#define ROUNDS 1000 +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; +static int count; + +static void * +tf (void *p) +{ + int i; + for (i = 0; i < ROUNDS; ++i) + { + pthread_mutex_lock (&mut); + + if (++count == N) + pthread_cond_signal (&cond2); + +#ifdef TIMED + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + /* Wait three seconds. */ + ts.tv_sec = tv.tv_sec + 3; + ts.tv_nsec = tv.tv_usec * 1000; + pthread_cond_timedwait (&cond, &mut, &ts); +#else + pthread_cond_wait (&cond, &mut); +#endif + + pthread_mutex_unlock (&mut); + + int err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + } + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_mutex_lock (&mut); + + int i, j, err; + pthread_t th[N]; + for (i = 0; i < N; ++i) + if ((err = pthread_create (&th[i], NULL, tf, NULL)) != 0) + { + printf ("cannot create thread %d: %s\n", i, strerror (err)); + return 1; + } + + for (i = 0; i < ROUNDS; ++i) + { + pthread_cond_wait (&cond2, &mut); + + if (i & 1) + pthread_mutex_unlock (&mut); + + if (i & 2) + pthread_cond_broadcast (&cond); + else if (i & 4) + for (j = 0; j < N; ++j) + pthread_cond_signal (&cond); + else + { + for (j = 0; j < (i / 8) % N; ++j) + pthread_cond_signal (&cond); + pthread_cond_broadcast (&cond); + } + + if ((i & 1) == 0) + pthread_mutex_unlock (&mut); + + err = pthread_cond_destroy (&cond); + if (err) + { + printf ("pthread_cond_destroy failed: %s\n", strerror (err)); + return 1; + } + + /* Now clobber the cond variable which has been successfully + destroyed above. */ + memset (&cond, (char) i, sizeof (cond)); + + err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + + pthread_mutex_lock (&mut); + + err = pthread_barrier_wait (&b); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: barrier_wait failed"); + return 1; + } + + count = 0; + err = pthread_cond_init (&cond, NULL); + if (err) + { + printf ("pthread_cond_init failed: %s\n", strerror (err)); + return 1; + } + } + + for (i = 0; i < N; ++i) + if ((err = pthread_join (th[i], NULL)) != 0) + { + printf ("failed to join thread %d: %s\n", i, strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond21.c b/test/nptl/tst-cond21.c new file mode 100644 index 000000000..89cb771b5 --- /dev/null +++ b/test/nptl/tst-cond21.c @@ -0,0 +1,3 @@ +#include <sys/time.h> +#define TIMED 1 +#include "tst-cond20.c" diff --git a/test/nptl/tst-cond3.c b/test/nptl/tst-cond3.c new file mode 100644 index 000000000..cb9eb8558 --- /dev/null +++ b/test/nptl/tst-cond3.c @@ -0,0 +1,113 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +/* Note that this test requires more than the standard. It is + required that there are no spurious wakeups if only more readers + are added. This is a reasonable demand. */ + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +#define N 10 + + +static void * +tf (void *arg) +{ + int i = (long int) arg; + int err; + + /* Get the mutex. */ + err = pthread_mutex_lock (&mut); + if (err != 0) + { + printf ("child %d mutex_lock failed: %s\n", i, strerror (err)); + exit (1); + } + + /* This call should never return. */ + pthread_cond_wait (&cond, &mut); + + /* We should never get here. */ + exit (1); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + int i; + + for (i = 0; i < N; ++i) + { + pthread_t th; + + if (i != 0) + { + /* Release the mutex. */ + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + printf ("mutex_unlock %d failed: %s\n", i, strerror (err)); + return 1; + } + } + + err = pthread_create (&th, NULL, tf, (void *) (long int) i); + if (err != 0) + { + printf ("create %d failed: %s\n", i, strerror (err)); + return 1; + } + + /* Get the mutex. */ + err = pthread_mutex_lock (&mut); + if (err != 0) + { + printf ("mutex_lock %d failed: %s\n", i, strerror (err)); + return 1; + } + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + /* This call should never return. */ + pthread_cond_wait (&cond, &mut); + + puts ("cond_wait returned"); + return 1; +} + + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond4.c b/test/nptl/tst-cond4.c new file mode 100644 index 000000000..4d8859616 --- /dev/null +++ b/test/nptl/tst-cond4.c @@ -0,0 +1,264 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <stdint.h> + + +int *condition; + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-cond4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutexattr_t ma; + pthread_mutex_t *mut1; + pthread_mutex_t *mut2; + pthread_condattr_t ca; + pthread_cond_t *cond; + pid_t pid; + int result = 0; + int p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + mut1 = (pthread_mutex_t *) (((uintptr_t) mem + + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + mut2 = mut1 + 1; + + cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1) + + __alignof (pthread_cond_t)) + & ~(__alignof (pthread_cond_t) - 1)); + + condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int)) + & ~(__alignof (int) - 1)); + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&ma, &p) != 0) + { + puts ("1st mutexattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&ma, &p) != 0) + { + puts ("2nd mutexattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_mutex_init (mut1, &ma) != 0) + { + puts ("1st mutex_init failed"); + return 1; + } + + if (pthread_mutex_init (mut2, &ma) != 0) + { + puts ("2nd mutex_init failed"); + return 1; + } + + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (pthread_condattr_getpshared (&ca, &p) != 0) + { + puts ("1st condattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default value for pshared in condattr wrong"); + return 1; + } + + if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("condattr_setpshared failed"); + return 1; + } + + if (pthread_condattr_getpshared (&ca, &p) != 0) + { + puts ("2nd condattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared condattr still not set"); + return 1; + } + + if (pthread_cond_init (cond, &ca) != 0) + { + puts ("cond_init failed"); + return 1; + } + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 1st mutex_lock failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + if (pthread_mutex_lock (mut2) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (mut1) != 0) + { + puts ("child: 1st mutex_unlock failed"); + return 1; + } + + do + if (pthread_cond_wait (cond, mut2) != 0) + { + puts ("child: cond_wait failed"); + return 1; + } + while (*condition == 0); + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("child: 2nd mutex_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + int status; + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("parent: 3rd mutex_lock failed"); + return 1; + } + + if (pthread_cond_signal (cond) != 0) + { + puts ("parent: cond_signal failed"); + return 1; + } + + *condition = 1; + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("parent: mutex_unlock failed"); + return 1; + } + + puts ("waiting for child"); + + waitpid (pid, &status, 0); + result |= status; + + puts ("parent done"); + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond5.c b/test/nptl/tst-cond5.c new file mode 100644 index 000000000..efa207b5d --- /dev/null +++ b/test/nptl/tst-cond5.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_mutex_t mut; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + + +static int +do_test (void) +{ + pthread_mutexattr_t ma; + int err; + struct timespec ts; + struct timeval tv; + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + + if (pthread_mutex_init (&mut, &ma) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + /* Get the mutex. */ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Waiting for the condition will fail. But we want the timeout here. */ + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + exit (1); + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + /* This could in theory happen but here without any signal and + additional waiter it should not. */ + puts ("cond_timedwait succeeded"); + exit (1); + } + else if (err != ETIMEDOUT) + { + printf ("cond_timedwait returned with %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + printf ("mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond6.c b/test/nptl/tst-cond6.c new file mode 100644 index 000000000..8c5fe2093 --- /dev/null +++ b/test/nptl/tst-cond6.c @@ -0,0 +1,234 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <stdint.h> + + +int *condition; + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-cond6.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutexattr_t ma; + pthread_mutex_t *mut1; + pthread_mutex_t *mut2; + pthread_condattr_t ca; + pthread_cond_t *cond; + pid_t pid; + int result = 0; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + exit (1); + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + exit (1); + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + exit (1); + } + + mut1 = (pthread_mutex_t *) (((uintptr_t) mem + + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + mut2 = mut1 + 1; + + cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1) + + __alignof (pthread_cond_t)) + & ~(__alignof (pthread_cond_t) - 1)); + + condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int)) + & ~(__alignof (int) - 1)); + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + exit (1); + } + + if (pthread_mutex_init (mut1, &ma) != 0) + { + puts ("1st mutex_init failed"); + exit (1); + } + + if (pthread_mutex_init (mut2, &ma) != 0) + { + puts ("2nd mutex_init failed"); + exit (1); + } + + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + exit (1); + } + + if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("condattr_setpshared failed"); + exit (1); + } + + if (pthread_cond_init (cond, &ca) != 0) + { + puts ("cond_init failed"); + exit (1); + } + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 1st mutex_lock failed"); + exit (1); + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + else if (pid == 0) + { + struct timespec ts; + struct timeval tv; + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + if (pthread_mutex_unlock (mut1) != 0) + { + puts ("child: 1st mutex_unlock failed"); + exit (1); + } + + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + exit (1); + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + do + if (pthread_cond_timedwait (cond, mut2, &ts) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + while (*condition == 0); + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("child: 2nd mutex_unlock failed"); + exit (1); + } + + puts ("child done"); + } + else + { + int status; + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + exit (1); + } + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("parent: 3rd mutex_lock failed"); + exit (1); + } + + if (pthread_cond_signal (cond) != 0) + { + puts ("parent: cond_signal failed"); + exit (1); + } + + *condition = 1; + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + puts ("waiting for child"); + + waitpid (pid, &status, 0); + result |= status; + + puts ("parent done"); + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond7.c b/test/nptl/tst-cond7.c new file mode 100644 index 000000000..5ab7b8f8f --- /dev/null +++ b/test/nptl/tst-cond7.c @@ -0,0 +1,168 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> + + +typedef struct + { + pthread_cond_t cond; + pthread_mutex_t lock; + pthread_t h; + } T; + + +static volatile bool done; + + +static void * +tf (void *arg) +{ + puts ("child created"); + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + T *t = (T *) arg; + + if (pthread_mutex_lock (&t->lock) != 0) + { + puts ("child: lock failed"); + exit (1); + } + + done = true; + + if (pthread_cond_signal (&t->cond) != 0) + { + puts ("child: cond_signal failed"); + exit (1); + } + + if (pthread_cond_wait (&t->cond, &t->lock) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&t->lock) != 0) + { + puts ("child: unlock failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + int i; +#define N 100 + T *t[N]; + for (i = 0; i < N; ++i) + { + printf ("round %d\n", i); + + t[i] = (T *) malloc (sizeof (T)); + if (t[i] == NULL) + { + puts ("out of memory"); + exit (1); + } + + if (pthread_mutex_init (&t[i]->lock, NULL) != 0 + || pthread_cond_init (&t[i]->cond, NULL) != 0) + { + puts ("an _init function failed"); + exit (1); + } + + if (pthread_mutex_lock (&t[i]->lock) != 0) + { + puts ("initial mutex_lock failed"); + exit (1); + } + + done = false; + + if (pthread_create (&t[i]->h, NULL, tf, t[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + do + if (pthread_cond_wait (&t[i]->cond, &t[i]->lock) != 0) + { + puts ("cond_wait failed"); + exit (1); + } + while (! done); + + /* Release the lock since the cancel handler will get it. */ + if (pthread_mutex_unlock (&t[i]->lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (t[i]->h) != 0) + { + puts ("cancel failed"); + exit (1); + } + + puts ("parent: joining now"); + + void *result; + if (pthread_join (t[i]->h, &result) != 0) + { + puts ("join failed"); + exit (1); + } + + if (result != PTHREAD_CANCELED) + { + puts ("result != PTHREAD_CANCELED"); + exit (1); + } + } + + for (i = 0; i < N; ++i) + free (t[i]); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond8.c b/test/nptl/tst-cond8.c new file mode 100644 index 000000000..9c97a96fa --- /dev/null +++ b/test/nptl/tst-cond8.c @@ -0,0 +1,277 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static pthread_barrier_t bar; + + +static void +ch (void *arg) +{ + int e = pthread_mutex_lock (&mut); + if (e == 0) + { + puts ("mutex not locked at all by cond_wait"); + exit (1); + } + + if (e != EDEADLK) + { + puts ("no deadlock error signaled"); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("ch: cannot unlock mutex"); + exit (1); + } + + puts ("ch done"); +} + + +static void * +tf1 (void *p) +{ + int err; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("child: cannot get mutex"); + exit (1); + } + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("barrier_wait returned %d\n", err); + exit (1); + } + + puts ("child: got mutex; waiting"); + + pthread_cleanup_push (ch, NULL); + + pthread_cond_wait (&cond, &mut); + + pthread_cleanup_pop (0); + + puts ("child: cond_wait should not have returned"); + + return NULL; +} + + +static void * +tf2 (void *p) +{ + int err; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("child: cannot get mutex"); + exit (1); + } + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("barrier_wait returned %d\n", err); + exit (1); + } + + puts ("child: got mutex; waiting"); + + pthread_cleanup_push (ch, NULL); + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + pthread_cond_timedwait (&cond, &mut, &ts); + + pthread_cleanup_pop (0); + + puts ("child: cond_wait should not have returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_barrier_init (&bar, NULL, 2); + if (err != 0) + { + puts ("parent: cannot init barrier"); + exit (1); + } + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf1, NULL); + if (err != 0) + { + puts ("parent: cannot create thread"); + exit (1); + } + + puts ("parent: wait for child to lock mutex"); + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: cannot wait for barrier"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel thread"); + exit (1); + } + + void *r; + err = pthread_join (th, &r); + if (err != 0) + { + puts ("parent: failed to join"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("child hasn't been canceled"); + exit (1); + } + + + + puts ("parent: create 2nd child"); + + err = pthread_create (&th, NULL, tf2, NULL); + if (err != 0) + { + puts ("parent: cannot create thread"); + exit (1); + } + + puts ("parent: wait for child to lock mutex"); + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: cannot wait for barrier"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel thread"); + exit (1); + } + + err = pthread_join (th, &r); + if (err != 0) + { + puts ("parent: failed to join"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("child hasn't been canceled"); + exit (1); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cond9.c b/test/nptl/tst-cond9.c new file mode 100644 index 000000000..2a8477dd8 --- /dev/null +++ b/test/nptl/tst-cond9.c @@ -0,0 +1,150 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + + +static void * +tf (void *arg) +{ + int err = pthread_cond_wait (&cond, &mut); + if (err == 0) + { + puts ("cond_wait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_wait didn't return EPERM but %d\n", err); + exit (1); + } + + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + puts ("cond_timedwait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_timedwait didn't return EPERM but %d\n", err); + exit (1); + } + + return (void *) 1l; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + err = pthread_cond_wait (&cond, &mut); + if (err == 0) + { + puts ("cond_wait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_wait didn't return EPERM but %d\n", err); + exit (1); + } + + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + puts ("cond_timedwait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_timedwait didn't return EPERM but %d\n", err); + exit (1); + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + puts ("creating thread"); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != (void *) 1l) + { + puts ("thread has wrong return value"); + exit (1); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cpuclock1.c b/test/nptl/tst-cpuclock1.c new file mode 100644 index 000000000..024df6314 --- /dev/null +++ b/test/nptl/tst-cpuclock1.c @@ -0,0 +1,307 @@ +/* Test program for process CPU clocks. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +/* This function is intended to rack up both user and system time. */ +static void +chew_cpu (void) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); + } +} + +static int +do_test (void) +{ + int result = 0; + clockid_t cl; + int e; + pid_t dead_child, child; + + /* Fork a child and let it die, to give us a PID known not be valid + (assuming PIDs don't wrap around during the test). */ + { + dead_child = fork (); + if (dead_child == 0) + _exit (0); + if (dead_child < 0) + { + perror ("fork"); + return 1; + } + int x; + if (wait (&x) != dead_child) + { + perror ("wait"); + return 2; + } + } + + /* POSIX says we should get ESRCH for this. */ + e = clock_getcpuclockid (dead_child, &cl); + if (e != ENOSYS && e != ESRCH && e != EPERM) + { + printf ("clock_getcpuclockid on dead PID %d => %s\n", + dead_child, strerror (e)); + result = 1; + } + + /* Now give us a live child eating up CPU time. */ + child = fork (); + if (child == 0) + { + chew_cpu (); + _exit (1); + } + if (child < 0) + { + perror ("fork"); + return 1; + } + + e = clock_getcpuclockid (child, &cl); + if (e == EPERM) + { + puts ("clock_getcpuclockid does not support other processes"); + goto done; + } + if (e != 0) + { + printf ("clock_getcpuclockid on live PID %d => %s\n", + child, strerror (e)); + result = 1; + goto done; + } + + const clockid_t child_clock = cl; + struct timespec res; + if (clock_getres (child_clock, &res) < 0) + { + printf ("clock_getres on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d clock %lx resolution %lu.%.9lu\n", + child, (unsigned long int) child_clock, res.tv_sec, res.tv_nsec); + + struct timespec before, after; + if (clock_gettime (child_clock, &before) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d before sleep => %lu.%.9lu\n", + child, before.tv_sec, before.tv_nsec); + + struct timespec sleeptime = { .tv_nsec = 500000000 }; + nanosleep (&sleeptime, NULL); + + if (clock_gettime (child_clock, &after) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("live PID %d after sleep => %lu.%.9lu\n", + child, after.tv_sec, after.tv_nsec); + + struct timespec diff = { .tv_sec = after.tv_sec - before.tv_sec, + .tv_nsec = after.tv_nsec - before.tv_nsec }; + if (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + if (diff.tv_sec != 0 + || diff.tv_nsec > 600000000 + || diff.tv_nsec < 100000000) + { + printf ("before - after %lu.%.9lu outside reasonable range\n", + diff.tv_sec, diff.tv_nsec); + result = 1; + } + + sleeptime.tv_nsec = 100000000; + e = clock_nanosleep (child_clock, 0, &sleeptime, NULL); + if (e == EINVAL || e == ENOTSUP || e == ENOSYS) + { + printf ("clock_nanosleep not supported for other process clock: %s\n", + strerror (e)); + } + else if (e != 0) + { + printf ("clock_nanosleep on other process clock: %s\n", strerror (e)); + result = 1; + } + else + { + struct timespec afterns; + if (clock_gettime (child_clock, &afterns) < 0) + { + printf ("clock_gettime on live PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + } + else + { + struct timespec d = { .tv_sec = afterns.tv_sec - after.tv_sec, + .tv_nsec = afterns.tv_nsec - after.tv_nsec }; + if (d.tv_nsec < 0) + { + --d.tv_sec; + d.tv_nsec += 1000000000; + } + if (d.tv_sec > 0 + || d.tv_nsec < sleeptime.tv_nsec + || d.tv_nsec > sleeptime.tv_nsec * 2) + { + printf ("nanosleep time %lu.%.9lu outside reasonable range\n", + d.tv_sec, d.tv_nsec); + result = 1; + } + } + } + + if (kill (child, SIGKILL) != 0) + { + perror ("kill"); + result = 2; + goto done; + } + + /* Wait long enough to let the child finish dying. */ + + sleeptime.tv_nsec = 200000000; + nanosleep (&sleeptime, NULL); + + struct timespec dead; + if (clock_gettime (child_clock, &dead) < 0) + { + printf ("clock_gettime on dead PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + result = 1; + goto done; + } + printf ("dead PID %d => %lu.%.9lu\n", + child, dead.tv_sec, dead.tv_nsec); + + diff.tv_sec = dead.tv_sec - after.tv_sec; + diff.tv_nsec = dead.tv_nsec - after.tv_nsec; + if (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + if (diff.tv_sec != 0 || diff.tv_nsec > 200000000) + { + printf ("dead - after %lu.%.9lu outside reasonable range\n", + diff.tv_sec, diff.tv_nsec); + result = 1; + } + + /* Now reap the child and verify that its clock is no longer valid. */ + { + int x; + if (waitpid (child, &x, 0) != child) + { + perror ("waitpid"); + result = 1; + } + } + + if (clock_gettime (child_clock, &dead) == 0) + { + printf ("clock_gettime on reaped PID %d clock %lx => %lu%.9lu\n", + child, (unsigned long int) child_clock, + dead.tv_sec, dead.tv_nsec); + result = 1; + } + else + { + if (errno != EINVAL) + result = 1; + printf ("clock_gettime on reaped PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + } + + if (clock_getres (child_clock, &dead) == 0) + { + printf ("clock_getres on reaped PID %d clock %lx => %lu%.9lu\n", + child, (unsigned long int) child_clock, + dead.tv_sec, dead.tv_nsec); + result = 1; + } + else + { + if (errno != EINVAL) + result = 1; + printf ("clock_getres on reaped PID %d clock %lx => %s\n", + child, (unsigned long int) child_clock, strerror (errno)); + } + + return result; + + done: + { + if (kill (child, SIGKILL) != 0 && errno != ESRCH) + { + perror ("kill"); + return 2; + } + int x; + if (waitpid (child, &x, 0) != child && errno != ECHILD) + { + perror ("waitpid"); + return 2; + } + } + + return result; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cpuclock2.c b/test/nptl/tst-cpuclock2.c new file mode 100644 index 000000000..d1621f3d0 --- /dev/null +++ b/test/nptl/tst-cpuclock2.c @@ -0,0 +1,332 @@ +/* Test program for process and thread CPU clocks. + Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <unistd.h> + +#if (_POSIX_THREADS - 0) <= 0 + +# define TEST_FUNCTION 0 + +#else + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <fcntl.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> + +static pthread_barrier_t barrier; + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + pthread_barrier_wait (&barrier); + + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static unsigned long long int +tsdiff (const struct timespec *before, const struct timespec *after) +{ + struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec, + .tv_nsec = after->tv_nsec - before->tv_nsec }; + while (diff.tv_nsec < 0) + { + --diff.tv_sec; + diff.tv_nsec += 1000000000; + } + return diff.tv_sec * 1000000000ULL + diff.tv_nsec; +} + +static unsigned long long int +test_nanosleep (clockid_t clock, const char *which, + const struct timespec *before, int *bad) +{ + const struct timespec sleeptime = { .tv_nsec = 100000000 }; + int e = clock_nanosleep (clock, 0, &sleeptime, NULL); + if (e == EINVAL || e == ENOTSUP || e == ENOSYS) + { + printf ("clock_nanosleep not supported for %s CPU clock: %s\n", + which, strerror (e)); + return 0; + } + if (e != 0) + { + printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e)); + *bad = 1; + return 0; + } + + struct timespec after; + if (clock_gettime (clock, &after) < 0) + { + printf ("clock_gettime on %s CPU clock %lx => %s\n", + which, (unsigned long int) clock, strerror (errno)); + *bad = 1; + return 0; + } + + unsigned long long int diff = tsdiff (before, &after); + if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2) + { + printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n", + which, diff); + *bad = 1; + return diff; + } + + struct timespec sleeptimeabs = sleeptime; + sleeptimeabs.tv_sec += after.tv_sec; + sleeptimeabs.tv_nsec += after.tv_nsec; + while (sleeptimeabs.tv_nsec > 1000000000) + { + ++sleeptimeabs.tv_sec; + sleeptimeabs.tv_nsec -= 1000000000; + } + e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL); + if (e != 0) + { + printf ("absolute clock_nanosleep on %s CPU clock: %s\n", + which, strerror (e)); + *bad = 1; + return diff; + } + + struct timespec afterabs; + if (clock_gettime (clock, &afterabs) < 0) + { + printf ("clock_gettime on %s CPU clock %lx => %s\n", + which, (unsigned long int) clock, strerror (errno)); + *bad = 1; + return diff; + } + + unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs); + if (sleepdiff > sleeptime.tv_nsec) + { + printf ("\ +absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n", + which, sleepdiff); + *bad = 1; + } + + unsigned long long int diffabs = tsdiff (&after, &afterabs); + if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2) + { + printf ("\ +absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n", + which, diffabs); + *bad = 1; + } + + return diff + diffabs; +} + + + +static int +do_test (void) +{ + int result = 0; + clockid_t process_clock, th_clock, my_thread_clock; + int e; + pthread_t th; + + e = clock_getcpuclockid (0, &process_clock); + if (e != 0) + { + printf ("clock_getcpuclockid on self => %s\n", strerror (e)); + return 1; + } + + e = pthread_getcpuclockid (pthread_self (), &my_thread_clock); + if (e != 0) + { + printf ("pthread_getcpuclockid on self => %s\n", strerror (e)); + return 1; + } + + /* This is a kludge. This test fails if the semantics of thread and + process clocks are wrong. The old code using hp-timing without kernel + support has bogus semantics if there are context switches. We don't + fail to report failure when the proper functionality is not available + in the kernel. It so happens that Linux kernels without correct CPU + clock support also lack CPU timer support, so we use use that to guess + that we are using the bogus code and not test it. */ + timer_t t; + if (timer_create (my_thread_clock, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + puts ("No support for CPU clocks with good semantics, skipping test"); + return 0; + } + timer_delete (t); + + + pthread_barrier_init (&barrier, NULL, 2); + + e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + return 1; + } + + e = pthread_getcpuclockid (th, &th_clock); + if (e == ENOENT || e == ENOSYS || e == ENOTSUP) + { + puts ("pthread_getcpuclockid does not support other threads"); + return 1; + } + + pthread_barrier_wait (&barrier); + + struct timespec res; + if (clock_getres (th_clock, &res) < 0) + { + printf ("clock_getres on thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + result = 1; + return 1; + } + printf ("live thread clock %lx resolution %lu.%.9lu\n", + (unsigned long int) th_clock, res.tv_sec, res.tv_nsec); + + struct timespec process_before, process_after; + if (clock_gettime (process_clock, &process_before) < 0) + { + printf ("clock_gettime on process clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + + struct timespec before, after; + if (clock_gettime (th_clock, &before) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("live thread before sleep => %lu.%.9lu\n", + before.tv_sec, before.tv_nsec); + + struct timespec me_before, me_after; + if (clock_gettime (my_thread_clock, &me_before) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("self thread before sleep => %lu.%.9lu\n", + me_before.tv_sec, me_before.tv_nsec); + + struct timespec sleeptime = { .tv_nsec = 500000000 }; + nanosleep (&sleeptime, NULL); + + if (clock_gettime (th_clock, &after) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("live thread after sleep => %lu.%.9lu\n", + after.tv_sec, after.tv_nsec); + + if (clock_gettime (process_clock, &process_after) < 0) + { + printf ("clock_gettime on process clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + + if (clock_gettime (my_thread_clock, &me_after) < 0) + { + printf ("clock_gettime on live thread clock %lx => %s\n", + (unsigned long int) th_clock, strerror (errno)); + return 1; + } + printf ("self thread after sleep => %lu.%.9lu\n", + me_after.tv_sec, me_after.tv_nsec); + + unsigned long long int th_diff = tsdiff (&before, &after); + unsigned long long int pdiff = tsdiff (&process_before, &process_after); + unsigned long long int my_diff = tsdiff (&me_before, &me_after); + + if (th_diff < 100000000 || th_diff > 600000000) + { + printf ("thread before - after %llu outside reasonable range\n", + th_diff); + result = 1; + } + + if (my_diff > 100000000) + { + printf ("self thread before - after %llu outside reasonable range\n", + my_diff); + result = 1; + } + + if (pdiff < th_diff) + { + printf ("process before - after %llu outside reasonable range (%llu)\n", + pdiff, th_diff); + result = 1; + } + + process_after.tv_nsec += test_nanosleep (th_clock, "thread", + &after, &result); + process_after.tv_nsec += test_nanosleep (process_clock, "process", + &process_after, &result); + test_nanosleep (CLOCK_PROCESS_CPUTIME_ID, + "PROCESS_CPUTIME_ID", &process_after, &result); + + pthread_cancel (th); + + e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL); + if (e != EINVAL) + { + printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n", + strerror (e)); + result = 1; + } + + return result; +} +# define TIMEOUT 8 +# define TEST_FUNCTION do_test () +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-cputimer1.c b/test/nptl/tst-cputimer1.c new file mode 100644 index 000000000..8f5dd76cf --- /dev/null +++ b/test/nptl/tst-cputimer1.c @@ -0,0 +1,68 @@ +/* Tests for POSIX timer implementation using process CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> + +#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "process CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static int +setup_test (void) +{ + /* Test timers on our own process CPU clock by having a worker thread + eating CPU. First make sure we can make such timers at all. */ + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + pthread_t th; + int e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + exit (1); + } + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-cputimer2.c b/test/nptl/tst-cputimer2.c new file mode 100644 index 000000000..397d7998c --- /dev/null +++ b/test/nptl/tst-cputimer2.c @@ -0,0 +1,83 @@ +/* Tests for POSIX timer implementation using thread CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <pthread.h> + +static clockid_t worker_thread_clock; + +#define TEST_CLOCK worker_thread_clock +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "thread CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void * +chew_cpu (void *arg) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + } + + return NULL; +} + +static int +setup_test (void) +{ + /* Test timers on a thread CPU clock by having a worker thread eating + CPU. First make sure we can make such timers at all. */ + + pthread_t th; + int e = pthread_create (&th, NULL, chew_cpu, NULL); + if (e != 0) + { + printf ("pthread_create: %s\n", strerror (e)); + exit (1); + } + + e = pthread_getcpuclockid (th, &worker_thread_clock); + if (e == EPERM || e == ENOENT || e == ENOTSUP) + { + puts ("pthread_getcpuclockid does not support other threads"); + return 1; + } + if (e != 0) + { + printf ("pthread_getcpuclockid: %s\n", strerror (e)); + exit (1); + } + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-cputimer3.c b/test/nptl/tst-cputimer3.c new file mode 100644 index 000000000..056766a37 --- /dev/null +++ b/test/nptl/tst-cputimer3.c @@ -0,0 +1,130 @@ +/* Tests for POSIX timer implementation using another process's CPU clock. */ + +#include <unistd.h> + +#if _POSIX_THREADS && defined _POSIX_CPUTIME + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <time.h> +#include <signal.h> +#include <sys/wait.h> + +static clockid_t child_clock; + +#define TEST_CLOCK child_clock +#define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "other-process CPU clock timer support" : NULL) + +/* This function is intended to rack up both user and system time. */ +static void +chew_cpu (void) +{ + while (1) + { + static volatile char buf[4096]; + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xaa; + int nullfd = open ("/dev/null", O_WRONLY); + for (int i = 0; i < 100; ++i) + for (size_t j = 0; j < sizeof buf; ++j) + buf[j] = 0xbb; + write (nullfd, (char *) buf, sizeof buf); + close (nullfd); + if (getppid () == 1) + _exit (2); + } +} + +static pid_t child; +static void +cleanup_child (void) +{ + if (child <= 0) + return; + if (kill (child, SIGKILL) < 0 && errno != ESRCH) + printf ("cannot kill child %d: %m\n", child); + else + { + int status; + errno = 0; + if (waitpid (child, &status, 0) != child) + printf ("waitpid %d: %m\n", child); + } +} +#define CLEANUP_HANDLER cleanup_child () + +static int +setup_test (void) +{ + /* Test timers on a process CPU clock by having a child process eating + CPU. First make sure we can make such timers at all. */ + + int pipefd[2]; + if (pipe (pipefd) < 0) + { + printf ("pipe: %m\n"); + exit (1); + } + + child = fork (); + + if (child == 0) + { + char c; + close (pipefd[1]); + if (read (pipefd[0], &c, 1) == 1) + chew_cpu (); + _exit (1); + } + + if (child < 0) + { + printf ("fork: %m\n"); + exit (1); + } + + atexit (&cleanup_child); + + close (pipefd[0]); + + int e = clock_getcpuclockid (child, &child_clock); + if (e == EPERM) + { + puts ("clock_getcpuclockid does not support other processes"); + return 1; + } + if (e != 0) + { + printf ("clock_getcpuclockid: %s\n", strerror (e)); + exit (1); + } + + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + /* Get the child started chewing. */ + if (write (pipefd[1], "x", 1) != 1) + { + printf ("write to pipe: %m\n"); + return 1; + } + close (pipefd[1]); + + return 0; +} + +#else +# define TEST_CLOCK_MISSING(clock) "process clocks" +#endif + +#include "tst-timer4.c" diff --git a/test/nptl/tst-detach1.c b/test/nptl/tst-detach1.c new file mode 100644 index 000000000..7b27f6ead --- /dev/null +++ b/test/nptl/tst-detach1.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + /* Give the child a chance to finish. */ + sleep (1); + + if (pthread_detach (th) != 0) + { + puts ("detach failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr1.c b/test/nptl/tst-eintr1.c new file mode 100644 index 000000000..43a5df5b9 --- /dev/null +++ b/test/nptl/tst-eintr1.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "eintr.c" + + +static void * +tf2 (void *arg) +{ + return arg; +} + + +static void * +tf1 (void *arg) +{ + while (1) + { + pthread_t th; + + int e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + if (e == EINTR) + { + puts ("pthread_create returned EINTR"); + exit (1); + } + + char buf[100]; + printf ("tf1: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + e = pthread_join (th, NULL); + if (e != 0) + { + if (e == EINTR) + { + puts ("pthread_join returned EINTR"); + exit (1); + } + + char buf[100]; + printf ("tf1: pthread_join failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + } +} + + +static int +do_test (void) +{ + setup_eintr (SIGUSR1, NULL); + + int i; + for (i = 0; i < 10; ++i) + { + pthread_t th; + int e = pthread_create (&th, NULL, tf1, NULL); + if (e != 0) + { + char buf[100]; + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + } + + (void) tf1 (NULL); + /* NOTREACHED */ + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr2.c b/test/nptl/tst-eintr2.c new file mode 100644 index 000000000..8cbbc5a02 --- /dev/null +++ b/test/nptl/tst-eintr2.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "eintr.c" + + +static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf1 (void *arg) +{ + struct timespec ts; + struct timeval tv; + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10000; + + /* This call must never return. */ + int e = pthread_mutex_timedlock (&m1, &ts); + char buf[100]; + printf ("tf1: mutex_timedlock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + exit (1); +} + + +static void * +tf2 (void *arg) +{ + while (1) + { + int e = pthread_mutex_lock (&m2); + if (e != 0) + { + puts ("tf2: mutex_lock failed"); + exit (1); + } + e = pthread_mutex_unlock (&m2); + if (e != 0) + { + puts ("tf2: mutex_unlock failed"); + exit (1); + } + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + } +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&m1) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + setup_eintr (SIGUSR1, NULL); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf1, NULL); + if (e != 0) + { + printf ("main: 1st pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + printf ("main: 2nd pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_mutex_lock (&m1); + printf ("main: mutex_lock returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr3.c b/test/nptl/tst-eintr3.c new file mode 100644 index 000000000..eecab48b1 --- /dev/null +++ b/test/nptl/tst-eintr3.c @@ -0,0 +1,72 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "eintr.c" + + +static void * +tf (void *arg) +{ + pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock (&m); + /* This call must not return. */ + pthread_mutex_lock (&m); + + puts ("tf: mutex_lock returned"); + exit (1); +} + + +static int +do_test (void) +{ + pthread_t self = pthread_self (); + + setup_eintr (SIGUSR1, &self); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_join (th, NULL); + + if (e == EINTR) + puts ("pthread_join returned with EINTR"); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 1 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr4.c b/test/nptl/tst-eintr4.c new file mode 100644 index 000000000..dffbdd605 --- /dev/null +++ b/test/nptl/tst-eintr4.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "eintr.c" + + +static int +do_test (void) +{ + pthread_t self = pthread_self (); + + setup_eintr (SIGUSR1, &self); + + pthread_barrier_t b; + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + /* This call must never return. */ + int e = pthread_barrier_wait (&b); + + if (e == EINTR) + puts ("pthread_join returned with EINTR"); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 1 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-eintr5.c b/test/nptl/tst-eintr5.c new file mode 100644 index 000000000..91473ec4c --- /dev/null +++ b/test/nptl/tst-eintr5.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + +#include "eintr.c" + + +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; + + +static void * +tf (void *arg) +{ + struct timespec ts; + struct timeval tv; + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10000; + + /* This call must never return. */ + int e = pthread_cond_timedwait (&c, &m, &ts); + char buf[100]; + printf ("tf: cond_timedwait returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + exit (1); +} + + +static int +do_test (void) +{ + setup_eintr (SIGUSR1, NULL); + + pthread_t th; + char buf[100]; + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("main: pthread_create failed: %s\n", + strerror_r (e, buf, sizeof (buf))); + exit (1); + } + + /* This call must never return. */ + e = pthread_cond_wait (&c, &m); + printf ("main: cond_wait returned: %s\n", + strerror_r (e, buf, sizeof (buf))); + + return 0; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exec2.c b/test/nptl/tst-exec2.c new file mode 100644 index 000000000..432da32ef --- /dev/null +++ b/test/nptl/tst-exec2.c @@ -0,0 +1,154 @@ +/* Thread with running thread calls exec. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static void * +tf (void *arg) +{ + pthread_t th = (pthread_t) arg; + + if (pthread_join (th, NULL) == 0) + { + puts ("thread in parent joined!?"); + exit (1); + } + + puts ("join in thread in parent returned!?"); + exit (1); +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + exit (1); + } + + /* Not interested in knowing when the pipe is closed. */ + if (sigignore (SIGPIPE) != 0) + { + puts ("sigignore failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Use the fd for stdout. This is kind of ugly because it + substitutes the fd of stdout but we know what we are doing + here... */ + if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO) + { + puts ("dup2 failed"); + exit (1); + } + + close (fd[0]); + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL); + + puts ("execl failed"); + exit (1); + } + + close (fd[1]); + + char buf[200]; + ssize_t n; + bool seen_pid = false; + while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0) + { + /* We only expect to read the PID. */ + char *endp; + long int rpid = strtol (buf, &endp, 10); + + if (*endp != '\n') + { + printf ("didn't parse whole line: \"%s\"\n", buf); + exit (1); + } + if (endp == buf) + { + puts ("read empty line"); + exit (1); + } + + if (rpid != pid) + { + printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid); + exit (1); + } + + if (seen_pid) + { + puts ("found more than one PID line"); + exit (1); + } + seen_pid = true; + } + + close (fd[0]); + + int status; + int err = waitpid (pid, &status, 0); + if (err != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (!seen_pid) + { + puts ("didn't get PID"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exec3.c b/test/nptl/tst-exec3.c new file mode 100644 index 000000000..be49b048c --- /dev/null +++ b/test/nptl/tst-exec3.c @@ -0,0 +1,152 @@ +/* Thread calls exec. + Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <paths.h> +#include <pthread.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static void * +tf (void *arg) +{ + execl (_PATH_BSHELL, _PATH_BSHELL, "-c", "echo $$", NULL); + + puts ("execl failed"); + exit (1); +} + + +static int +do_test (void) +{ + int fd[2]; + if (pipe (fd) != 0) + { + puts ("pipe failed"); + exit (1); + } + + /* Not interested in knowing when the pipe is closed. */ + if (sigignore (SIGPIPE) != 0) + { + puts ("sigignore failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + { + /* Use the fd for stdout. This is kind of ugly because it + substitutes the fd of stdout but we know what we are doing + here... */ + if (dup2 (fd[1], STDOUT_FILENO) != STDOUT_FILENO) + { + puts ("dup2 failed"); + exit (1); + } + + close (fd[0]); + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_join (th, NULL) == 0) + { + puts ("join succeeded!?"); + exit (1); + } + + puts ("join returned!?"); + exit (1); + } + + close (fd[1]); + + char buf[200]; + ssize_t n; + bool seen_pid = false; + while (TEMP_FAILURE_RETRY ((n = read (fd[0], buf, sizeof (buf)))) > 0) + { + /* We only expect to read the PID. */ + char *endp; + long int rpid = strtol (buf, &endp, 10); + + if (*endp != '\n') + { + printf ("didn't parse whole line: \"%s\"\n", buf); + exit (1); + } + if (endp == buf) + { + puts ("read empty line"); + exit (1); + } + + if (rpid != pid) + { + printf ("found \"%s\", expected PID %ld\n", buf, (long int) pid); + exit (1); + } + + if (seen_pid) + { + puts ("found more than one PID line"); + exit (1); + } + seen_pid = true; + } + + close (fd[0]); + + int status; + int err = waitpid (pid, &status, 0); + if (err != pid) + { + puts ("waitpid failed"); + exit (1); + } + + if (!seen_pid) + { + puts ("didn't get PID"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exec4.c b/test/nptl/tst-exec4.c new file mode 100644 index 000000000..b3920a030 --- /dev/null +++ b/test/nptl/tst-exec4.c @@ -0,0 +1,116 @@ +/* Signal handler and mask set in thread which calls exec. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + /* Ignore SIGUSR1 and block SIGUSR2. */ + if (sigignore (SIGUSR1) != 0) + { + puts ("sigignore failed"); + exit (1); + } + + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, SIGUSR2); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("1st run: sigmask failed"); + exit (1); + } + + char **oldargv = (char **) arg; + size_t n = 1; + while (oldargv[n] != NULL) + ++n; + + char **argv = (char **) alloca ((n + 1) * sizeof (char *)); + for (n = 0; oldargv[n + 1] != NULL; ++n) + argv[n] = oldargv[n + 1]; + argv[n++] = (char *) "--direct"; + argv[n] = NULL; + + execv (argv[0], argv); + + puts ("execv failed"); + + exit (1); +} + + +static int +do_test (int argc, char *argv[]) +{ + if (argc == 1) + { + /* This is the second call. Perform the test. */ + struct sigaction sa; + + if (sigaction (SIGUSR1, NULL, &sa) != 0) + { + puts ("2nd run: sigaction failed"); + return 1; + } + if (sa.sa_handler != SIG_IGN) + { + puts ("SIGUSR1 not ignored"); + return 1; + } + + sigset_t ss; + if (pthread_sigmask (SIG_SETMASK, NULL, &ss) != 0) + { + puts ("2nd run: sigmask failed"); + return 1; + } + if (! sigismember (&ss, SIGUSR2)) + { + puts ("SIGUSR2 not blocked"); + return 1; + } + + return 0; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, argv) != 0) + { + puts ("create failed"); + exit (1); + } + + /* This call should never return. */ + pthread_join (th, NULL); + + puts ("join returned"); + + return 1; +} + +#define TEST_FUNCTION do_test (argc, argv) +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exit1.c b/test/nptl/tst-exit1.c new file mode 100644 index 000000000..44175f76c --- /dev/null +++ b/test/nptl/tst-exit1.c @@ -0,0 +1,79 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +static pthread_barrier_t b; + + +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); + } + + exit (0); +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + /* Do nothing. */ + if (pthread_join (th, NULL) == 0) + { + puts ("join succeeded!?"); + exit (1); + } + + puts ("join returned!?"); + exit (1); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exit2.c b/test/nptl/tst-exit2.c new file mode 100644 index 000000000..3f5ff27b0 --- /dev/null +++ b/test/nptl/tst-exit2.c @@ -0,0 +1,40 @@ +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + + +static void * +tf (void *arg) +{ + while (1) + sleep (100); + + /* NOTREACHED */ + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("create failed: %s\n", strerror (e)); + return 1; + } + + /* Terminate only this thread. */ + pthread_exit (NULL); + + /* NOTREACHED */ + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-exit3.c b/test/nptl/tst-exit3.c new file mode 100644 index 000000000..da92c82c0 --- /dev/null +++ b/test/nptl/tst-exit3.c @@ -0,0 +1,81 @@ +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +static pthread_barrier_t b; + + +static void * +tf2 (void *arg) +{ + while (1) + sleep (100); + + /* NOTREACHED */ + return NULL; +} + + +static void * +tf (void *arg) +{ + pthread_t th; + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_create (&th, NULL, tf2, NULL); + if (e != 0) + { + printf ("create failed: %s\n", strerror (e)); + exit (1); + } + + /* Terminate only this thread. */ + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + int e = pthread_create (&th, NULL, tf, NULL); + if (e != 0) + { + printf ("create failed: %s\n", strerror (e)); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + /* Terminate only this thread. */ + pthread_exit (NULL); + + /* NOTREACHED */ + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-flock1.c b/test/nptl/tst-flock1.c new file mode 100644 index 000000000..ed2472d3a --- /dev/null +++ b/test/nptl/tst-flock1.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/file.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +static int fd; + + +static void * +tf (void *arg) +{ + if (flock (fd, LOCK_SH | LOCK_NB) != 0) + { + puts ("second flock failed"); + exit (1); + } + + pthread_mutex_unlock (&lock); + + return NULL; +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-flock1-XXXXXX"; + + fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + unlink (tmp); + + write (fd, "foobar xyzzy", 12); + + if (flock (fd, LOCK_EX | LOCK_NB) != 0) + { + puts ("first flock failed"); + exit (1); + } + + pthread_mutex_lock (&lock); + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + pthread_mutex_lock (&lock); + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + + close (fd); + + return result != NULL; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-flock2.c b/test/nptl/tst-flock2.c new file mode 100644 index 000000000..8ef3206cc --- /dev/null +++ b/test/nptl/tst-flock2.c @@ -0,0 +1,260 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/file.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER; +static int fd; + + +static void * +tf (void *arg) +{ + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 10 + }; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("fourth fcntl failed"); + exit (1); + } + + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock2); + + return NULL; +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-flock2-XXXXXX"; + + fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + return 1; + } + + unlink (tmp); + + int i; + for (i = 0; i < 20; ++i) + write (fd, "foobar xyzzy", 12); + + pthread_barrier_t *b; + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + { + puts ("mmap failed"); + return 1; + } + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + return 1; + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + struct flock fl = + { + .l_type = F_WRLCK, + .l_start = 0, + .l_whence = SEEK_SET, + .l_len = 10 + }; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("first fcntl failed"); + return 1; + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + if (pid == 0) + { + /* Make sure the child does not stay around indefinitely. */ + alarm (10); + + /* Try to get the lock. */ + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0) + { + puts ("child: second flock succeeded"); + return 1; + } + } + + pthread_barrier_wait (b); + + if (pid != 0) + { + fl.l_type = F_UNLCK; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("third fcntl failed"); + return 1; + } + } + + pthread_barrier_wait (b); + + pthread_t th; + if (pid == 0) + { + if (pthread_mutex_lock (&lock) != 0) + { + puts ("1st locking of lock failed"); + return 1; + } + + if (pthread_mutex_lock (&lock2) != 0) + { + puts ("1st locking of lock2 failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("2nd locking of lock failed"); + return 1; + } + + puts ("child locked file"); + } + + pthread_barrier_wait (b); + + if (pid != 0) + { + fl.l_type = F_WRLCK; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0) + { + puts ("fifth fcntl succeeded"); + return 1; + } + + puts ("file locked by child"); + } + + pthread_barrier_wait (b); + + if (pid == 0) + { + if (pthread_mutex_unlock (&lock2) != 0) + { + puts ("unlock of lock2 failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + puts ("child's thread terminated"); + } + + pthread_barrier_wait (b); + + if (pid != 0) + { + fl.l_type = F_WRLCK; + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLK, &fl)) == 0) + { + puts ("fifth fcntl succeeded"); + return 1; + } + + puts ("file still locked"); + } + + pthread_barrier_wait (b); + + if (pid == 0) + { + _exit (0); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + puts ("child terminated"); + + if (TEMP_FAILURE_RETRY (fcntl (fd, F_SETLKW, &fl)) != 0) + { + puts ("sixth fcntl failed"); + return 1; + } + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-fork1.c b/test/nptl/tst-fork1.c new file mode 100644 index 000000000..33c4ed84f --- /dev/null +++ b/test/nptl/tst-fork1.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Roland McGrath <roland@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> + +static void * +thread_function (void * arg) +{ + int i = (intptr_t) arg; + int status; + pid_t pid; + pid_t pid2; + + pid = fork (); + switch (pid) + { + case 0: + printf ("%ld for %d\n", (long int) getpid (), i); + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 * i }; + nanosleep (&ts, NULL); + _exit (i); + break; + case -1: + printf ("fork: %m\n"); + return (void *) 1l; + break; + } + + pid2 = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)); + if (pid2 != pid) + { + printf ("waitpid returned %ld, expected %ld\n", + (long int) pid2, (long int) pid); + return (void *) 1l; + } + + printf ("%ld with %d, expected %d\n", + (long int) pid, WEXITSTATUS (status), i); + + return WEXITSTATUS (status) == i ? NULL : (void *) 1l; +} + +#define N 5 +static const int t[N] = { 7, 6, 5, 4, 3 }; + +int +main (void) +{ + pthread_t th[N]; + int i; + int result = 0; + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], NULL, thread_function, + (void *) (intptr_t) t[i]) != 0) + { + printf ("creation of thread %d failed\n", i); + exit (1); + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + void *v; + if (pthread_join (th[i], &v) != 0) + { + printf ("join of thread %d failed\n", i); + result = 1; + } + else if (v != NULL) + { + printf ("join %d successful, but child failed\n", i); + result = 1; + } + else + printf ("join %d successful\n", i); + } + + return result; +} diff --git a/test/nptl/tst-fork2.c b/test/nptl/tst-fork2.c new file mode 100644 index 000000000..07d6c2266 --- /dev/null +++ b/test/nptl/tst-fork2.c @@ -0,0 +1,90 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Roland McGrath <roland@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static pid_t initial_pid; + + +static void * +tf (void *arg) +{ + if (getppid () != initial_pid) + { + printf ("getppid in thread returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + return (void *) -1; + } + + return NULL; +} + + +int +main (void) +{ + initial_pid = getpid (); + + pid_t child = fork (); + if (child == 0) + { + if (getppid () != initial_pid) + { + printf ("first getppid returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + + exit (result == NULL ? 0 : 1); + } + else if (child == -1) + { + puts ("initial fork failed"); + return 1; + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child) + { + printf ("waitpid failed: %m\n"); + return 1; + } + + return status; +} diff --git a/test/nptl/tst-fork3.c b/test/nptl/tst-fork3.c new file mode 100644 index 000000000..bc73853a5 --- /dev/null +++ b/test/nptl/tst-fork3.c @@ -0,0 +1,107 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Roland McGrath <roland@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + + +static pid_t initial_pid; + + +static void * +tf2 (void *arg) +{ + if (getppid () != initial_pid) + { + printf ("getppid in thread returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + return (void *) -1; + } + + return NULL; +} + + +static void * +tf1 (void *arg) +{ + pid_t child = fork (); + if (child == 0) + { + if (getppid () != initial_pid) + { + printf ("first getppid returned %ld, expected %ld\n", + (long int) getppid (), (long int) initial_pid); + exit (1); + } + + pthread_t th2; + if (pthread_create (&th2, NULL, tf2, NULL) != 0) + { + puts ("child: pthread_create failed"); + exit (1); + } + + void *result; + if (pthread_join (th2, &result) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + + exit (result == NULL ? 0 : 1); + } + else if (child == -1) + { + puts ("initial fork failed"); + exit (1); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child) + { + printf ("waitpid failed: %m\n"); + exit (1); + } + + exit (status); +} + + +int +main (void) +{ + initial_pid = getpid (); + + pthread_t th1; + if (pthread_create (&th1, NULL, tf1, NULL) != 0) + { + puts ("parent: pthread_create failed"); + exit (1); + } + + /* This call should never return. */ + pthread_join (th1, NULL); + + return 1; +} diff --git a/test/nptl/tst-fork4.c b/test/nptl/tst-fork4.c new file mode 100644 index 000000000..cca19f406 --- /dev/null +++ b/test/nptl/tst-fork4.c @@ -0,0 +1,65 @@ +/* Test of fork updating child universe's pthread structures. + Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <string.h> + + +static int +do_test (void) +{ + pthread_t me = pthread_self (); + + pid_t pid = fork (); + + if (pid < 0) + { + printf ("fork: %m\n"); + return 1; + } + + if (pid == 0) + { + int err = pthread_kill (me, SIGTERM); + printf ("pthread_kill returned: %s\n", strerror (err)); + return 3; + } + + int status; + errno = 0; + if (wait (&status) != pid) + printf ("wait failed: %m\n"); + else if (WIFSIGNALED (status) && WTERMSIG (status) == SIGTERM) + { + printf ("child correctly died with SIGTERM\n"); + return 0; + } + else + printf ("child died with bad status %#x\n", status); + + return 1; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-initializers1.c b/test/nptl/tst-initializers1.c new file mode 100644 index 000000000..ccd27286e --- /dev/null +++ b/test/nptl/tst-initializers1.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2005 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <pthread.h> + +pthread_mutex_t mtx_normal = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t mtx_recursive = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +pthread_mutex_t mtx_errorchk = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; +pthread_mutex_t mtx_adaptive = PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP; +pthread_rwlock_t rwl_normal = PTHREAD_RWLOCK_INITIALIZER; +pthread_rwlock_t rwl_writer + = PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +int +main (void) +{ + if (mtx_normal.__data.__kind != PTHREAD_MUTEX_TIMED_NP) + return 1; + if (mtx_recursive.__data.__kind != PTHREAD_MUTEX_RECURSIVE_NP) + return 1; + if (mtx_errorchk.__data.__kind != PTHREAD_MUTEX_ERRORCHECK_NP) + return 1; + if (mtx_adaptive.__data.__kind != PTHREAD_MUTEX_ADAPTIVE_NP) + return 1; + if (rwl_normal.__data.__flags != PTHREAD_RWLOCK_PREFER_READER_NP) + return 1; + if (rwl_writer.__data.__flags + != PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP) + return 1; + return 0; +} diff --git a/test/nptl/tst-join1.c b/test/nptl/tst-join1.c new file mode 100644 index 000000000..95a78ba0b --- /dev/null +++ b/test/nptl/tst-join1.c @@ -0,0 +1,83 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + pthread_t mh = (pthread_t) arg; + void *result; + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("unlock failed"); + exit (1); + } + + if (pthread_join (mh, &result) != 0) + { + puts ("join failed"); + exit (1); + } + + if (result != (void *) 42l) + { + printf ("result wrong: expected %p, got %p\n", (void *) 42, result); + exit (1); + } + + exit (0); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("1st lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("2nd lock failed"); + exit (1); + } + + pthread_exit ((void *) 42); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join2.c b/test/nptl/tst-join2.c new file mode 100644 index 000000000..2cfab8b0e --- /dev/null +++ b/test/nptl/tst-join2.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&lock) != 0) + { + puts ("child: mutex_lock failed"); + return NULL; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("mutex_create failed"); + exit (1); + } + + void *status; + int val = pthread_tryjoin_np (th, &status); + if (val == 0) + { + puts ("1st tryjoin succeeded"); + exit (1); + } + else if (val != EBUSY) + { + puts ("1st tryjoin didn't return EBUSY"); + exit (1); + } + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + while ((val = pthread_tryjoin_np (th, &status)) != 0) + { + if (val != EBUSY) + { + printf ("tryjoin returned %s (%d), expected only 0 or EBUSY\n", + strerror (val), val); + exit (1); + } + + /* Delay minimally. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + } + + if (status != (void *) 42l) + { + printf ("return value %p, expected %p\n", status, (void *) 42l); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join3.c b/test/nptl/tst-join3.c new file mode 100644 index 000000000..df1135fb5 --- /dev/null +++ b/test/nptl/tst-join3.c @@ -0,0 +1,123 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&lock) != 0) + { + puts ("child: mutex_lock failed"); + return NULL; + } + + return (void *) 42l; +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("mutex_create failed"); + exit (1); + } + + void *status; + struct timespec ts; + struct timeval tv; + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 200000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + int val = pthread_timedjoin_np (th, &status, &ts); + if (val == 0) + { + puts ("1st timedjoin succeeded"); + exit (1); + } + else if (val != ETIMEDOUT) + { + puts ("1st timedjoin didn't return ETIMEDOUT"); + exit (1); + } + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + while (1) + { + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 200000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + val = pthread_timedjoin_np (th, &status, &ts); + if (val == 0) + break; + + if (val != ETIMEDOUT) + { + printf ("timedjoin returned %s (%d), expected only 0 or ETIMEDOUT\n", + strerror (val), val); + exit (1); + } + } + + if (status != (void *) 42l) + { + printf ("return value %p, expected %p\n", status, (void *) 42l); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join4.c b/test/nptl/tst-join4.c new file mode 100644 index 000000000..b13a51011 --- /dev/null +++ b/test/nptl/tst-join4.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t bar; + + +static void * +tf (void *arg) +{ + if (pthread_barrier_wait (&bar) != 0) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + + return (void *) 1l; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bar, NULL, 3) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + pthread_t th[2]; + + if (pthread_create (&th[0], &a, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED) != 0) + { + puts ("attr_setdetachstate failed"); + exit (1); + } + + if (pthread_create (&th[1], &a, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + if (pthread_detach (th[0]) != 0) + { + puts ("could not detach 1st thread"); + exit (1); + } + + int err = pthread_detach (th[0]); + if (err == 0) + { + puts ("second detach of 1st thread succeeded"); + exit (1); + } + if (err != EINVAL) + { + printf ("second detach of 1st thread returned %d, not EINVAL\n", err); + exit (1); + } + + err = pthread_detach (th[1]); + if (err == 0) + { + puts ("detach of 2nd thread succeeded"); + exit (1); + } + if (err != EINVAL) + { + printf ("detach of 2nd thread returned %d, not EINVAL\n", err); + exit (1); + } + + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-join5.c b/test/nptl/tst-join5.c new file mode 100644 index 000000000..b08af6e43 --- /dev/null +++ b/test/nptl/tst-join5.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static void * +tf1 (void *arg) +{ + pthread_join ((pthread_t) arg, NULL); + + puts ("1st join returned"); + + return (void *) 1l; +} + + +static void * +tf2 (void *arg) +{ + int a; + a = pthread_join ((pthread_t) arg, NULL); + + puts ("2nd join returned"); + printf("a = %i\n", a); + + return (void *) 1l; +} + + +static int +do_test (void) +{ + pthread_t th; + + int err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("1st circular join succeeded"); + exit (1); + } + if (err != EDEADLK) + { + printf ("1st circular join %d, not EDEADLK\n", err); + exit (1); + } + + if (pthread_create (&th, NULL, tf1, (void *) pthread_self ()) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel 1st thread"); + exit (1); + } + + void *r; + err = pthread_join (th, &r); + if (err != 0) + { + printf ("cannot join 1st thread: %d\n", err); + exit (1); + } + if (r != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + exit (1); + } + + err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("2nd circular join succeeded"); + exit (1); + } + if (err != EDEADLK) + { + printf ("2nd circular join %d, not EDEADLK\n", err); + exit (1); + } + + if (pthread_create (&th, NULL, tf2, (void *) pthread_self ()) != 0) + { + puts ("2nd create failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel 2nd thread"); + exit (1); + } + + if (pthread_join (th, &r) != 0) + { + puts ("cannot join 2nd thread"); + exit (1); + } + if (r != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + exit (1); + } + + err = pthread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("2nd circular join succeeded"); + exit (1); + } + if (err != EDEADLK) + { + printf ("2nd circular join %d, not EDEADLK\n", err); + exit (1); + } + + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key1.c b/test/nptl/tst-key1.c new file mode 100644 index 000000000..dfbe58417 --- /dev/null +++ b/test/nptl/tst-key1.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +int +do_test (void) +{ + int max; +#ifdef PTHREAD_KEYS_MAX + max = PTHREAD_KEYS_MAX; +#else + max = _POSIX_THREAD_KEYS_MAX; +#endif + pthread_key_t *keys = alloca (max * sizeof (pthread_key_t)); + + int i; + for (i = 0; i < max; ++i) + if (pthread_key_create (&keys[i], NULL) != 0) + { + write (2, "key_create failed\n", 18); + _exit (1); + } + else + { + printf ("created key %d\n", i); + + if (pthread_setspecific (keys[i], (const void *) (i + 100l)) != 0) + { + write (2, "setspecific failed\n", 19); + _exit (1); + } + } + + for (i = 0; i < max; ++i) + { + if (pthread_getspecific (keys[i]) != (void *) (i + 100l)) + { + write (2, "getspecific failed\n", 19); + _exit (1); + } + + if (pthread_key_delete (keys[i]) != 0) + { + write (2, "key_delete failed\n", 18); + _exit (1); + } + } + + /* Now it must be once again possible to allocate keys. */ + if (pthread_key_create (&keys[0], NULL) != 0) + { + write (2, "2nd key_create failed\n", 22); + _exit (1); + } + + if (pthread_key_delete (keys[0]) != 0) + { + write (2, "2nd key_delete failed\n", 22); + _exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key2.c b/test/nptl/tst-key2.c new file mode 100644 index 000000000..c5493322c --- /dev/null +++ b/test/nptl/tst-key2.c @@ -0,0 +1,115 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + +#define N 2 + + +static int cnt0; +static void +f0 (void *p) +{ + ++cnt0; +} + + +static int cnt1; +static void +f1 (void *p) +{ + ++cnt1; +} + + +static void (*fcts[N]) (void *) = +{ + f0, + f1 +}; + + +static void * +tf (void *arg) +{ + pthread_key_t *key = (pthread_key_t *) arg; + + if (pthread_setspecific (*key, (void *) -1l) != 0) + { + write (2, "setspecific failed\n", 19); + _exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_key_t keys[N]; + + int i; + for (i = 0; i < N; ++i) + if (pthread_key_create (&keys[i], fcts[i]) != 0) + { + write (2, "key_create failed\n", 18); + _exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &keys[1]) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + write (2, "join failed\n", 12); + _exit (1); + } + + if (cnt0 != 0) + { + write (2, "cnt0 != 0\n", 10); + _exit (1); + } + + if (cnt1 != 1) + { + write (2, "cnt1 != 1\n", 10); + _exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_key_delete (keys[i]) != 0) + { + write (2, "key_delete failed\n", 18); + _exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key3.c b/test/nptl/tst-key3.c new file mode 100644 index 000000000..73cb7417a --- /dev/null +++ b/test/nptl/tst-key3.c @@ -0,0 +1,156 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + +#define N 2 + + +static int cnt0; +static void +f0 (void *p) +{ + ++cnt0; +} + + +static int cnt1; +static void +f1 (void *p) +{ + ++cnt1; +} + + +static void (*fcts[N]) (void *) = +{ + f0, + f1 +}; + + +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + pthread_key_t *key = (pthread_key_t *) arg; + + if (pthread_setspecific (*key, (void *) -1l) != 0) + { + write (2, "setspecific failed\n", 19); + _exit (1); + } + + pthread_barrier_wait (&b); + + const struct timespec t = { .tv_sec = 1000, .tv_nsec = 0 }; + while (1) + nanosleep (&t, NULL); + + /* NOTREACHED */ + return NULL; +} + + +int +do_test (void) +{ + pthread_key_t keys[N]; + + int i; + for (i = 0; i < N; ++i) + if (pthread_key_create (&keys[i], fcts[i]) != 0) + { + write (2, "key_create failed\n", 18); + _exit (1); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + write (2, "barrier_init failed\n", 20); + _exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &keys[1]) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + pthread_barrier_wait (&b); + + if (pthread_cancel (th) != 0) + { + write (2, "cancel failed\n", 14); + _exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + write (2, "join failed\n", 12); + _exit (1); + } + + if (status != PTHREAD_CANCELED) + { + write (2, "thread not canceled\n", 20); + _exit (1); + } + + /* Note that the TSD destructors not necessarily have to have + finished by the time pthread_join returns. At least according to + POSIX. We implement the stronger requirement that they indeed + have run and therefore these tests succeed. */ + if (cnt0 != 0) + { + write (2, "cnt0 != 0\n", 10); + _exit (1); + } + + if (cnt1 != 1) + { + write (2, "cnt1 != 1\n", 10); + _exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_key_delete (keys[i]) != 0) + { + write (2, "key_delete failed\n", 18); + _exit (1); + } + + if (pthread_barrier_destroy (&b) != 0) + { + write (2, "barrier_destroy failed\n", 23); + _exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-key4.c b/test/nptl/tst-key4.c new file mode 100644 index 000000000..0a5b448e5 --- /dev/null +++ b/test/nptl/tst-key4.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +#ifdef PTHREAD_KEYS_MAX +const int max = PTHREAD_KEYS_MAX; +#else +const int max = _POSIX_THREAD_KEYS_MAX; +#endif +static pthread_key_t *keys; + + +static void * +tf1 (void *arg) +{ + int i; + for (i = 0; i < max; ++i) + if (pthread_setspecific (keys[i], (void *) (long int) (i + 1)) != 0) + { + puts ("setspecific failed"); + exit (1); + } + + return NULL; +} + + +static void * +tf2 (void *arg) +{ + int i; + for (i = 0; i < max; ++i) + if (pthread_getspecific (keys[i]) != NULL) + { + printf ("getspecific for key %d not NULL\n", i); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + keys = alloca (max * sizeof (pthread_key_t)); + + int i; + for (i = 0; i < max; ++i) + if (pthread_key_create (&keys[i], NULL) != 0) + { + puts ("key_create failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < 10; ++i) + { + int j; +#define N 2 + pthread_t th[N]; + for (j = 0; j < N; ++j) + if (pthread_create (&th[j], NULL, tf1, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + for (j = 0; j < N; ++j) + if (pthread_join (th[j], NULL) != 0) + { + puts ("1st join failed"); + exit (1); + } + + for (j = 0; j < N; ++j) + if (pthread_create (&th[j], NULL, tf2, NULL) != 0) + { + puts ("2nd create failed"); + exit (1); + } + + for (j = 0; j < N; ++j) + if (pthread_join (th[j], NULL) != 0) + { + puts ("2nd join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill1.c b/test/nptl/tst-kill1.c new file mode 100644 index 000000000..9eaf29be7 --- /dev/null +++ b/test/nptl/tst-kill1.c @@ -0,0 +1,100 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; + +static void * +tf (void *a) +{ + if (pthread_mutex_lock (&m) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + /* This call should never return. */ + pthread_cond_wait (&c, &m); + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Send the thread a signal which it doesn't catch and which will + cause the process to terminate. */ + if (pthread_kill (th, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + /* This call should never return. */ + pthread_join (th, NULL); + + return 0; +} + + +#define EXPECTED_SIGNAL SIGUSR1 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill2.c b/test/nptl/tst-kill2.c new file mode 100644 index 000000000..1e3dc4104 --- /dev/null +++ b/test/nptl/tst-kill2.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> + + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; + +static void * +tf (void *a) +{ + /* Block SIGUSR1. */ + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("child: sigmask failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + /* Compute timeout. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + /* Timeout: 1sec. */ + ts.tv_sec += 1; + + /* This call should never return. */ + if (pthread_cond_timedwait (&c, &m, &ts) != ETIMEDOUT) + { + puts ("cond_timedwait didn't time out"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Send the thread a signal which it has blocked. */ + if (pthread_kill (th, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != NULL) + { + puts ("return value wrong"); + exit (1); + } + + return 0; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill3.c b/test/nptl/tst-kill3.c new file mode 100644 index 000000000..9ea8d553b --- /dev/null +++ b/test/nptl/tst-kill3.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t b; + + +static void +handler (int sig) +{ + write (1, "handler called\n", 15); + _exit (1); +} + + +static void * +tf (void *a) +{ + /* Block SIGUSR1. */ + sigset_t ss; + + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("child: sigmask failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + /* Compute timeout. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + /* Timeout: 1sec. */ + ts.tv_sec += 1; + + /* This call should never return. */ + if (pthread_cond_timedwait (&c, &m, &ts) != ETIMEDOUT) + { + puts ("cond_timedwait didn't time out"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = handler; + if (sigaction (SIGUSR1, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Send the thread a signal which it has blocked. */ + if (pthread_kill (th, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != NULL) + { + puts ("return value wrong"); + exit (1); + } + + return 0; +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill4.c b/test/nptl/tst-kill4.c new file mode 100644 index 000000000..4e7ff5eaf --- /dev/null +++ b/test/nptl/tst-kill4.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void * +tf (void *a) +{ + return NULL; +} + + +int +do_test (void) +{ + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + /* The following only works because we assume here something about + the implementation. Namely, that the memory allocated for the + thread descriptor is not going away, that the the TID field is + cleared and therefore the signal is sent to process 0, and that + we can savely assume there is no other process with this ID at + that time. */ + int e = pthread_kill (th, 0); + if (e == 0) + { + puts ("pthread_kill succeeded"); + exit (1); + } + if (e != ESRCH) + { + puts ("pthread_kill didn't return ESRCH"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill5.c b/test/nptl/tst-kill5.c new file mode 100644 index 000000000..12560943c --- /dev/null +++ b/test/nptl/tst-kill5.c @@ -0,0 +1,49 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + + +int +do_test (void) +{ + /* XXX This test might require architecture and system specific changes. + There is no guarantee that this signal number is invalid. */ + int e = pthread_kill (pthread_self (), SIGRTMAX + 10); + if (e == 0) + { + puts ("kill didn't failed"); + exit (1); + } + if (e != EINVAL) + { + puts ("error not EINVAL"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-kill6.c b/test/nptl/tst-kill6.c new file mode 100644 index 000000000..26e82d98f --- /dev/null +++ b/test/nptl/tst-kill6.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_t receiver; +static sem_t sem; +static pthread_barrier_t b; + +static void +handler (int sig) +{ + if (sig != SIGUSR1) + { + write (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + + if (pthread_self () != receiver) + { + write (STDOUT_FILENO, "not the intended receiver\n", 26); + _exit (1); + } + + if (sem_post (&sem) != 0) + { + write (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } +} + + +static void * +tf (void *a) +{ + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + return NULL; +} + + +int +do_test (void) +{ + struct sigaction sa; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = handler; + if (sigaction (SIGUSR1, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + +#define N 20 + + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + pthread_t th[N]; + int i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &a, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + if (sem_init (&sem, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + for (i = 0; i < N * 10; ++i) + { + receiver = th[i % N]; + + if (pthread_kill (receiver, SIGUSR1) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0) + { + puts ("sem_wait failed"); + exit (1); + } + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue.h b/test/nptl/tst-mqueue.h new file mode 100644 index 000000000..8e73be51c --- /dev/null +++ b/test/nptl/tst-mqueue.h @@ -0,0 +1,84 @@ +/* Common code for message queue passing tests. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <mqueue.h> +#include <search.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/uio.h> +#include <unistd.h> + +static int temp_mq_fd; + +/* Add temporary files in list. */ +static void +__attribute__ ((unused)) +add_temp_mq (const char *name) +{ + struct iovec iov[2]; + iov[0].iov_base = (char *) name; + iov[0].iov_len = strlen (name); + iov[1].iov_base = (char *) "\n"; + iov[1].iov_len = 1; + if (writev (temp_mq_fd, iov, 2) != iov[0].iov_len + 1) + printf ("Could not record temp mq filename %s\n", name); +} + +/* Delete all temporary message queues. */ +static void +do_cleanup (void) +{ + if (lseek (temp_mq_fd, 0, SEEK_SET) != 0) + return; + + FILE *f = fdopen (temp_mq_fd, "r"); + if (f == NULL) + return; + + char *line = NULL; + size_t n = 0; + ssize_t rets; + while ((rets = getline (&line, &n, f)) > 0) + { + if (line[rets - 1] != '\n') + continue; + + line[rets - 1] = '\0'; + mq_unlink (line); + } + fclose (f); +} + +static void +do_prepare (void) +{ + char name [] = "/tmp/tst-mqueueN.XXXXXX"; + temp_mq_fd = mkstemp (name); + if (temp_mq_fd == -1) + { + printf ("Could not create temporary file %s: %m\n", name); + exit (1); + } + unlink (name); +} + +#define PREPARE(argc, argv) do_prepare () +#define CLEANUP_HANDLER do_cleanup () diff --git a/test/nptl/tst-mqueue1.c b/test/nptl/tst-mqueue1.c new file mode 100644 index 000000000..70e42377b --- /dev/null +++ b/test/nptl/tst-mqueue1.c @@ -0,0 +1,417 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static int +intcmp (const void *a, const void *b) +{ + if (*(unsigned char *)a < *(unsigned char *)b) + return 1; + if (*(unsigned char *)a > *(unsigned char *)b) + return -1; + return 0; +} + +static int +check_attrs (struct mq_attr *attr, int nonblock, long cnt) +{ + int result = 0; + + if (attr->mq_maxmsg != 10 || attr->mq_msgsize != 1) + { + printf ("attributes don't match those passed to mq_open\n" + "mq_maxmsg %ld, mq_msgsize %ld\n", + attr->mq_maxmsg, attr->mq_msgsize); + result = 1; + } + + if ((attr->mq_flags & O_NONBLOCK) != nonblock) + { + printf ("mq_flags %lx != %x\n", (attr->mq_flags & O_NONBLOCK), nonblock); + result = 1; + } + + if (attr->mq_curmsgs != cnt) + { + printf ("mq_curmsgs %ld != %ld\n", attr->mq_curmsgs, cnt); + result = 1; + } + + return result; +} + +static int +do_one_test (mqd_t q, const char *name, int nonblock) +{ + int result = 0; + + char v [] + = { 0x32, 0x62, 0x22, 0x31, 0x11, 0x73, 0x61, 0x21, 0x72, 0x71, 0x81 }; + + struct mq_attr attr; + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + if (mq_receive (q, &v[0], 1, NULL) != -1) + { + puts ("mq_receive on O_WRONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + --ts.tv_sec; + else + { + ts.tv_sec = time (NULL) - 1; + ts.tv_nsec = 0; + } + + int ret; + for (int i = 0; i < 10; ++i) + { + if (i & 1) + ret = mq_send (q, &v[i], 1, v[i] >> 4); + else + ret = mq_timedsend (q, &v[i], 1, v[i] >> 4, &ts); + + if (ret) + { + printf ("mq_%ssend failed: %m\n", (i & 1) ? "" : "timed"); + result = 1; + } + } + + ret = mq_timedsend (q, &v[10], 1, 8, &ts); + if (ret != -1) + { + puts ("mq_timedsend on full queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedsend on full queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_send (q, &v[10], 1, 8); + if (ret != -1) + { + puts ("mq_send on full non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_send on full non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 10); + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + result = 1; + } + else if (pid == 0) + { + result = 0; + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + q = mq_open (name, O_RDONLY | nonblock); + if (q == (mqd_t) -1) + { + printf ("mq_open in child failed: %m\n"); + exit (1); + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 10); + + char vr[11] = { }; + unsigned int prio; + ssize_t rets; + + if (mq_send (q, &v[0], 1, 1) != -1) + { + puts ("mq_send on O_RDONLY mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on O_WRONLY mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + for (int i = 0; i < 10; ++i) + { + if (i & 1) + rets = mq_receive (q, &vr[i], 1, &prio); + else + rets = mq_timedreceive (q, &vr[i], 1, &prio, &ts); + + if (rets != 1) + { + if (rets == -1) + printf ("mq_%sreceive failed: %m\n", (i & 1) ? "" : "timed"); + else + printf ("mq_%sreceive returned %zd != 1\n", + (i & 1) ? "" : "timed", rets); + result = 1; + } + else if (prio != (unsigned int) vr[i] >> 4) + { + printf ("unexpected priority %x for value %02x\n", prio, + vr[i]); + result = 1; + } + } + + qsort (v, 10, 1, intcmp); + if (memcmp (v, vr, 10) != 0) + { + puts ("messages not received in expected order"); + result = 1; + } + + rets = mq_timedreceive (q, &vr[10], 1, &prio, &ts); + if (rets != -1) + { + puts ("mq_timedreceive on empty queue did not fail"); + result = 1; + } + else if (errno != (nonblock ? EAGAIN : ETIMEDOUT)) + { + printf ("mq_timedreceive on empty queue did not fail with %s: %m\n", + nonblock ? "EAGAIN" : "ETIMEDOUT"); + result = 1; + } + + if (nonblock) + { + ret = mq_receive (q, &vr[10], 1, &prio); + if (ret != -1) + { + puts ("mq_receive on empty non-blocking queue did not fail"); + result = 1; + } + else if (errno != EAGAIN) + { + printf ("mq_receive on empty non-blocking queue did not fail" + "with EAGAIN: %m\n"); + result = 1; + } + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + if (mq_close (q) != 0) + { + printf ("mq_close in child failed: %m\n"); + result = 1; + } + + exit (result); + } + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed: %d\n", status); + result = 1; + } + + memset (&attr, 0xaa, sizeof (attr)); + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + result |= check_attrs (&attr, nonblock, 0); + + return result; +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue1-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue1-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + result |= do_one_test (q, name, 0); + + mqd_t q2 = mq_open (name, O_WRONLY | O_NONBLOCK); + if (q2 == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + q2 = q; + result = 1; + } + else + { + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + q = q2; + result |= do_one_test (q, name, O_NONBLOCK); + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + else + { + attr.mq_flags ^= O_NONBLOCK; + + struct mq_attr attr2; + memset (&attr2, 0x55, sizeof (attr2)); + if (mq_setattr (q, &attr, &attr2) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else if (attr.mq_flags != (attr2.mq_flags ^ O_NONBLOCK) + || attr.mq_maxmsg != attr2.mq_maxmsg + || attr.mq_msgsize != attr2.mq_msgsize + || attr.mq_curmsgs != 0 + || attr2.mq_curmsgs != 0) + { + puts ("mq_setattr returned unexpected values in *omqstat"); + result = 1; + } + else + { + result |= do_one_test (q, name, 0); + + if (mq_setattr (q, &attr2, NULL) != 0) + { + printf ("mq_setattr failed: %m\n"); + result = 1; + } + else + result |= do_one_test (q, name, O_NONBLOCK); + } + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_close (q) != -1) + { + puts ("second mq_close did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("second mq_close did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue2.c b/test/nptl/tst-mqueue2.c new file mode 100644 index 000000000..1948965c6 --- /dev/null +++ b/test/nptl/tst-mqueue2.c @@ -0,0 +1,477 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +static void +alrm_handler (int sig) +{ +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue2-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue2-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with O_EXCL unexpectedly succeeded"); + result = 1; + } + else if (errno != EEXIST) + { + printf ("mq_open did not fail with EEXIST: %m\n"); + result = 1; + } + + char name2[sizeof "/tst-mqueue2-2-" + sizeof (pid_t) * 3]; + snprintf (name2, sizeof (name2), "/tst-mqueue2-2-%u", getpid ()); + + attr.mq_maxmsg = -2; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_maxmsg unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_maxmsg did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + attr.mq_maxmsg = 2; + attr.mq_msgsize = -56; + q2 = mq_open (name2, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with invalid mq_msgsize unexpectedly succeeded"); + add_temp_mq (name2); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_open with invalid mq_msgsize did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + char buf[3]; + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ts.tv_sec += 10; + else + { + ts.tv_sec = time (NULL) + 10; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q, buf, 1, NULL, &ts) == 0) + { + puts ("mq_timedreceive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_timedreceive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -1; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = 1000000000; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedreceive with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + struct sigaction sa = { .sa_handler = alrm_handler, .sa_flags = 0 }; + sigemptyset (&sa.sa_mask); + sigaction (SIGALRM, &sa, NULL); + + struct itimerval it = { .it_value = { .tv_sec = 1 } }; + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_receive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_nsec = 0; + if (mq_timedreceive (q, buf, 2, NULL, &ts) == 0) + { + puts ("mq_timedreceive on empty queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedreceive on empty queue did not fail with EINTR: %m\n"); + result = 1; + } + + buf[0] = '6'; + buf[1] = '7'; + if (mq_send (q, buf, 2, 3) != 0 + || (buf[0] = '8', mq_send (q, buf, 1, 4) != 0)) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q, buf, 3, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 4 || memcmp (buf, "8 ", 3) != 0) + { + printf ("mq_receive prio %u (4) buf \"%c%c%c\" (\"8 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + rets = mq_receive (q, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "67 ", 3) != 0) + { + printf ("mq_receive buf \"%c%c%c\" != \"67 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + buf[0] = '2'; + buf[1] = '1'; + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + if ((mq_timedsend (q, buf, 2, 5, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 2, 5) != 0)) + || (buf[0] = '3', ts.tv_nsec = -ts.tv_nsec, + (mq_timedsend (q, buf, 1, 4, &ts) != 0 + && (errno != EINVAL || mq_send (q, buf, 1, 4) != 0)))) + { + printf ("mq_timedsend failed: %m\n"); + result = 1; + } + + buf[0] = '-'; + ts.tv_nsec = 1000000001; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with tv_nsec >= 1000000000 did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with tv_nsec >= 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + ts.tv_nsec = -2; + if (mq_timedsend (q, buf, 1, 6, &ts) == 0) + { + puts ("mq_timedsend with negative tv_nsec did not fail"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_timedsend with megatove tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + if (mq_send (q, buf, 2, 8) == 0) + { + puts ("mq_send on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_send on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + setitimer (ITIMER_REAL, &it, NULL); + + ts.tv_sec += 10; + ts.tv_nsec = 0; + if (mq_timedsend (q, buf, 2, 7, &ts) == 0) + { + puts ("mq_timedsend on full queue did not block"); + result = 1; + } + else if (errno != EINTR) + { + printf ("mq_timedsend on full queue did not fail with EINTR: %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + ts.tv_sec = time (NULL); + ts.tv_nsec = -1000000001; + rets = mq_timedreceive (q, buf, 2, &prio, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, &prio); + if (rets != 2) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 2\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "21 ", 3) != 0) + { + printf ("mq_timedreceive prio %u (5) buf \"%c%c%c\" (\"21 \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_receive (q, buf, 1, NULL) == 0) + { + puts ("mq_receive with too small msg_len did not fail"); + result = 1; + } + else if (errno != EMSGSIZE) + { + printf ("mq_receive with too small msg_len did not fail with " + "EMSGSIZE: %m\n"); + result = 1; + } + + ts.tv_nsec = -ts.tv_nsec; + rets = mq_timedreceive (q, buf, 2, NULL, &ts); + if (rets == -1 && errno == EINVAL) + rets = mq_receive (q, buf, 2, NULL); + if (rets != 1) + { + if (rets == -1) + printf ("mq_timedreceive failed: %m\n"); + else + printf ("mq_timedreceive returned %zd != 1\n", rets); + result = 1; + } + else if (memcmp (buf, "31 ", 3) != 0) + { + printf ("mq_timedreceive buf \"%c%c%c\" != \"31 \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_send (q, "", 0, 2) != 0) + { + printf ("mq_send with msg_len 0 failed: %m\n"); + result = 1; + } + + rets = mq_receive (q, buf, 2, &prio); + if (rets) + { + if (rets == -1) + printf ("mq_receive failed: %m\n"); + else + printf ("mq_receive returned %zd != 0\n", rets); + result = 1; + } + + long mq_prio_max = sysconf (_SC_MQ_PRIO_MAX); + if (mq_prio_max > 0 && (unsigned int) mq_prio_max == mq_prio_max) + { + if (mq_send (q, buf, 1, mq_prio_max) == 0) + { + puts ("mq_send with MQ_PRIO_MAX priority unpexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("mq_send with MQ_PRIO_MAX priority did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, mq_prio_max - 1) != 0) + { + printf ("mq_send with MQ_PRIO_MAX-1 priority failed: %m\n"); + result = 1; + } + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDWR); + if (q2 != (mqd_t) -1) + { + printf ("mq_open of unlinked %s without O_CREAT unexpectedly" + "succeeded\n", name); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_open of unlinked %s without O_CREAT did not fail with " + "ENOENT: %m\n", name); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close in parent failed: %m\n"); + result = 1; + } + + if (mq_receive (q, buf, 2, NULL) == 0) + { + puts ("mq_receive on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_receive on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_send (q, buf, 1, 2) == 0) + { + puts ("mq_send on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_send on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_getattr (q, &attr) == 0) + { + puts ("mq_getattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&attr, 0, sizeof (attr)); + if (mq_setattr (q, &attr, NULL) == 0) + { + puts ("mq_setattr on invalid mqd_t did not fail"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_setattr on invalid mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (mq_unlink ("/tst-mqueue2-which-should-never-exist") != -1) + { + puts ("mq_unlink of non-existant message queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ENOENT) + { + printf ("mq_unlink of non-existant message queue did not fail with " + "ENOENT: %m\n"); + result = 1; + } + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue3.c b/test/nptl/tst-mqueue3.c new file mode 100644 index 000000000..990e05728 --- /dev/null +++ b/test/nptl/tst-mqueue3.c @@ -0,0 +1,244 @@ +/* Test SIGEV_THREAD handling for POSIX message queues. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <mqueue.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +static pid_t pid; +static mqd_t m; +static const char message[] = "hello"; + +# define MAXMSG 10 +# define MSGSIZE 10 +# define UNIQUE 42 + + +static void +fct (union sigval s) +{ + /* Put the mq in non-blocking mode. */ + struct mq_attr attr; + if (mq_getattr (m, &attr) != 0) + { + printf ("%s: mq_getattr failed: %m\n", __FUNCTION__); + exit (1); + } + attr.mq_flags |= O_NONBLOCK; + if (mq_setattr (m, &attr, NULL) != 0) + { + printf ("%s: mq_setattr failed: %m\n", __FUNCTION__); + exit (1); + } + + /* Check the values. */ + if (attr.mq_maxmsg != MAXMSG) + { + printf ("%s: mq_maxmsg wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_maxmsg, MAXMSG); + exit (1); + } + if (attr.mq_msgsize != MAXMSG) + { + printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n", + __FUNCTION__, attr.mq_msgsize, MSGSIZE); + exit (1); + } + + /* Read the message. */ + char buf[attr.mq_msgsize]; + ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL)); + if (n != sizeof (message)) + { + printf ("%s: length of message wrong: is %zd, expected %zu\n", + __FUNCTION__, n, sizeof (message)); + exit (1); + } + if (memcmp (buf, message, sizeof (message)) != 0) + { + printf ("%s: message wrong: is \"%s\", expected \"%s\"\n", + __FUNCTION__, buf, message); + exit (1); + } + + exit (UNIQUE); +} + + +int +do_test (void) +{ + char tmpfname[] = "/tmp/tst-mqueue3-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b; + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + /* Name for the message queue. */ + char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)]; + snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld", + (long int) getpid ()); + + /* Create the message queue. */ + struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE }; + m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (m == -1) + { + if (errno == ENOSYS) + { + puts ("not implemented"); + return 0; + } + + puts ("mq_open failed"); + return 1; + } + + /* Unlink the message queue right away. */ + if (mq_unlink (mqname) != 0) + { + puts ("mq_unlink failed"); + return 1; + } + + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + if (pid == 0) + { + /* Request notification via thread. */ + struct sigevent ev; + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_value.sival_ptr = NULL; + ev.sigev_notify_attributes = NULL; + + /* Tell the kernel. */ + if (mq_notify (m,&ev) != 0) + { + puts ("mq_notify failed"); + exit (1); + } + + /* Tell the parent we are ready. */ + (void) pthread_barrier_wait (b); + + /* Make sure the process goes away eventually. */ + alarm (10); + + /* Do nothing forever. */ + while (1) + pause (); + } + + /* Wait for the child process to register to notification method. */ + (void) pthread_barrier_wait (b); + + /* Send the message. */ + if (mq_send (m, message, sizeof (message), 1) != 0) + { + kill (pid, SIGKILL); + puts ("mq_send failed"); + return 1; + } + + int r; + if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid) + { + kill (pid, SIGKILL); + puts ("waitpid failed"); + return 1; + } + + return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1; +} +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue4.c b/test/nptl/tst-mqueue4.c new file mode 100644 index 000000000..aa31706f8 --- /dev/null +++ b/test/nptl/tst-mqueue4.c @@ -0,0 +1,288 @@ +/* Test message queue passing. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue4-" + sizeof (pid_t) * 3 + NAME_MAX]; + char *p; + p = name + snprintf (name, sizeof (name), "/tst-mqueue4-%u", getpid ()); + struct mq_attr attr = { .mq_maxmsg = 2, .mq_msgsize = 2 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + *p = '.'; + memset (p + 1, 'x', NAME_MAX + 1 - (p - name)); + name[NAME_MAX + 1] = '\0'; + + mqd_t q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open with NAME_MAX long name compoment failed with: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + name[NAME_MAX + 1] = 'x'; + name[NAME_MAX + 2] = '\0'; + q2 = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + if (q2 != (mqd_t) -1) + { + puts ("mq_open with too long name component unexpectedly succeeded"); + mq_unlink (name); + mq_close (q2); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_open with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + if (mq_unlink (name) == 0) + { + puts ("mq_unlink with too long name component unexpectedly succeeded"); + result = 1; + } + else if (errno != ENAMETOOLONG) + { + printf ("mq_unlink with too long name component did not fail with " + "ENAMETOOLONG: %m\n"); + result = 1; + } + + *p = '\0'; + attr.mq_maxmsg = 1; + attr.mq_msgsize = 3; + q2 = mq_open (name, O_CREAT | O_RDWR, 0600, &attr); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_EXCL failed with %m\n"); + result = 1; + } + + char buf[3]; + strcpy (buf, "jk"); + if (mq_send (q, buf, 2, 4) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_send (q, buf + 1, 1, 5) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + } + + if (mq_getattr (q2, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 2) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + struct timespec ts; + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedsend (q2, buf, 1, 1, &ts) == 0) + { + puts ("mq_timedsend unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedsend did not fail with ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + q2 = mq_open (name, O_RDONLY, 0600); + if (q2 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + mqd_t q3 = mq_open (name, O_RDONLY, 0600); + if (q3 == (mqd_t) -1) + { + printf ("mq_open without O_CREAT failed with %m\n"); + result = 1; + } + + memset (buf, ' ', sizeof (buf)); + + unsigned int prio; + ssize_t rets = mq_receive (q2, buf, 2, &prio); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 1\n", rets); + result = 1; + } + else if (prio != 5 || memcmp (buf, "k ", 3) != 0) + { + printf ("mq_receive returned prio %u (2) buf \"%c%c%c\" (\"k \")\n", + prio, buf[0], buf[1], buf[2]); + result = 1; + } + + if (mq_getattr (q3, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + result = 1; + } + + if ((attr.mq_flags & O_NONBLOCK) + || attr.mq_maxmsg != 2 + || attr.mq_msgsize != 2 + || attr.mq_curmsgs != 1) + { + printf ("mq_getattr returned unexpected { .mq_flags = %ld,\n" + ".mq_maxmsg = %ld, .mq_msgsize = %ld, .mq_curmsgs = %ld }\n", + attr.mq_flags, attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs); + result = 1; + } + + rets = mq_receive (q3, buf, 2, NULL); + if (rets != 2) + { + if (rets == -1) + printf ("mq_receive failed with: %m\n"); + else + printf ("mq_receive returned %zd != 2\n", rets); + result = 1; + } + else if (memcmp (buf, "jk ", 3) != 0) + { + printf ("mq_receive returned buf \"%c%c%c\" != \"jk \"\n", + buf[0], buf[1], buf[2]); + result = 1; + } + + if (clock_gettime (CLOCK_REALTIME, &ts) == 0) + ++ts.tv_sec; + else + { + ts.tv_sec = time (NULL) + 1; + ts.tv_nsec = 0; + } + + if (mq_timedreceive (q2, buf, 2, NULL, &ts) != -1) + { + puts ("mq_timedreceive on empty queue unexpectedly succeeded"); + result = 1; + } + else if (errno != ETIMEDOUT) + { + printf ("mq_timedreceive on empty queue did not fail with " + "ETIMEDOUT: %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue5.c b/test/nptl/tst-mqueue5.c new file mode 100644 index 000000000..97571da8a --- /dev/null +++ b/test/nptl/tst-mqueue5.c @@ -0,0 +1,1014 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TIMEOUT 3 + +#if _POSIX_THREADS +# include <pthread.h> + +volatile int rtmin_cnt; +volatile pid_t rtmin_pid; +volatile uid_t rtmin_uid; +volatile int rtmin_code; +volatile union sigval rtmin_sigval; + +static void +rtmin_handler (int sig, siginfo_t *info, void *ctx) +{ + if (sig != SIGRTMIN) + abort (); + ++rtmin_cnt; + rtmin_pid = info->si_pid; + rtmin_uid = info->si_uid; + rtmin_code = info->si_code; + rtmin_sigval = info->si_value; +} + +#define mqsend(q) (mqsend) (q, __LINE__) +static int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +#define mqrecv(q) (mqrecv) (q, __LINE__) +static int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +struct thr_data +{ + const char *name; + pthread_barrier_t *b3; + mqd_t q; +}; + +static void * +thr (void *arg) +{ + pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3; + mqd_t q = ((struct thr_data *)arg)->q; + const char *name = ((struct thr_data *)arg)->name; + int result = 0; + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 0xdeadbeef) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (%d)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int, 0xdeadbeef); + result = 1; + } + + struct sigevent ev; + memset (&ev, 0x82, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + if (mq_notify (q, NULL) != 0) + { + printf ("second mq_notify in thread (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q4 = mq_open (name, O_RDONLY); + if (q4 == (mqd_t) -1) + { + printf ("mq_open in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q4, NULL) != 0) + { + printf ("mq_notify in thread (q4, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q4) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + mqd_t q5 = mq_open (name, O_WRONLY); + if (q5 == (mqd_t) -1) + { + printf ("mq_open O_WRONLY in thread failed with: %m\n"); + result = 1; + } + + if (mq_notify (q5, NULL) != 0) + { + printf ("mq_notify in thread (q5, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_close (q5) != 0) + { + printf ("mq_close in thread failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been received. */ + + return (void *) (long) result; +} + +static void +do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3, + mqd_t q) +{ + int result = 0; + + struct sigevent ev; + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which makes notification available. */ + + (void) pthread_barrier_wait (b2); + + rtmin_cnt = 0; + + if (mq_notify (q, &ev) != 0) + { + printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal in child caught too early"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify. */ + /* Parent calls mqsend (q), which makes notification available + and triggers a signal in the child. */ + /* Parent successfully calls mq_notify SIGEV_SIGNAL. */ + + (void) pthread_barrier_wait (b2); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal in child did not arrive"); + result = 1; + } + else if (rtmin_pid != getppid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_ptr != &ev) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_ptr %p (%p)\n", + rtmin_pid, getppid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_ptr, &ev); + result = 1; + } + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Parent verifies caught SIGRTMIN. */ + + mqd_t q2 = mq_open (name, O_RDWR); + if (q2 == (mqd_t) -1) + { + printf ("mq_open in child failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent mq_open's another mqd_t for the same queue (q3). */ + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q2, &ev) != 0) + { + printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q2) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent successfully calls mq_notify { SIGEV_NONE } on q3. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &b2; + if (mq_notify (q, &ev) == 0) + { + puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mq_close on q3, which makes the queue available again for + notification. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x13, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify in child (q, NULL) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + struct thr_data thr_data = { .name = name, .b3 = b3, .q = q }; + pthread_t th; + int ret = pthread_create (&th, NULL, thr, &thr_data); + if (ret) + { + errno = ret; + printf ("pthread_created failed with: %m\n"); + result = 1; + } + + /* Wait till thr calls mq_receive on the empty queue q and blocks on it. */ + sleep (1); + + memset (&ev, 0x5f, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 0xdeadbeef; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Parent calls mqsend (q), which should wake up mqrecv (q) + in the thread but no notification should be sent. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught while thr was blocked on mq_receive"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should trigger notification. */ + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been received. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + memset (&ev, 0x6a, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = do_child; + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL), which should unregister the above + notification. */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0x7b, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = thr; + if (mq_notify (q, &ev) != 0) + { + printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + memset (&ev, 0xe1, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 127; + if (mq_notify (q, &ev) != 0) + { + printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL), which should unregister the above + notification. */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + /* Parent calls mqsend (q), which should not trigger notification. */ + + (void) pthread_barrier_wait (b3); + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal caught while notification has been disabled"); + result = 1; + } + + void *thr_ret; + ret = pthread_join (th, &thr_ret); + if (ret) + { + errno = ret; + printf ("pthread_join failed: %m\n"); + result = 1; + } + else if (thr_ret) + result = 1; + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + exit (result); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX"; + int fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + size_t ps = sysconf (_SC_PAGESIZE); + char data[ps]; + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + pthread_barrier_t *b2; + b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + pthread_barrier_t *b3; + b3 = b2 + 1; + + pthread_barrierattr_t a; + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed, could not test"); + return 0; + } + + if (pthread_barrier_init (b2, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (b3, &a, 3) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + /* Implementation-defined behaviour, so don't fail, + just inform. */ + printf ("second mq_notify (q, NULL) failed with: %m\n"); + } + + struct sigaction sa = { .sa_sigaction = rtmin_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 26; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + ev.sigev_value.sival_ptr = &ev; + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 0) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqsend (q); + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != getpid () + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 26) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n", + rtmin_pid, getpid (), rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int); + result = 1; + } + + ev.sigev_value.sival_int = 75; + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqrecv (q); + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) != 0) + { + printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork () failed: %m\n"); + mq_unlink (name); + return 1; + } + + if (pid == 0) + do_child (name, b2, b3, q); + + /* Child unsuccessfully attempts to mq_notify. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify SIGEV_SIGNAL now. */ + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_int = 15; + if (mq_notify (q, &ev) == 0) + { + puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + result |= mqsend (q); + + if (mq_notify (q, &ev) != 0) + { + printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n"); + result = 1; + } + + if (rtmin_cnt != 1) + { + puts ("SIGRTMIN signal caught too early"); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child verifies caught SIGRTMIN signal. */ + /* Child calls mq_send (q) which triggers SIGRTMIN signal here. */ + + (void) pthread_barrier_wait (b2); + + /* Child mq_open's another mqd_t for the same queue (q2). */ + + if (rtmin_cnt != 2) + { + puts ("SIGRTMIN signal did not arrive"); + result = 1; + } + else if (rtmin_pid != pid + || rtmin_uid != getuid () + || rtmin_code != SI_MESGQ + || rtmin_sigval.sival_int != 15) + { + printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n", + rtmin_pid, pid, rtmin_uid, getuid (), + rtmin_code, SI_MESGQ, rtmin_sigval.sival_int); + result = 1; + } + + result |= mqrecv (q); + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2. */ + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0xbb, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child calls mq_close on q2, which makes the queue available again for + notification. */ + + mqd_t q3 = mq_open (name, O_RDWR); + if (q3 == (mqd_t) -1) + { + printf ("mq_open q3 in parent failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + memset (&ev, 0x12, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q3, &ev) != 0) + { + printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + if (mq_close (q3) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + (void) pthread_barrier_wait (b2); + + /* Child successfully calls mq_notify { SIGEV_NONE } on q. */ + /* Child successfully calls mq_notify NULL on q. */ + + (void) pthread_barrier_wait (b2); + + /* Child creates new thread. */ + /* Thread blocks on mqrecv (q). */ + /* Child sleeps for 1sec so that thread has time to reach that point. */ + /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q. */ + + (void) pthread_barrier_wait (b2); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + + (void) pthread_barrier_wait (b3); + + /* Thread verifies SIGRTMIN has been caught. */ + /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now + available for registration. */ + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread calls mq_notify (q, NULL). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_RDONLY mqd_t (q4). */ + /* Thread calls mq_notify (q4, NULL). */ + /* Thread calls mq_close (q4). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + /* Child calls mq_notify (q, { SIGEV_SIGNAL }). */ + + (void) pthread_barrier_wait (b3); + + /* Thread opens a new O_WRONLY mqd_t (q5). */ + /* Thread calls mq_notify (q5, NULL). */ + /* Thread calls mq_close (q5). */ + + (void) pthread_barrier_wait (b3); + + result |= mqsend (q); + result |= mqrecv (q); + + (void) pthread_barrier_wait (b3); + + /* Child verifies SIGRTMIN has not been sent. */ + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + kill (pid, SIGKILL); + result = 1; + } + else if (!WIFEXITED (status) || WEXITSTATUS (status)) + { + printf ("child failed with status %d\n", status); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue6.c b/test/nptl/tst-mqueue6.c new file mode 100644 index 000000000..5c9ee69e1 --- /dev/null +++ b/test/nptl/tst-mqueue6.c @@ -0,0 +1,305 @@ +/* Test mq_notify. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <limits.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#if _POSIX_THREADS +# include <pthread.h> + +# define mqsend(q) (mqsend) (q, __LINE__) +static int +(mqsend) (mqd_t q, int line) +{ + char c; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send on line %d failed with: %m\n", line); + return 1; + } + return 0; +} + +# define mqrecv(q) (mqrecv) (q, __LINE__) +static int +(mqrecv) (mqd_t q, int line) +{ + char c; + ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + if (rets != 1) + { + if (rets == -1) + printf ("mq_receive on line %d failed with: %m\n", line); + else + printf ("mq_receive on line %d returned %zd != 1\n", + line, rets); + return 1; + } + return 0; +} + +volatile int fct_cnt, fct_err; +size_t fct_guardsize; + +static void +fct (union sigval s) +{ + mqd_t q = *(mqd_t *) s.sival_ptr; + + pthread_attr_t nattr; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("pthread_getattr_np failed: %m\n"); + fct_err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &fct_guardsize); + if (ret) + { + errno = ret; + printf ("pthread_attr_getguardsize failed: %m\n"); + fct_err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + fct_err = 1; + } + } + + ++fct_cnt; + fct_err |= mqsend (q); +} + +# define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + + char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return result; + } + else + add_temp_mq (name); + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + fct_guardsize = 1; + + struct sigevent ev; + memset (&ev, 0xaa, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + size_t ps = sysconf (_SC_PAGESIZE); + if (pthread_attr_setguardsize (&nattr, 32 * ps)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 0) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 1) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 0) + { + printf ("fct_guardsize %zd != 0\n", fct_guardsize); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_ptr = &q; + if (mq_notify (q, &ev) != 0) + { + printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_setguardsize (&nattr, 0)) + { + puts ("pthread_attr_t setup failed"); + result = 1; + } + + if (mq_notify (q, &ev) == 0) + { + puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded"); + result = 1; + } + else if (errno != EBUSY) + { + printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (fct_cnt != 1) + { + printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + + result |= mqsend (q); + + result |= mqrecv (q); + result |= mqrecv (q); + + if (fct_cnt != 2) + { + printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__); + result = 1; + } + else if (fct_guardsize != 32 * ps) + { + printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps); + result = 1; + } + + if (mq_notify (q, &ev) != 0) + { + printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n"); + result = 1; + } + + if (mq_notify (q, NULL) != 0) + { + printf ("mq_notify (q, NULL) failed with: %m\n"); + result = 1; + } + + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("pthread_attr_destroy failed"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = fct; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_int = 0; + if (mq_notify (q, &ev) == 0) + { + puts ("mq_notify on closed mqd_t unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n"); + result = 1; + } + + if (fct_err) + result = 1; + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue7.c b/test/nptl/tst-mqueue7.c new file mode 100644 index 000000000..34222f834 --- /dev/null +++ b/test/nptl/tst-mqueue7.c @@ -0,0 +1,109 @@ +/* Test all open message queues descriptors are closed during exec*. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/wait.h> +#include <time.h> +#include <unistd.h> + +#define OPT_AFTEREXEC 20000 + +static mqd_t after_exec = (mqd_t) -1; + +#define CMDLINE_OPTIONS \ + { "after-exec", required_argument, NULL, OPT_AFTEREXEC }, + +#define CMDLINE_PROCESS \ + case OPT_AFTEREXEC: \ + after_exec = (mqd_t) strtoul (optarg, NULL, 0); \ + break; + +static int +do_after_exec (void) +{ + int result = 0; + + struct mq_attr attr; + if (mq_getattr (after_exec, &attr) == 0) + { + puts ("mq_getattr after exec unexpectedly succeeded"); + result = 1; + } + else if (errno != EBADF) + { + printf ("mq_getattr after exec did not fail with EBADF: %m\n"); + result = 1; + } + + return result; +} + +static int +do_test (int argc, char **argv) +{ + if (after_exec != (mqd_t) -1) + return do_after_exec (); + + char name[sizeof "/tst-mqueue7-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue7-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 10, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_WRONLY, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + else if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + return 1; + } + + if (mq_getattr (q, &attr) != 0) + { + printf ("mq_getattr failed: %m\n"); + return 1; + } + + char after_exec_arg[sizeof "--after-exec=0x" + sizeof (long) * 3]; + snprintf (after_exec_arg, sizeof (after_exec_arg), + "--after-exec=0x%lx", (long) q); + + const char *newargv[argc + 2]; + for (int i = 1; i < argc; ++i) + newargv[i - 1] = argv[i]; + newargv[argc - 1] = "--direct"; + newargv[argc] = after_exec_arg; + newargv[argc + 1] = NULL; + + /* Verify that exec* has the effect of mq_close (q). */ + execv (newargv[0], (char * const *) newargv); + printf ("execv failed: %m\n"); + return 1; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue8.c b/test/nptl/tst-mqueue8.c new file mode 100644 index 000000000..7e902aa60 --- /dev/null +++ b/test/nptl/tst-mqueue8.c @@ -0,0 +1,266 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + +static pthread_barrier_t b; + +/* Cleanup handling test. */ +static int cl_called; + +static void +cl (void *arg) +{ + ++cl_called; +} + +#define TF_MQ_RECEIVE 0L +#define TF_MQ_TIMEDRECEIVE 1L +#define TF_MQ_SEND 2L +#define TF_MQ_TIMEDSEND 3L + +static const char *names[] + = { "mq_receive", "mq_timedreceive", "mq_send", "mq_timedsend" }; + +static mqd_t q; +static struct timespec never; + +static void * +tf (void *arg) +{ + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_push (cl, NULL); + + char c = ' '; + + switch ((long) arg) + { + case TF_MQ_SEND: + TEMP_FAILURE_RETRY (mq_send (q, &c, 1, 1)); + break; + case TF_MQ_TIMEDSEND: + TEMP_FAILURE_RETRY (mq_timedsend (q, &c, 1, 1, &never)); + break; + case TF_MQ_RECEIVE: + TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL)); + break; + case TF_MQ_TIMEDRECEIVE: + TEMP_FAILURE_RETRY (mq_timedreceive (q, &c, 1, NULL, &never)); + break; + } + + pthread_cleanup_pop (0); + + printf ("tf: %s returned\n", names[(long) arg]); + + exit (1); +} + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + char name[sizeof "/tst-mqueue8-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue8-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (clock_gettime (CLOCK_REALTIME, &never) == 0) + never.tv_sec += 100; + else + { + never.tv_sec = time (NULL) + 100; + never.tv_nsec = 0; + } + + int result = 0; + for (long l = TF_MQ_RECEIVE; l <= TF_MQ_TIMEDSEND; ++l) + { + cl_called = 0; + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) l) != 0) + { + printf ("1st %s create failed\n", names[l]); + result = 1; + continue; + } + + int r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + result = 1; + continue; + } + + struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 }; + while (nanosleep (&ts, &ts) != 0) + continue; + + printf ("going to cancel %s in-time\n", names[l]); + if (pthread_cancel (th) != 0) + { + printf ("1st cancel of %s failed\n", names[l]); + result = 1; + continue; + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("1st join of %s failed\n", names[l]); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("1st %s thread not canceled\n", names[l]); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("%s cleanup handler not called\n", names[l]); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("%s cleanup handler called more than once\n", names[l]); + result = 1; + continue; + } + + printf ("in-time %s cancellation succeeded\n", names[l]); + + cl_called = 0; + + if (pthread_create (&th, NULL, tf, (void *) l) != 0) + { + printf ("2nd %s create failed\n", names[l]); + result = 1; + continue; + } + + printf ("going to cancel %s early\n", names[l]); + if (pthread_cancel (th) != 0) + { + printf ("2nd cancel of %s failed\n", names[l]); + result = 1; + continue; + } + + r = pthread_barrier_wait (&b); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + result = 1; + continue; + } + + if (pthread_join (th, &status) != 0) + { + printf ("2nd join of %s failed\n", names[l]); + result = 1; + continue; + } + if (status != PTHREAD_CANCELED) + { + printf ("2nd %s thread not canceled\n", names[l]); + result = 1; + continue; + } + + if (cl_called == 0) + { + printf ("%s cleanup handler not called\n", names[l]); + result = 1; + continue; + } + if (cl_called > 1) + { + printf ("%s cleanup handler called more than once\n", names[l]); + result = 1; + continue; + } + + printf ("early %s cancellation succeeded\n", names[l]); + + if (l == TF_MQ_TIMEDRECEIVE) + { + /* mq_receive and mq_timedreceive are tested on empty mq. + For mq_send and mq_timedsend we need to make it full. + If this fails, there is no point in doing further testing. */ + char c = ' '; + if (mq_send (q, &c, 1, 1) != 0) + { + printf ("mq_send failed: %m\n"); + result = 1; + break; + } + } + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed: %m\n"); + result = 1; + } + + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mqueue9.c b/test/nptl/tst-mqueue9.c new file mode 100644 index 000000000..fb057d4ad --- /dev/null +++ b/test/nptl/tst-mqueue9.c @@ -0,0 +1,92 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <mqueue.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "tst-mqueue.h" + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + if (geteuid () != 0) + { + puts ("this test requires root"); + return 0; + } + + char name[sizeof "/tst-mqueue9-" + sizeof (pid_t) * 3]; + snprintf (name, sizeof (name), "/tst-mqueue9-%u", getpid ()); + + struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 }; + mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr); + + if (q == (mqd_t) -1) + { + printf ("mq_open failed with: %m\n"); + return 0; + } + else + add_temp_mq (name); + + if (seteuid (1) != 0) + { + printf ("failed to seteuid (1): %m\n"); + mq_unlink (name); + return 0; + } + + int result = 0; + if (mq_unlink (name) == 0) + { + puts ("mq_unlink unexpectedly succeeded"); + result = 1; + } + else if (errno != EACCES) + { + printf ("mq_unlink did not fail with EACCES: %m\n"); + result = 1;; + } + + if (seteuid (0) != 0) + { + printf ("failed to seteuid (0): %m\n"); + result = 1; + } + + if (mq_unlink (name) != 0) + { + printf ("mq_unlink failed with: %m\n"); + result = 1; + } + + if (mq_close (q) != 0) + { + printf ("mq_close failed with: %m\n"); + result = 1; + } + + return result; +} + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex1.c b/test/nptl/tst-mutex1.c new file mode 100644 index 000000000..50b5ccaf0 --- /dev/null +++ b/test/nptl/tst-mutex1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_mutex_t m; + + if (pthread_mutex_init (&m, NULL) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex2.c b/test/nptl/tst-mutex2.c new file mode 100644 index 000000000..f589a1ea1 --- /dev/null +++ b/test/nptl/tst-mutex2.c @@ -0,0 +1,223 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m; +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + int e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("child: 1st mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("child: 1st mutex_unlock error != EPERM"); + exit (1); + } + + e = pthread_mutex_trylock (&m); + if (e == 0) + { + puts ("child: 1st trylock suceeded"); + exit (1); + } + if (e != EBUSY) + { + puts ("child: 1st trylock didn't return EBUSY"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 1st barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 2nd barrier_wait failed"); + exit (1); + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("child: 2nd mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("child: 2nd mutex_unlock error != EPERM"); + exit (1); + } + + if (pthread_mutex_trylock (&m) != 0) + { + puts ("child: 2nd trylock failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("child: 3rd mutex_unlock failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_mutexattr_t a; + int e; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + + if (pthread_mutex_init (&m, &a) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if ((e = pthread_mutex_unlock (&m)) == 0) + { + puts ("1st mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("1st mutex_unlock error != EPERM"); + exit (1); + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + if ((e = pthread_mutex_lock (&m)) == 0) + { + puts ("2nd mutex_lock succeeded"); + exit (1); + } + else if (e != EDEADLK) + { + puts ("2nd mutex_lock error != EDEADLK"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + exit (1); + } + + if ((e = pthread_mutex_unlock (&m)) == 0) + { + puts ("3rd mutex_unlock succeeded"); + exit (1); + } + else if (e != EPERM) + { + puts ("3rd mutex_unlock error != EPERM"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + exit (1); + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + exit (1); + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex3.c b/test/nptl/tst-mutex3.c new file mode 100644 index 000000000..8e57924ba --- /dev/null +++ b/test/nptl/tst-mutex3.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m; +static pthread_barrier_t b; + + +static void * +tf (void *arg) +{ + int e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("1st mutex_unlock in child succeeded"); + exit (1); + } + if (e != EPERM) + { + puts ("1st mutex_unlock in child didn't return EPERM"); + exit (1); + } + + e = pthread_mutex_trylock (&m); + if (e == 0) + { + puts ("mutex_trylock in second thread succeeded"); + exit (1); + } + if (e != EBUSY) + { + puts ("mutex_trylock returned wrong value"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("2nd mutex_unlock in child succeeded"); + exit (1); + } + if (e != EPERM) + { + puts ("2nd mutex_unlock in child didn't return EPERM"); + exit (1); + } + + if (pthread_mutex_trylock (&m) != 0) + { + puts ("2nd mutex_trylock in second thread failed"); + exit (1); + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("3rd mutex_unlock in second thread failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_mutexattr_t a; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (&m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + if (pthread_mutex_trylock (&m) != 0) + { + puts ("1st trylock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, 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; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("3rd mutex_unlock failed"); + return 1; + } + + e = pthread_mutex_unlock (&m); + if (e == 0) + { + puts ("4th mutex_unlock succeeded"); + return 1; + } + if (e != EPERM) + { + puts ("4th mutex_unlock didn't return EPERM"); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex4.c b/test/nptl/tst-mutex4.c new file mode 100644 index 000000000..0ce7313ca --- /dev/null +++ b/test/nptl/tst-mutex4.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-mutex4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t a; + pid_t pid; + char *p; + int err; + int s; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + p = (char *) (m + 1); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&a, &s) != 0) + { + puts ("1st mutexattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&a, &s) != 0) + { + puts ("2nd mutexattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_mutex_init (m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + err = pthread_mutex_trylock (m); + if (err == 0) + { + puts ("mutex_trylock succeeded"); + return 1; + } + else if (err != EBUSY) + { + puts ("mutex_trylock didn't return EBUSY"); + return 1; + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + puts ("child: 1st mutex_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + if (pthread_mutex_lock (m) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + return 1; + } + + if (*p != 1) + { + puts ("*p != 1"); + return 1; + } + + puts ("parent done"); + } + + return 0; +} + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex5.c b/test/nptl/tst-mutex5.c new file mode 100644 index 000000000..eb35b78d3 --- /dev/null +++ b/test/nptl/tst-mutex5.c @@ -0,0 +1,186 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + + +#ifndef TYPE +# define TYPE PTHREAD_MUTEX_NORMAL +#endif + + +static int +do_test (void) +{ + pthread_mutex_t m; + struct timespec ts; + struct timeval tv; + struct timeval tv2; + int err; + pthread_mutexattr_t a; + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, TYPE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (&m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutex_trylock (&m) == 0) + { + puts ("mutex_trylock succeeded"); + return 1; + } + + gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_sec += 2; /* Wait 2 seconds. */ + + err = pthread_mutex_timedlock (&m, &ts); + if (err == 0) + { + puts ("timedlock succeeded"); + return 1; + } + else if (err != ETIMEDOUT) + { + printf ("timedlock error != ETIMEDOUT: %d\n", err); + return 1; + } + else + { + int clk_tck = sysconf (_SC_CLK_TCK); + + gettimeofday (&tv2, NULL); + + tv2.tv_sec -= tv.tv_sec; + tv2.tv_usec -= tv.tv_usec; + if (tv2.tv_usec < 0) + { + tv2.tv_usec += 1000000; + tv2.tv_sec -= 1; + } + + /* Be a bit tolerant, add one CLK_TCK. */ + tv2.tv_usec += 1000000 / clk_tck; + if (tv2.tv_usec >= 1000000) + { + tv2.tv_usec -= 1000000; + ++tv2.tv_sec; + } + + if (tv2.tv_sec < 2) + { + printf ("premature timeout: %ld.%06ld difference\n", + tv2.tv_sec, tv2.tv_usec); + return 1; + } + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_sec += 2; /* Wait 2 seconds. */ + /* The following makes the ts value invalid. */ + ts.tv_nsec += 1000000000; + + err = pthread_mutex_timedlock (&m, &ts); + if (err == 0) + { + puts ("2nd timedlock succeeded"); + return 1; + } + else if (err != EINVAL) + { + printf ("2nd timedlock error != EINVAL: %d\n", err); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_sec += 2; /* Wait 2 seconds. */ + if (pthread_mutex_timedlock (&m, &ts) != 0) + { + puts ("3rd timedlock failed"); + } + + (void) gettimeofday (&tv2, NULL); + + /* Check that timedlock didn't delay. We use a limit of 0.1 secs. */ + timersub (&tv2, &tv, &tv2); + if (tv2.tv_sec > 0 || tv2.tv_usec > 100000) + { + puts ("3rd timedlock didn't return right away"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("final mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy failed"); + return 1; + } + + return 0; +} + +#define TIMEOUT 4 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex5a.c b/test/nptl/tst-mutex5a.c new file mode 100644 index 000000000..f91eec0d7 --- /dev/null +++ b/test/nptl/tst-mutex5a.c @@ -0,0 +1,2 @@ +#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP +#include "tst-mutex5.c" diff --git a/test/nptl/tst-mutex6.c b/test/nptl/tst-mutex6.c new file mode 100644 index 000000000..f066c62ed --- /dev/null +++ b/test/nptl/tst-mutex6.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + pthread_mutex_t m; + + if (pthread_mutex_init (&m, NULL) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + /* This call should never return. */ + pthread_mutex_lock (&m); + + puts ("2nd mutex_lock returned"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex7.c b/test/nptl/tst-mutex7.c new file mode 100644 index 000000000..a9b9f318c --- /dev/null +++ b/test/nptl/tst-mutex7.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <time.h> + + +#ifndef INIT +# define INIT PTHREAD_MUTEX_INITIALIZER +#endif + + +static pthread_mutex_t lock = INIT; + + +#define ROUNDS 1000 +#define N 100 + + +static void * +tf (void *arg) +{ + int nr = (long int) arg; + int cnt; + struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 }; + + for (cnt = 0; cnt < ROUNDS; ++cnt) + { + if (pthread_mutex_lock (&lock) != 0) + { + printf ("thread %d: failed to get the lock\n", nr); + return (void *) 1l; + } + + if (pthread_mutex_unlock (&lock) != 0) + { + printf ("thread %d: failed to release the lock\n", nr); + return (void *) 1l; + } + + nanosleep (&ts, NULL); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + pthread_t th[N]; + int cnt; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("locking in parent failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0) + { + printf ("creating thread %d failed\n", cnt); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("unlocking in parent failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + printf ("joining thread %d failed\n", cnt); + return 1; + } + + return 0; +} + +#define TIMEOUT 60 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex7a.c b/test/nptl/tst-mutex7a.c new file mode 100644 index 000000000..f08799ae7 --- /dev/null +++ b/test/nptl/tst-mutex7a.c @@ -0,0 +1,2 @@ +#define INIT PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP +#include "tst-mutex7.c" diff --git a/test/nptl/tst-mutex8.c b/test/nptl/tst-mutex8.c new file mode 100644 index 000000000..80ebe71f0 --- /dev/null +++ b/test/nptl/tst-mutex8.c @@ -0,0 +1,367 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +/* This test checks behavior not required by POSIX. */ +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t *m; +static pthread_barrier_t b; +static pthread_cond_t c; +static bool done; + + +static void +cl (void *arg) +{ + if (pthread_mutex_unlock (m) != 0) + { + puts ("cl: mutex_unlocked failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (m) != 0) + { + puts ("tf: mutex_lock failed"); + return (void *) 1l; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return (void *) 1l; + } + + if (arg == NULL) + do + if (pthread_cond_wait (&c, m) != 0) + { + puts ("tf: cond_wait failed"); + return (void *) 1l; + } + while (! done); + else + do + { + pthread_cleanup_push (cl, NULL); + + if (pthread_cond_wait (&c, m) != 0) + { + puts ("tf: cond_wait failed"); + return (void *) 1l; + } + + pthread_cleanup_pop (0); + } + while (! done); + + if (pthread_mutex_unlock (m) != 0) + { + puts ("tf: mutex_unlock failed"); + return (void *) 1l; + } + + return NULL; +} + + +static int +check_type (const char *mas, pthread_mutexattr_t *ma) +{ + if (pthread_mutex_init (m, ma) != 0) + { + printf ("1st mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("immediate mutex_destroy failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_init (m, ma) != 0) + { + printf ("2nd mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + printf ("1st mutex_lock failed for %s\n", mas); + return 1; + } + + int e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("mutex_destroy of self-locked mutex did not return EBUSY %s\n", + mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("1st mutex_unlock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_trylock (m) != 0) + { + printf ("mutex_trylock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of self-trylocked mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +mutex_destroy of self-trylocked mutex did not return EBUSY %s\n", + mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("2nd mutex_unlock failed for %s\n", mas); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + return 1; + } + done = false; + + 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) + { + printf ("2nd mutex_lock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("3rd mutex_unlock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("mutex_destroy of condvar-used mutex succeeded for %s\n", mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas); + return 1; + } + + done = true; + if (pthread_cond_signal (&c) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + if (r != NULL) + { + puts ("thread didn't return NULL"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("mutex_destroy after condvar-use failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_init (m, ma) != 0) + { + printf ("3rd mutex_init failed for %s\n", mas); + return 1; + } + + if (pthread_create (&th, NULL, tf, (void *) 1) != 0) + { + puts ("2nd create failed"); + return 1; + } + done = false; + + 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) + { + printf ("3rd mutex_lock failed for %s\n", mas); + return 1; + } + + if (pthread_mutex_unlock (m) != 0) + { + printf ("4th mutex_unlock failed for %s\n", mas); + return 1; + } + + e = pthread_mutex_destroy (m); + if (e == 0) + { + printf ("2nd mutex_destroy of condvar-used mutex succeeded for %s\n", + mas); + return 1; + } + if (e != EBUSY) + { + printf ("\ +2nd mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", + mas); + return 1; + } + + if (pthread_cancel (th) != 0) + { + puts ("cond_cancel failed"); + return 1; + } + + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("thread not canceled"); + return 1; + } + + if (pthread_mutex_destroy (m) != 0) + { + printf ("mutex_destroy after condvar-canceled failed for %s\n", mas); + return 1; + } + + return 0; +} + + +static int +do_test (void) +{ + pthread_mutex_t mm; + m = &mm; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_cond_init (&c, NULL) != 0) + { + puts ("cond_init failed"); + return 1; + } + + puts ("check normal mutex"); + int res = check_type ("normal", NULL); + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("1st mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("1st mutexattr_settype failed"); + return 1; + } + puts ("check recursive mutex"); + res |= check_type ("recursive", &ma); + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("1st mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("2nd mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("2nd mutexattr_settype failed"); + return 1; + } + puts ("check error-checking mutex"); + res |= check_type ("error-checking", &ma); + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("2nd mutexattr_destroy failed"); + return 1; + } + + return res; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-mutex9.c b/test/nptl/tst-mutex9.c new file mode 100644 index 000000000..3748584b1 --- /dev/null +++ b/test/nptl/tst-mutex9.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/time.h> + +int gettimeofday(struct timeval *tv, struct timezone *tz); + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-mutex9.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t a; + pid_t pid; + char *p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + p = (char *) (m + 1); + + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_settype (&a, PTHREAD_MUTEX_RECURSIVE) != 0) + { + puts ("mutexattr_settype failed"); + return 1; + } + + if (pthread_mutex_init (m, &a) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + if (pthread_mutex_trylock (m) == 0) + { + puts ("child: mutex_trylock succeeded"); + exit (1); + } + + if (pthread_mutex_unlock (m) == 0) + { + puts ("child: mutex_unlock succeeded"); + exit (1); + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + + int e = pthread_mutex_timedlock (m, &ts); + if (e == 0) + { + puts ("child: mutex_timedlock succeeded"); + exit (1); + } + if (e != ETIMEDOUT) + { + puts ("child: mutex_timedlock didn't time out"); + exit (1); + } + + alarm (1); + + pthread_mutex_lock (m); + + puts ("child: mutex_lock returned"); + + exit (0); + } + + sleep (2); + + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + return 1; + } + if (! WIFSIGNALED (status)) + { + puts ("child not killed by signal"); + return 1; + } + if (WTERMSIG (status) != SIGALRM) + { + puts ("child not killed by SIGALRM"); + return 1; + } + + return 0; +} + +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once1.c b/test/nptl/tst-once1.c new file mode 100644 index 000000000..87ed51c82 --- /dev/null +++ b/test/nptl/tst-once1.c @@ -0,0 +1,51 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> + + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static int global; + +static void +once_handler (void) +{ + ++global; +} + + +static int +do_test (void) +{ + pthread_once (&once, once_handler); + pthread_once (&once, once_handler); + + if (global != 1) + { + printf ("global = %d, expected 1\n", global); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once2.c b/test/nptl/tst-once2.c new file mode 100644 index 000000000..c60634538 --- /dev/null +++ b/test/nptl/tst-once2.c @@ -0,0 +1,104 @@ +/* Copyright (C) 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +#define N 100 + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static int global; + +static void +once_handler (void) +{ + struct timespec ts; + + ++global; + + ts.tv_sec = 2; + ts.tv_nsec = 0; + nanosleep (&ts, NULL); +} + + +static void * +tf (void *arg) +{ + pthread_once (&once, once_handler); + + if (global != 1) + { + printf ("thread %ld: global == %d\n", (long int) arg, global); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + pthread_t th[N]; + int cnt; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0) + { + printf ("creation of thread %d failed\n", cnt); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + for (cnt = 0; cnt < N; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + printf ("join of thread %d failed\n", cnt); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once3.c b/test/nptl/tst-once3.c new file mode 100644 index 000000000..43b354a39 --- /dev/null +++ b/test/nptl/tst-once3.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +#define N 100 + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + +static pthread_barrier_t bar; + +static int global; +static int cl_called; + +static void +once_handler1 (void) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("once_handler1: mutex_lock failed"); + exit (1); + } + puts ("once_handler1: locked"); + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("once_handler1: barrier_wait failed"); + exit (1); + } + + pthread_cond_wait (&cond, &mut); + + /* We should never get here. */ + exit (42); +} + +static void +once_handler2 (void) +{ + global = 1; +} + + +static void +cl (void *arg) +{ + cl_called = 1; +} + + +static void * +tf (void *arg) +{ + pthread_cleanup_push (cl, NULL) + + pthread_once (&once, once_handler1); + + pthread_cleanup_pop (0); + + /* We should never get here. */ + puts ("pthread_once in tf returned"); + exit (1); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("first create failed"); + return 1; + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + /* We unlock the mutex so that we catch the case where the pthread_cond_wait + call incorrectly resumes and tries to get the mutex. */ + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + /* Cancel the thread. */ + puts ("going to cancel"); + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *result; + pthread_join (th, &result); + if (result != PTHREAD_CANCELED) + { + puts ("join didn't return PTHREAD_CANCELED"); + return 1; + } + + if (cl_called != 1) + { + puts ("cleanup handler not called"); + return 1; + } + + pthread_once (&once, once_handler2); + + if (global != 1) + { + puts ("global still 0"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-once4.c b/test/nptl/tst-once4.c new file mode 100644 index 000000000..35bae3c0e --- /dev/null +++ b/test/nptl/tst-once4.c @@ -0,0 +1,202 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +static pthread_once_t once = PTHREAD_ONCE_INIT; + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + +static pthread_barrier_t bar; + +static int global; +static int cl_called; + +static void +once_handler1 (void) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("once_handler1: mutex_lock failed"); + exit (1); + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("once_handler1: barrier_wait failed"); + exit (1); + } + + pthread_cond_wait (&cond, &mut); + + /* We should never get here. */ +} + + +static void +once_handler2 (void) +{ + global = 1; +} + + +static void +cl (void *arg) +{ + ++cl_called; +} + + +static void * +tf1 (void *arg) +{ + pthread_cleanup_push (cl, NULL); + + pthread_once (&once, once_handler1); + + pthread_cleanup_pop (0); + + /* We should never get here. */ + puts ("pthread_once in tf returned"); + exit (1); +} + + +static void * +tf2 (void *arg) +{ + pthread_cleanup_push (cl, NULL); + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("once_handler2: barrier_wait failed"); + exit (1); + } + + pthread_cleanup_pop (0); + + pthread_once (&once, once_handler2); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th[2]; + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_create (&th[0], NULL, tf1, NULL) != 0) + { + puts ("first create failed"); + return 1; + } + + int r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("first barrier_wait failed"); + return 1; + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + /* We unlock the mutex so that we catch the case where the pthread_cond_wait + call incorrectly resumes and tries to get the mutex. */ + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_create (&th[1], NULL, tf2, NULL) != 0) + { + puts ("second create failed"); + return 1; + } + + r = pthread_barrier_wait (&bar); + if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("second barrier_wait failed"); + return 1; + } + + /* Give the second thread a chance to reach the pthread_once call. */ + sleep (2); + + /* Cancel the thread. */ + if (pthread_cancel (th[0]) != 0) + { + puts ("cancel failed"); + return 1; + } + + void *result; + pthread_join (th[0], &result); + if (result != PTHREAD_CANCELED) + { + puts ("first join didn't return PTHREAD_CANCELED"); + return 1; + } + + puts ("joined first thread"); + + pthread_join (th[1], &result); + if (result != NULL) + { + puts ("second join didn't return PTHREAD_CANCELED"); + return 1; + } + + if (global != 1) + { + puts ("global still 0"); + return 1; + } + + if (cl_called != 1) + { + printf ("cl_called = %d\n", cl_called); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 4 +#include "../test-skeleton.c" diff --git a/test/nptl/tst-popen1.c b/test/nptl/tst-popen1.c new file mode 100644 index 000000000..a9d077371 --- /dev/null +++ b/test/nptl/tst-popen1.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void * +dummy (void *x) +{ + return NULL; +} + +static char buf[sizeof "something\n"]; + +static int +do_test (void) +{ + FILE *f; + pthread_t p; + int err; + + f = popen ("echo something", "r"); + if (f == NULL) + error (EXIT_FAILURE, errno, "popen failed"); + if (fgets (buf, sizeof (buf), f) == NULL) + error (EXIT_FAILURE, 0, "fgets failed"); + if (strcmp (buf, "something\n")) + error (EXIT_FAILURE, 0, "read wrong data"); + if (pclose (f)) + error (EXIT_FAILURE, errno, "pclose returned non-zero"); + if ((err = pthread_create (&p, NULL, dummy, NULL))) + error (EXIT_FAILURE, err, "pthread_create failed"); + if ((err = pthread_join (p, NULL))) + error (EXIT_FAILURE, err, "pthread_join failed"); + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-raise1.c b/test/nptl/tst-raise1.c new file mode 100644 index 000000000..5ea9886a4 --- /dev/null +++ b/test/nptl/tst-raise1.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <errno.h> +#include <error.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> + +volatile int count; + +void +sh (int sig) +{ + ++count; +} + +int +main (void) +{ + struct sigaction sa; + sa.sa_handler = sh; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (SIGUSR1, &sa, NULL) < 0) + { + printf ("sigaction failed: %m\n"); + exit (1); + } + if (raise (SIGUSR1) < 0) + { + printf ("first raise failed: %m\n"); + exit (1); + } + if (raise (SIGUSR1) < 0) + { + printf ("second raise failed: %m\n"); + exit (1); + } + if (count != 2) + { + printf ("signal handler not called 2 times\n"); + exit (1); + } + exit (0); +} diff --git a/test/nptl/tst-rwlock1.c b/test/nptl/tst-rwlock1.c new file mode 100644 index 000000000..c97e0e60f --- /dev/null +++ b/test/nptl/tst-rwlock1.c @@ -0,0 +1,117 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlock_rdlock (&r) != 0) + { + puts ("1st rwlock_rdlock failed"); + return 1; + } + puts ("1st rwlock_rdlock succeeded"); + + if (pthread_rwlock_rdlock (&r) != 0) + { + puts ("2nd rwlock_rdlock failed"); + return 1; + } + puts ("2nd rwlock_rdlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("1st rwlock_unlock failed"); + return 1; + } + puts ("1st rwlock_unlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("2nd rwlock_unlock failed"); + return 1; + } + puts ("2nd rwlock_unlock succeeded"); + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("1st rwlock_wrlock failed"); + return 1; + } + puts ("1st rwlock_wrlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("3rd rwlock_unlock failed"); + return 1; + } + puts ("3rd rwlock_unlock succeeded"); + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("2nd rwlock_wrlock failed"); + return 1; + } + puts ("2nd rwlock_wrlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("4th rwlock_unlock failed"); + return 1; + } + puts ("4th rwlock_unlock succeeded"); + + if (pthread_rwlock_rdlock (&r) != 0) + { + puts ("3rd rwlock_rdlock failed"); + return 1; + } + puts ("3rd rwlock_rdlock succeeded"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("5th rwlock_unlock failed"); + return 1; + } + puts ("5th rwlock_unlock succeeded"); + + if (pthread_rwlock_destroy (&r) != 0) + { + puts ("rwlock_destroy failed"); + return 1; + } + puts ("rwlock_destroy succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock10.c b/test/nptl/tst-rwlock10.c new file mode 100644 index 000000000..43156eae6 --- /dev/null +++ b/test/nptl/tst-rwlock10.c @@ -0,0 +1,21 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define INIT PTHREAD_RWLOCK_INITIALIZER +#include "tst-rwlock8.c" diff --git a/test/nptl/tst-rwlock11.c b/test/nptl/tst-rwlock11.c new file mode 100644 index 000000000..ed9af7edc --- /dev/null +++ b/test/nptl/tst-rwlock11.c @@ -0,0 +1,21 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#define INIT PTHREAD_RWLOCK_INITIALIZER +#include "tst-rwlock9.c" diff --git a/test/nptl/tst-rwlock12.c b/test/nptl/tst-rwlock12.c new file mode 100644 index 000000000..91f25d3b1 --- /dev/null +++ b/test/nptl/tst-rwlock12.c @@ -0,0 +1,208 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-rwlock12.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutex_t *m; + pthread_mutexattr_t ma; + pthread_rwlock_t *r; + pthread_rwlockattr_t ra; + pid_t pid; + int status = 0; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t)) + & ~(__alignof (pthread_rwlock_t) - 1)); + /* The following assumes alignment for a mutex is at least as high + as that for a rwlock. Which is true in our case. */ + m = (pthread_mutex_t *) (r + 1); + + if (pthread_rwlockattr_init (&ra) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + + if (pthread_rwlockattr_setpshared (&ra, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("rwlockattr_setpshared failed"); + return 1; + } + + if (pthread_rwlock_init (r, &ra) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutex_init (m, &ma) != 0) + { + puts ("mutex_init failed"); + return 1; + } + + /* Lock the mutex. */ + if (pthread_mutex_lock (m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Lock the mutex. */ + if (pthread_mutex_lock (m) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + /* Try to get the rwlock. */ + if (pthread_rwlock_trywrlock (r) == 0) + { + puts ("rwlock_trywrlock succeeded"); + return 1; + } + + /* Try again. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000000 }; + int e = pthread_rwlock_timedwrlock (r, &ts); + if (e == 0) + { + puts ("rwlock_timedwrlock succeeded"); + return 1; + } + if (e != ETIMEDOUT) + { + puts ("rwlock_timedwrlock didn't return ETIMEDOUT"); + status = 1; + } + + if (pthread_rwlock_tryrdlock (r) == 0) + { + puts ("rwlock_tryrdlock succeeded"); + return 1; + } + + e = pthread_rwlock_timedrdlock (r, &ts); + if (e == 0) + { + puts ("rwlock_timedrdlock succeeded"); + return 1; + } + if (e != ETIMEDOUT) + { + puts ("rwlock_timedrdlock didn't return ETIMEDOUT"); + status = 1; + } + } + else + { + /* Lock the rwlock for writing. */ + if (pthread_rwlock_wrlock (r) != 0) + { + puts ("rwlock_wrlock failed"); + kill (pid, SIGTERM); + return 1; + } + + /* Allow the child to run. */ + if (pthread_mutex_unlock (m) != 0) + { + puts ("mutex_unlock failed"); + kill (pid, SIGTERM); + return 1; + } + + /* Just wait for the child. */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("waitpid failed"); + kill (pid, SIGTERM); + return 1; + } + } + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock13.c b/test/nptl/tst-rwlock13.c new file mode 100644 index 000000000..61d5b83e1 --- /dev/null +++ b/test/nptl/tst-rwlock13.c @@ -0,0 +1,71 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + int ret; + + memset (&r, 0xaa, sizeof (r)); + if ((ret = pthread_rwlock_init (&r, NULL)) != 0) + { + printf ("rwlock_init failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_rdlock (&r)) != 0) + { + printf ("rwlock_rdlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_unlock (&r)) != 0) + { + printf ("rwlock_unlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_wrlock (&r)) != 0) + { + printf ("rwlock_wrlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_unlock (&r)) != 0) + { + printf ("second rwlock_unlock failed: %d\n", ret); + return 1; + } + + if ((ret = pthread_rwlock_destroy (&r)) != 0) + { + printf ("second rwlock_destroy failed: %d\n", ret); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock14.c b/test/nptl/tst-rwlock14.c new file mode 100644 index 000000000..fc0d3d219 --- /dev/null +++ b/test/nptl/tst-rwlock14.c @@ -0,0 +1,169 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + + +static pthread_barrier_t b; +static pthread_rwlock_t r = PTHREAD_RWLOCK_INITIALIZER; + + +static void * +tf (void *arg) +{ + /* Lock the read-write lock. */ + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("tf: cannot lock rwlock"); + exit (EXIT_FAILURE); + } + + pthread_t mt = *(pthread_t *) arg; + + pthread_barrier_wait (&b); + + /* This call will never return. */ + pthread_join (mt, NULL); + + return NULL; +} + + +static int +do_test (void) +{ + int result = 0; + struct timespec ts; + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t me = pthread_self (); + pthread_t th; + if (pthread_create (&th, NULL, tf, &me) != 0) + { + puts ("create failed"); + return 1; + } + + /* Wait until the rwlock is locked. */ + pthread_barrier_wait (&b); + + ts.tv_nsec = -1; + + int e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("first rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + e = pthread_rwlock_timedwrlock (&r, &ts); + if (e == 0) + { + puts ("first rwlock_timedwrlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first rwlock_timedwrlock did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 1000000000; + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("second rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("second rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 0x100001000LL; + if (ts.tv_nsec != 0x100001000LL) + ts.tv_nsec = 2000000000; + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("third rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("third rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("third rwlock_timedrdlock did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("third rwlock_timedrdlock did not return EINVAL"); + result = 1; + } + + if (result == 0) + puts ("no bugs"); + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock2.c b/test/nptl/tst-rwlock2.c new file mode 100644 index 000000000..6f38682b8 --- /dev/null +++ b/test/nptl/tst-rwlock2.c @@ -0,0 +1,143 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + int e; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("1st rwlock_wrlock failed"); + return 1; + } + puts ("1st rwlock_wrlock succeeded"); + + e = pthread_rwlock_tryrdlock (&r); + if (e == 0) + { + puts ("rwlock_tryrdlock on rwlock with writer succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY"); + return 1; + } + puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY"); + + e = pthread_rwlock_trywrlock (&r); + if (e == 0) + { + puts ("rwlock_trywrlock on rwlock with writer succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_trywrlock on rwlock with writer return value != EBUSY"); + return 1; + } + puts ("rwlock_trywrlock on rwlock with writer failed with EBUSY"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("1st rwlock_unlock failed"); + return 1; + } + puts ("1st rwlock_unlock succeeded"); + + if (pthread_rwlock_tryrdlock (&r) != 0) + { + puts ("rwlock_tryrdlock on unlocked rwlock failed"); + return 1; + } + puts ("rwlock_tryrdlock on unlocked rwlock succeeded"); + + e = pthread_rwlock_trywrlock (&r); + if (e == 0) + { + puts ("rwlock_trywrlock on rwlock with reader succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_trywrlock on rwlock with reader return value != EBUSY"); + return 1; + } + puts ("rwlock_trywrlock on rwlock with reader failed with EBUSY"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("2nd rwlock_unlock failed"); + return 1; + } + puts ("2nd rwlock_unlock succeeded"); + + if (pthread_rwlock_trywrlock (&r) != 0) + { + puts ("rwlock_trywrlock on unlocked rwlock failed"); + return 1; + } + puts ("rwlock_trywrlock on unlocked rwlock succeeded"); + + e = pthread_rwlock_tryrdlock (&r); + if (e == 0) + { + puts ("rwlock_tryrdlock on rwlock with writer succeeded"); + return 1; + } + if (e != EBUSY) + { + puts ("rwlock_tryrdlock on rwlock with writer return value != EBUSY"); + return 1; + } + puts ("rwlock_tryrdlock on rwlock with writer failed with EBUSY"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("3rd rwlock_unlock failed"); + return 1; + } + puts ("3rd rwlock_unlock succeeded"); + + if (pthread_rwlock_destroy (&r) != 0) + { + puts ("rwlock_destroy failed"); + return 1; + } + puts ("rwlock_destroy succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock3.c b/test/nptl/tst-rwlock3.c new file mode 100644 index 000000000..c1cac876d --- /dev/null +++ b/test/nptl/tst-rwlock3.c @@ -0,0 +1,93 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +/* This test case checks more than standard compliance. An + implementation may provide this service but it is not required to + do so. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_rwlock_t r; + int e; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + puts ("rwlock_init succeeded"); + + if (pthread_rwlock_trywrlock (&r) != 0) + { + puts ("rwlock_trywrlock on unlocked rwlock failed"); + return 1; + } + puts ("rwlock_trywrlock on unlocked rwlock succeeded"); + + e = pthread_rwlock_rdlock (&r); + if (e == 0) + { + puts ("rwlock_rdlock on rwlock with writer succeeded"); + return 1; + } + if (e != EDEADLK) + { + puts ("rwlock_rdlock on rwlock with writer failed != EDEADLK"); + return 1; + } + puts ("rwlock_rdlock on rwlock with writer failed with EDEADLK"); + + e = pthread_rwlock_wrlock (&r); + if (e == 0) + { + puts ("rwlock_wrlock on rwlock with writer succeeded"); + return 1; + } + if (e != EDEADLK) + { + puts ("rwlock_wrlock on rwlock with writer failed != EDEADLK"); + return 1; + } + puts ("rwlock_wrlock on rwlock with writer failed with EDEADLK"); + + if (pthread_rwlock_unlock (&r) != 0) + { + puts ("rwlock_unlock failed"); + return 1; + } + puts ("rwlock_unlock succeeded"); + + if (pthread_rwlock_destroy (&r) != 0) + { + puts ("rwlock_destroy failed"); + return 1; + } + puts ("rwlock_destroy succeeded"); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock4.c b/test/nptl/tst-rwlock4.c new file mode 100644 index 000000000..8de0121b3 --- /dev/null +++ b/test/nptl/tst-rwlock4.c @@ -0,0 +1,190 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-rwlock4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_rwlock_t *r; + pthread_rwlockattr_t a; + pid_t pid; + char *p; + int err; + int s; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t)) + & ~(__alignof (pthread_rwlock_t) - 1)); + p = (char *) (r + 1); + + if (pthread_rwlockattr_init (&a) != 0) + { + puts ("rwlockattr_init failed"); + return 1; + } + + if (pthread_rwlockattr_getpshared (&a, &s) != 0) + { + puts ("1st rwlockattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_rwlockattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("rwlockattr_setpshared failed"); + return 1; + } + + if (pthread_rwlockattr_getpshared (&a, &s) != 0) + { + puts ("2nd rwlockattr_getpshared failed"); + return 1; + } + + if (s != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_rwlock_init (r, &a) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + + if (pthread_rwlock_rdlock (r) != 0) + { + puts ("rwlock_rdlock failed"); + return 1; + } + + if (pthread_rwlockattr_destroy (&a) != 0) + { + puts ("rwlockattr_destroy failed"); + return 1; + } + + err = pthread_rwlock_trywrlock (r); + if (err == 0) + { + puts ("rwlock_trywrlock succeeded"); + return 1; + } + else if (err != EBUSY) + { + puts ("rwlock_trywrlock didn't return EBUSY"); + return 1; + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_rwlock_unlock (r) != 0) + { + puts ("child: 1st rwlock_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + if (pthread_rwlock_wrlock (r) != 0) + { + puts ("parent: rwlock_wrlock failed"); + return 1; + } + + if (*p != 1) + { + puts ("*p != 1"); + return 1; + } + + puts ("parent done"); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock5.c b/test/nptl/tst-rwlock5.c new file mode 100644 index 000000000..a04eb2670 --- /dev/null +++ b/test/nptl/tst-rwlock5.c @@ -0,0 +1,87 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t r; + + +static void * +tf (void *arg) +{ + if (pthread_rwlock_wrlock (&r) == 0) + { + puts ("child: rwlock_wrlock succeeded"); + exit (1); + } + + puts ("child: rwlock_wrlock returned"); + + exit (1); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_rwlock_init (&r, NULL) != 0) + { + puts ("rwlock_init failed"); + return 1; + } + + if (pthread_rwlock_wrlock (&r) != 0) + { + puts ("rwlock_wrlock failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("mutex_lock failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + /* This call should never return. */ + pthread_mutex_lock (&m); + + puts ("2nd mutex_lock returned"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock6.c b/test/nptl/tst-rwlock6.c new file mode 100644 index 000000000..3b525b9d5 --- /dev/null +++ b/test/nptl/tst-rwlock6.c @@ -0,0 +1,226 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + + +static int kind[] = + { + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + }; + + +static void * +tf (void *arg) +{ + pthread_rwlock_t *r = arg; + + /* Timeout: 0.3 secs. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 300000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + puts ("child calling timedrdlock"); + + int err = pthread_rwlock_timedrdlock (r, &ts); + if (err == 0) + { + puts ("rwlock_timedrdlock returned"); + pthread_exit ((void *) 1l); + } + + if (err != ETIMEDOUT) + { + printf ("err = %s (%d), expected %s (%d)\n", + strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT); + pthread_exit ((void *) 1l); + } + + puts ("1st child timedrdlock done"); + + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + timersub (&tv2, &tv, &tv); + + if (tv.tv_usec < 200000) + { + puts ("timeout too short"); + pthread_exit ((void *) 1l); + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10; + /* Note that the following operation makes ts invalid. */ + ts.tv_nsec += 1000000000; + + err = pthread_rwlock_timedrdlock (r, &ts); + if (err == 0) + { + puts ("2nd timedrdlock succeeded"); + pthread_exit ((void *) 1l); + } + if (err != EINVAL) + { + puts ("2nd timedrdlock did not return EINVAL"); + pthread_exit ((void *) 1l); + } + + puts ("2nd child timedrdlock done"); + + return NULL; +} + + +static int +do_test (void) +{ + size_t cnt; + for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt) + { + pthread_rwlock_t r; + pthread_rwlockattr_t a; + + if (pthread_rwlockattr_init (&a) != 0) + { + printf ("round %Zu: rwlockattr_t failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0) + { + printf ("round %Zu: rwlockattr_setkind failed\n", cnt); + exit (1); + } + + if (pthread_rwlock_init (&r, &a) != 0) + { + printf ("round %Zu: rwlock_init failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_destroy (&a) != 0) + { + printf ("round %Zu: rwlockattr_destroy failed\n", cnt); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ++ts.tv_sec; + + /* Get a write lock. */ + int e = pthread_rwlock_timedwrlock (&r, &ts); + if (e != 0) + { + printf ("round %Zu: rwlock_timedwrlock failed (%d)\n", cnt, e); + exit (1); + } + + puts ("1st timedwrlock done"); + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ++ts.tv_sec; + e = pthread_rwlock_timedrdlock (&r, &ts); + if (e == 0) + { + puts ("timedrdlock succeeded"); + exit (1); + } + if (e != EDEADLK) + { + puts ("timedrdlock did not return EDEADLK"); + exit (1); + } + + puts ("1st timedrdlock done"); + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ++ts.tv_sec; + e = pthread_rwlock_timedwrlock (&r, &ts); + if (e == 0) + { + puts ("2nd timedwrlock succeeded"); + exit (1); + } + if (e != EDEADLK) + { + puts ("2nd timedwrlock did not return EDEADLK"); + exit (1); + } + + puts ("2nd timedwrlock done"); + + pthread_t th; + if (pthread_create (&th, NULL, tf, &r) != 0) + { + printf ("round %Zu: create failed\n", cnt); + exit (1); + } + + puts ("started thread"); + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("round %Zu: join failed\n", cnt); + exit (1); + } + if (status != NULL) + { + printf ("failure in round %Zu\n", cnt); + exit (1); + } + + puts ("joined thread"); + + if (pthread_rwlock_destroy (&r) != 0) + { + printf ("round %Zu: rwlock_destroy failed\n", cnt); + exit (1); + } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock7.c b/test/nptl/tst-rwlock7.c new file mode 100644 index 000000000..1f34c0650 --- /dev/null +++ b/test/nptl/tst-rwlock7.c @@ -0,0 +1,179 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/time.h> + + +static int kind[] = + { + PTHREAD_RWLOCK_PREFER_READER_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, + PTHREAD_RWLOCK_PREFER_WRITER_NP, + }; + + +static void * +tf (void *arg) +{ + pthread_rwlock_t *r = arg; + + /* Timeout: 0.3 secs. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 300000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + int err = pthread_rwlock_timedwrlock (r, &ts); + if (err == 0) + { + puts ("rwlock_timedwrlock returned"); + pthread_exit ((void *) 1l); + } + + if (err != ETIMEDOUT) + { + printf ("err = %s (%d), expected %s (%d)\n", + strerror (err), err, strerror (ETIMEDOUT), ETIMEDOUT); + pthread_exit ((void *) 1l); + } + + struct timeval tv2; + (void) gettimeofday (&tv2, NULL); + + timersub (&tv2, &tv, &tv); + + if (tv.tv_usec < 200000) + { + puts ("timeout too short"); + pthread_exit ((void *) 1l); + } + + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 10; + /* Note that the following operation makes ts invalid. */ + ts.tv_nsec += 1000000000; + + err = pthread_rwlock_timedwrlock (r, &ts); + if (err == 0) + { + puts ("2nd timedwrlock succeeded"); + pthread_exit ((void *) 1l); + } + if (err != EINVAL) + { + puts ("2nd timedwrlock did not return EINVAL"); + pthread_exit ((void *) 1l); + } + + return NULL; +} + + +static int +do_test (void) +{ + size_t cnt; + for (cnt = 0; cnt < sizeof (kind) / sizeof (kind[0]); ++cnt) + { + pthread_rwlock_t r; + pthread_rwlockattr_t a; + + if (pthread_rwlockattr_init (&a) != 0) + { + printf ("round %Zu: rwlockattr_t failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_setkind_np (&a, kind[cnt]) != 0) + { + printf ("round %Zu: rwlockattr_setkind failed\n", cnt); + exit (1); + } + + if (pthread_rwlock_init (&r, &a) != 0) + { + printf ("round %Zu: rwlock_init failed\n", cnt); + exit (1); + } + + if (pthread_rwlockattr_destroy (&a) != 0) + { + printf ("round %Zu: rwlockattr_destroy failed\n", cnt); + exit (1); + } + + struct timeval tv; + (void) gettimeofday (&tv, NULL); + + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ++ts.tv_sec; + + /* Get a read lock. */ + if (pthread_rwlock_timedrdlock (&r, &ts) != 0) + { + printf ("round %Zu: rwlock_timedrdlock failed\n", cnt); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, &r) != 0) + { + printf ("round %Zu: create failed\n", cnt); + exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + printf ("round %Zu: join failed\n", cnt); + exit (1); + } + if (status != NULL) + { + printf ("failure in round %Zu\n", cnt); + exit (1); + } + + if (pthread_rwlock_destroy (&r) != 0) + { + printf ("round %Zu: rwlock_destroy failed\n", cnt); + exit (1); + } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock8.c b/test/nptl/tst-rwlock8.c new file mode 100644 index 000000000..7eeaea885 --- /dev/null +++ b/test/nptl/tst-rwlock8.c @@ -0,0 +1,164 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> + + +#define NWRITERS 15 +#define WRITETRIES 10 +#define NREADERS 15 +#define READTRIES 15 + +#define DELAY 1000000 + +#ifndef INIT +# define INIT PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +#endif + +static pthread_rwlock_t lock = INIT; + + +static void * +writer_thread (void *nr) +{ + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < WRITETRIES; ++n) + { + printf ("writer thread %ld tries again\n", (long int) nr); + + if (pthread_rwlock_wrlock (&lock) != 0) + { + puts ("wrlock failed"); + exit (1); + } + + printf ("writer thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for writer failed"); + exit (1); + } + + printf ("writer thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static void * +reader_thread (void *nr) +{ + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < READTRIES; ++n) + { + printf ("reader thread %ld tries again\n", (long int) nr); + + if (pthread_rwlock_rdlock (&lock) != 0) + { + puts ("rdlock failed"); + exit (1); + } + + printf ("reader thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for reader failed"); + exit (1); + } + + printf ("reader thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t thwr[NWRITERS]; + pthread_t thrd[NREADERS]; + int n; + void *res; + + /* Make standard error the same as standard output. */ + dup2 (1, 2); + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + for (n = 0; n < NWRITERS; ++n) + if (pthread_create (&thwr[n], NULL, writer_thread, + (void *) (long int) n) != 0) + { + puts ("writer create failed"); + exit (1); + } + + for (n = 0; n < NREADERS; ++n) + if (pthread_create (&thrd[n], NULL, reader_thread, + (void *) (long int) n) != 0) + { + puts ("reader create failed"); + exit (1); + } + + /* Wait for all the threads. */ + for (n = 0; n < NWRITERS; ++n) + if (pthread_join (thwr[n], &res) != 0) + { + puts ("writer join failed"); + exit (1); + } + for (n = 0; n < NREADERS; ++n) + if (pthread_join (thrd[n], &res) != 0) + { + puts ("reader join failed"); + exit (1); + } + + return 0; +} + +#define TIMEOUT 30 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-rwlock9.c b/test/nptl/tst-rwlock9.c new file mode 100644 index 000000000..a5522ce48 --- /dev/null +++ b/test/nptl/tst-rwlock9.c @@ -0,0 +1,203 @@ +/* Test program for timedout read/write lock functions. + Copyright (C) 2000, 2003 Free Software Foundation, Inc. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + + +#define NWRITERS 15 +#define WRITETRIES 10 +#define NREADERS 15 +#define READTRIES 15 + +#define TIMEOUT 1000000 +#define DELAY 1000000 + +#ifndef INIT +# define INIT PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP +#endif + +static pthread_rwlock_t lock = INIT; + + +static void * +writer_thread (void *nr) +{ + struct timespec ts; + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < WRITETRIES; ++n) + { + int e; + do + { + struct timeval tv; + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_nsec += 2 * TIMEOUT; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + printf ("writer thread %ld tries again\n", (long int) nr); + + e = pthread_rwlock_timedwrlock (&lock, &ts); + if (e != 0 && e != ETIMEDOUT) + { + puts ("timedwrlock failed"); + exit (1); + } + } + while (e == ETIMEDOUT); + + printf ("writer thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for writer failed"); + exit (1); + } + + printf ("writer thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static void * +reader_thread (void *nr) +{ + struct timespec ts; + struct timespec delay; + int n; + + delay.tv_sec = 0; + delay.tv_nsec = DELAY; + + for (n = 0; n < READTRIES; ++n) + { + int e; + do + { + struct timeval tv; + (void) gettimeofday (&tv, NULL); + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + ts.tv_nsec += TIMEOUT; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + printf ("reader thread %ld tries again\n", (long int) nr); + + e = pthread_rwlock_timedrdlock (&lock, &ts); + if (e != 0 && e != ETIMEDOUT) + { + puts ("timedrdlock failed"); + exit (1); + } + } + while (e == ETIMEDOUT); + + printf ("reader thread %ld succeeded\n", (long int) nr); + + nanosleep (&delay, NULL); + + if (pthread_rwlock_unlock (&lock) != 0) + { + puts ("unlock for reader failed"); + exit (1); + } + + printf ("reader thread %ld released\n", (long int) nr); + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t thwr[NWRITERS]; + pthread_t thrd[NREADERS]; + int n; + void *res; + + /* Make standard error the same as standard output. */ + dup2 (1, 2); + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + for (n = 0; n < NWRITERS; ++n) + if (pthread_create (&thwr[n], NULL, writer_thread, + (void *) (long int) n) != 0) + { + puts ("writer create failed"); + exit (1); + } + + for (n = 0; n < NREADERS; ++n) + if (pthread_create (&thrd[n], NULL, reader_thread, + (void *) (long int) n) != 0) + { + puts ("reader create failed"); + exit (1); + } + + /* Wait for all the threads. */ + for (n = 0; n < NWRITERS; ++n) + if (pthread_join (thwr[n], &res) != 0) + { + puts ("writer join failed"); + exit (1); + } + for (n = 0; n < NREADERS; ++n) + if (pthread_join (thrd[n], &res) != 0) + { + puts ("reader join failed"); + exit (1); + } + + return 0; +} + +#undef TIMEOUT +#define TIMEOUT 30 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sched1.c b/test/nptl/tst-sched1.c new file mode 100644 index 000000000..4d0702c79 --- /dev/null +++ b/test/nptl/tst-sched1.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> + + +static int global; + +static void * +tf (void *a) +{ + global = 1; + + return 0; +} + + +int +do_test (void) +{ + pthread_t th; + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setschedpolicy (&at, SCHED_OTHER) != 0) + { + puts ("attr_setschedpolicy failed"); + return 1; + } + + struct sched_param pa; + if (sched_getparam (getpid (), &pa) != 0) + { + puts ("sched_getschedparam failed"); + return 1; + } + + if (pthread_attr_setschedparam (&at, &pa) != 0) + { + puts ("attr_setschedparam failed"); + return 1; + } + + if (pthread_attr_setinheritsched (&at, PTHREAD_EXPLICIT_SCHED) != 0) + { + puts ("attr_setinheritsched failed"); + return 1; + } + + if (pthread_create (&th, &at, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + int e = pthread_join (th, NULL); + if (e != 0) + { + printf ("join failed: %d\n", e); + return 1; + } + + if (global == 0) + { + puts ("thread didn't run"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem1.c b/test/nptl/tst-sem1.c new file mode 100644 index 000000000..32d59eb36 --- /dev/null +++ b/test/nptl/tst-sem1.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + sem_t s; + + if (sem_init (&s, 0, 1) == -1) + { + puts ("init failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("1st wait failed"); + return 1; + } + + if (sem_post (&s) == -1) + { + puts ("1st post failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_trywait (&s)) == -1) + { + puts ("1st trywait failed"); + return 1; + } + + errno = 0; + if (TEMP_FAILURE_RETRY (sem_trywait (&s)) != -1) + { + puts ("2nd trywait succeeded"); + return 1; + } + else if (errno != EAGAIN) + { + puts ("2nd trywait did not set errno to EAGAIN"); + return 1; + } + + if (sem_post (&s) == -1) + { + puts ("2nd post failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("2nd wait failed"); + return 1; + } + + if (sem_destroy (&s) == -1) + { + puts ("destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem2.c b/test/nptl/tst-sem2.c new file mode 100644 index 000000000..026939ef9 --- /dev/null +++ b/test/nptl/tst-sem2.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + sem_t s; + + if (sem_init (&s, 0, 0) == -1) + { + puts ("init failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("wait failed"); + return 1; + } + + /* We should never get here. */ + puts ("wait succeeded"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem3.c b/test/nptl/tst-sem3.c new file mode 100644 index 000000000..91b9f0877 --- /dev/null +++ b/test/nptl/tst-sem3.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +int +main (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-sem3.XXXXXX"; + char data[ps]; + void *mem; + int fd; + sem_t *s; + pid_t pid; + char *p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + exit (1); + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + exit (1); + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + exit (1); + } + + s = (sem_t *) (((uintptr_t) mem + __alignof (sem_t)) + & ~(__alignof (sem_t) - 1)); + p = (char *) (s + 1); + + if (sem_init (s, 1, 1) == -1) + { + puts ("init failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + puts ("1st wait failed"); + exit (1); + } + + errno = 0; + if (TEMP_FAILURE_RETRY (sem_trywait (s)) != -1) + { + puts ("trywait succeeded"); + exit (1); + } + else if (errno != EAGAIN) + { + puts ("trywait didn't return EAGAIN"); + exit (1); + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + exit (1); + } + + if (sem_post (s) == -1) + { + puts ("child: 1st post failed"); + exit (1); + } + + puts ("child done"); + } + else + { + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + printf ("parent: 2nd wait failed: %m\n"); + exit (1); + } + + if (*p != 1) + { + puts ("*p != 1"); + exit (1); + } + + puts ("parent done"); + } + + exit (0); +} diff --git a/test/nptl/tst-sem4.c b/test/nptl/tst-sem4.c new file mode 100644 index 000000000..ccffbdd77 --- /dev/null +++ b/test/nptl/tst-sem4.c @@ -0,0 +1,147 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + sem_t *s2; + pid_t pid; + int val; + + s = sem_open ("/glibc-tst-sem4", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + on_exit (remove_sem, (void *) "/glibc-tst-sem4"); + + /* We have the semaphore object. Now try again with O_EXCL, this + should fail. */ + s2 = sem_open ("/glibc-tst-sem4", O_CREAT | O_EXCL, 0600, 1); + if (s2 != SEM_FAILED) + { + puts ("2nd sem_open didn't fail"); + return 1; + } + if (errno != EEXIST) + { + puts ("2nd sem_open returned wrong error"); + return 1; + } + + /* Check the value. */ + if (sem_getvalue (s, &val) == -1) + { + puts ("getvalue failed"); + return 1; + } + if (val != 1) + { + printf ("initial value wrong: got %d, expected 1\n", val); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + puts ("1st sem_wait failed"); + return 1; + } + + pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid == 0) + { + /* Child. */ + + /* Check the value. */ + if (sem_getvalue (s, &val) == -1) + { + puts ("child: getvalue failed"); + return 1; + } + if (val != 0) + { + printf ("child: value wrong: got %d, expect 0\n", val); + return 1; + } + + if (sem_post (s) == -1) + { + puts ("child: post failed"); + return 1; + } + } + else + { + if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1) + { + puts ("2nd sem_wait failed"); + return 1; + } + + if (sem_getvalue (s, &val) == -1) + { + puts ("parent: 2nd getvalue failed"); + return 1; + } + if (val != 0) + { + printf ("parent: value wrong: got %d, expected 0\n", val); + return 1; + } + } + + return 0; +} diff --git a/test/nptl/tst-sem5.c b/test/nptl/tst-sem5.c new file mode 100644 index 000000000..cb85b8e76 --- /dev/null +++ b/test/nptl/tst-sem5.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <semaphore.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + + +static int +do_test (void) +{ + sem_t s; + struct timespec ts; + struct timeval tv; + + if (sem_init (&s, 0, 1) == -1) + { + puts ("sem_init failed"); + return 1; + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) == -1) + { + puts ("sem_wait failed"); + return 1; + } + + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + return 1; + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + + /* We wait for half a second. */ + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + + 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; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem6.c b/test/nptl/tst-sem6.c new file mode 100644 index 000000000..49240d962 --- /dev/null +++ b/test/nptl/tst-sem6.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static void +handler (int sig) +{ + struct sigaction sa; + + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGALRM, &sa, NULL); + + /* Rearm the timer. */ + alarm (1); +} + + +static int +do_test (void) +{ + sem_t s; + struct sigaction sa; + + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (SIGALRM, &sa, NULL); + + if (sem_init (&s, 0, 0) == -1) + { + puts ("init failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + int res = sem_wait (&s); + if (res == 0) + { + puts ("wait succeeded"); + return 1; + } + if (res != -1 || errno != EINTR) + { + puts ("wait didn't fail with EINTR"); + return 1; + } + + return 0; +} + +#define TIMEOUT 3 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sem7.c b/test/nptl/tst-sem7.c new file mode 100644 index 000000000..a85c73e71 --- /dev/null +++ b/test/nptl/tst-sem7.c @@ -0,0 +1,109 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + sem_t *s2; + sem_t *s3; + + s = sem_open ("/glibc-tst-sem7", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + on_exit (remove_sem, (void *) "/glibc-tst-sem7"); + + /* We have the semaphore object. Now try again. We should get the + same address. */ + s2 = sem_open ("/glibc-tst-sem7", O_CREAT, 0600, 1); + if (s2 == SEM_FAILED) + { + puts ("2nd sem_open failed"); + return 1; + } + if (s != s2) + { + puts ("2nd sem_open didn't return the same address"); + return 1; + } + + /* And again, this time without O_CREAT. */ + s3 = sem_open ("/glibc-tst-sem7", 0); + if (s3 == SEM_FAILED) + { + puts ("3rd sem_open failed"); + return 1; + } + if (s != s3) + { + puts ("3rd sem_open didn't return the same address"); + return 1; + } + + /* Now close the handle. Three times. */ + if (sem_close (s2) != 0) + { + puts ("1st sem_close failed"); + return 1; + } + if (sem_close (s) != 0) + { + puts ("2nd sem_close failed"); + return 1; + } + if (sem_close (s3) != 0) + { + puts ("3rd sem_close failed"); + return 1; + } + + return 0; +} diff --git a/test/nptl/tst-sem8.c b/test/nptl/tst-sem8.c new file mode 100644 index 000000000..5dea575e9 --- /dev/null +++ b/test/nptl/tst-sem8.c @@ -0,0 +1,74 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + int i; + + on_exit (remove_sem, (void *) "/glibc-tst-sem8"); + + for (i = 0; i < 3; ++i) + { + s = sem_open ("/glibc-tst-sem8", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + /* Now close the handle. */ + if (sem_close (s) != 0) + { + puts ("sem_close failed"); + return 1; + } + } + + return 0; +} diff --git a/test/nptl/tst-sem9.c b/test/nptl/tst-sem9.c new file mode 100644 index 000000000..cdd8eaa30 --- /dev/null +++ b/test/nptl/tst-sem9.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <fcntl.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void +remove_sem (int status, void *arg) +{ + sem_unlink (arg); +} + + +int +main (void) +{ + sem_t *s; + int i; + + on_exit (remove_sem, (void *) "/glibc-tst-sem9"); + + for (i = 0; i < 3; ++i) + { + s = sem_open ("/glibc-tst-sem9", O_CREAT, 0600, 1); + if (s == SEM_FAILED) + { + if (errno == ENOSYS) + { + puts ("sem_open not supported. Oh well."); + return 0; + } + + /* Maybe the shm filesystem has strict permissions. */ + if (errno == EACCES) + { + puts ("sem_open not allowed. Oh well."); + return 0; + } + + printf ("sem_open: %m\n"); + return 1; + } + + /* Now close the handle. */ + if (sem_close (s) != 0) + { + puts ("sem_close failed"); + return 1; + } + + /* And remove it. */ + if (sem_unlink ("/glibc-tst-sem9") != 0) + { + puts ("sem_unlink failed"); + return 1; + } + } + + return 0; +} diff --git a/test/nptl/tst-signal1.c b/test/nptl/tst-signal1.c new file mode 100644 index 000000000..3022f1846 --- /dev/null +++ b/test/nptl/tst-signal1.c @@ -0,0 +1,189 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static sigset_t ss; +static pthread_barrier_t *b; + + +static void * +tf (void *arg) +{ + sigdelset (&ss, SIGINT); + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("2nd pthread_sigmask failed"); + exit (1); + } + + pthread_barrier_wait (b); + + int sig; + int res = sigwait (&ss, &sig); + if (res == 0) + { + printf ("sigwait returned successfully with signal %d\n", sig); + exit (1); + } + + printf ("sigwait returned with %s (%d)\n", strerror (res), res); + + return NULL; +} + + +static void +receiver (void) +{ + pthread_t th; + + /* Make sure the process doesn't run forever. */ + alarm (10); + + sigfillset (&ss); + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st pthread_sigmask failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + if (pthread_join (th, NULL) == 0) + { + puts ("thread joined?!"); + exit (1); + } + + _exit (0); +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-signal1-XXXXXX"; + + int fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + unlink (tmp); + + int i; + for (i = 0; i < 20; ++i) + write (fd, "foobar xyzzy", 12); + + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + { + puts ("mmap failed"); + exit (1); + } + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + exit (1); + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + exit (1); + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + receiver (); + + pthread_barrier_wait (b); + + /* Wait a bit more. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + + /* Send the signal. */ + puts ("sending the signal now"); + kill (pid, SIGINT); + + /* Wait for the process to terminate. */ + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("wrong child reported terminated"); + exit (1); + } + + if (!WIFSIGNALED (status)) + { + puts ("child wasn't signalled"); + exit (1); + } + + if (WTERMSIG (status) != SIGINT) + { + puts ("child not terminated with SIGINT"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal2.c b/test/nptl/tst-signal2.c new file mode 100644 index 000000000..3f2c75d1f --- /dev/null +++ b/test/nptl/tst-signal2.c @@ -0,0 +1,198 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> +#include <string.h> + + +static sigset_t ss; +static pthread_barrier_t *b; + + +static void * +tf (void *arg) +{ + pthread_barrier_wait (b); + + puts ("child: calling sigwait now"); + + int sig; + int err; + err = sigwait (&ss, &sig); + if (err != 0) + { + printf ("sigwait returned unsuccessfully: %s (%d)\n", + strerror (err), err); + _exit (1); + } + + puts ("sigwait returned"); + + if (sig != SIGINT) + { + printf ("caught signal %d, expected %d (SIGINT)\n", sig, SIGINT); + _exit (1); + } + + puts ("child thread terminating now"); + + return NULL; +} + + +static void +receiver (void) +{ + pthread_t th; + + /* Make sure the process doesn't run forever. */ + alarm (10); + + sigfillset (&ss); + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st pthread_sigmask failed"); + _exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("pthread_create failed"); + _exit (1); + } + + if (pthread_join (th, NULL) != 0) + { + puts ("thread didn't join"); + _exit (1); + } + + puts ("join succeeded"); + + _exit (0); +} + + +static int +do_test (void) +{ + char tmp[] = "/tmp/tst-signal1-XXXXXX"; + + int fd = mkstemp (tmp); + if (fd == -1) + { + puts ("mkstemp failed"); + exit (1); + } + + unlink (tmp); + + int i; + for (i = 0; i < 20; ++i) + write (fd, "foobar xyzzy", 12); + + b = mmap (NULL, sizeof (pthread_barrier_t), PROT_READ | PROT_WRITE, + MAP_SHARED, fd, 0); + if (b == MAP_FAILED) + { + puts ("mmap failed"); + exit (1); + } + + pthread_barrierattr_t ba; + if (pthread_barrierattr_init (&ba) != 0) + { + puts ("barrierattr_init failed"); + exit (1); + } + + if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + exit (1); + } + + if (pthread_barrier_init (b, &ba, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrierattr_destroy (&ba) != 0) + { + puts ("barrierattr_destroy failed"); + exit (1); + } + + pid_t pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + + if (pid == 0) + receiver (); + + pthread_barrier_wait (b); + + /* Wait a bit more. */ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 }; + nanosleep (&ts, NULL); + + /* Send the signal. */ + puts ("sending the signal now"); + kill (pid, SIGINT); + + /* Wait for the process to terminate. */ + int status; + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + { + puts ("wrong child reported terminated"); + exit (1); + } + + if (!WIFEXITED (status)) + { + if (WIFSIGNALED (status)) + printf ("child exited with signal %d\n", WTERMSIG (status)); + else + puts ("child didn't exit normally"); + exit (1); + } + + if (WEXITSTATUS (status) != 0) + { + printf ("exit status %d != 0\n", WEXITSTATUS (status)); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal3.c b/test/nptl/tst-signal3.c new file mode 100644 index 000000000..e4756c56a --- /dev/null +++ b/test/nptl/tst-signal3.c @@ -0,0 +1,261 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +/* Number of different signalss to use. Also is the number of + threads. */ +#define N 10 +/* Maximum number of threads in flight at any one time. */ +#define INFLIGHT 5 +/* Number of signals sent in total. */ +#define ROUNDS 10000 + + +static int received[N][N]; +static int nsig[N]; +static pthread_t th[N]; +static sem_t sem; +static pthread_mutex_t lock[N]; +static pthread_t th_main; +static int sig0; + +static void +handler (int sig) +{ + int i; + for (i = 0; i < N; ++i) + if (pthread_equal (pthread_self (), th[i])) + break; + + if (i == N) + { + if (pthread_equal (pthread_self (), th_main)) + puts ("signal received by main thread"); + else + printf ("signal received by unknown thread (%lx)\n", + (unsigned long int) pthread_self ()); + exit (1); + } + + ++received[i][sig - sig0]; + + sem_post (&sem); +} + + +static void * +tf (void *arg) +{ + int idx = (long int) arg; + + sigset_t ss; + sigemptyset (&ss); + + int i; + for (i = 0; i <= idx; ++i) + sigaddset (&ss, sig0 + i); + + if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0) + { + printf ("thread %d: pthread_sigmask failed\n", i); + exit (1); + } + + pthread_mutex_lock (&lock[idx]); + + return NULL; +} + + +static int +do_test (void) +{ + /* Block all signals. */ + sigset_t ss; + sigfillset (&ss); + + th_main = pthread_self (); + + sig0 = SIGRTMIN; + + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st pthread_sigmask failed"); + exit (1); + } + + /* Install the handler. */ + int i; + for (i = 0; i < N; ++i) + { + struct sigaction sa = + { + .sa_handler = handler, + .sa_flags = 0 + }; + sigfillset (&sa.sa_mask); + + if (sigaction (sig0 + i, &sa, NULL) != 0) + { + printf ("sigaction for signal %d failed\n", i); + exit (1); + } + } + + if (sem_init (&sem, 0, INFLIGHT) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + if (pthread_mutex_init (&lock[i], NULL) != 0) + { + printf ("mutex_init[%d] failed\n", i); + } + + if (pthread_mutex_lock (&lock[i]) != 0) + { + printf ("mutex_lock[%d] failed\n", i); + } + + if (pthread_create (&th[i], &a, tf, (void *) (long int) i) != 0) + { + printf ("create of thread %d failed\n", i); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + int result = 0; + unsigned int r = 42; + pid_t pid = getpid (); + + for (i = 0; i < ROUNDS; ++i) + { + if (TEMP_FAILURE_RETRY (sem_wait (&sem)) != 0) + { + printf ("sem_wait round %d failed: %m\n", i); + exit (1); + } + + int s = rand_r (&r) % N; + + kill (pid, sig0 + s); + } + + void *status; + for (i = 0; i < N; ++i) + { + if (pthread_mutex_unlock (&lock[i]) != 0) + { + printf ("unlock %d failed\n", i); + exit (1); + } + + if (pthread_join (th[i], &status) != 0) + { + printf ("join %d failed\n", i); + result = 1; + } + else if (status != NULL) + { + printf ("%d: result != NULL\n", i); + result = 1; + } + } + + int total = 0; + for (i = 0; i < N; ++i) + { + int j; + + for (j = 0; j <= i; ++j) + total += received[i][j]; + + for (j = i + 1; j < N; ++j) + if (received[i][j] != 0) + { + printf ("thread %d received signal SIGRTMIN+%d\n", i, j); + result = 1; + } + } + + if (total != ROUNDS) + { + printf ("total number of handled signals is %d, expected %d\n", + total, ROUNDS); + result = 1; + } + + printf ("A total of %d signals sent and received\n", total); + for (i = 0; i < N; ++i) + { + printf ("thread %2d:", i); + + int j; + for (j = 0; j <= i; ++j) + { + printf (" %5d", received[i][j]); + nsig[j] += received[i][j]; + } + + putchar ('\n'); + + } + + printf ("\nTotal :"); + for (i = 0; i < N; ++i) + printf (" %5d", nsig[i]); + putchar ('\n'); + + return result; +} + +#define TIMEOUT 10 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal4.c b/test/nptl/tst-signal4.c new file mode 100644 index 000000000..dcb2893a0 --- /dev/null +++ b/test/nptl/tst-signal4.c @@ -0,0 +1,60 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + sigset_t ss; + + sigemptyset (&ss); + + int i; + for (i = 0; i < 10000; ++i) + { + long int r = random (); + + if (r != SIG_BLOCK && r != SIG_SETMASK && r != SIG_UNBLOCK) + { + int e = pthread_sigmask (r, &ss, NULL); + + if (e == 0) + { + printf ("pthread_sigmask succeeded for how = %ld\n", r); + exit (1); + } + + if (e != EINVAL) + { + puts ("pthread_sigmask didn't return EINVAL"); + exit (1); + } + } + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal5.c b/test/nptl/tst-signal5.c new file mode 100644 index 000000000..cea6ec143 --- /dev/null +++ b/test/nptl/tst-signal5.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static sigset_t ss; + + +static void * +tf (void *arg) +{ + sigset_t ss2; + if (pthread_sigmask (SIG_SETMASK, NULL, &ss2) != 0) + { + puts ("child: sigmask failed"); + exit (1); + } + + int i; + for (i = 1; i < 32; ++i) + if (sigismember (&ss, i) && ! sigismember (&ss2, i)) + { + printf ("signal %d set in parent mask, but not in child\n", i); + exit (1); + } + else if (! sigismember (&ss, i) && sigismember (&ss2, i)) + { + printf ("signal %d set in child mask, but not in parent\n", i); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + sigemptyset (&ss); + sigaddset (&ss, SIGUSR1); + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("1st sigmask failed"); + exit (1); + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("1st join failed"); + exit (1); + } + + sigemptyset (&ss); + sigaddset (&ss, SIGUSR2); + sigaddset (&ss, SIGFPE); + if (pthread_sigmask (SIG_SETMASK, &ss, NULL) != 0) + { + puts ("2nd sigmask failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("2nd create failed"); + exit (1); + } + + if (pthread_join (th, &r) != 0) + { + puts ("2nd join failed"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-signal6.c b/test/nptl/tst-signal6.c new file mode 100644 index 000000000..85a864002 --- /dev/null +++ b/test/nptl/tst-signal6.c @@ -0,0 +1,192 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +#define N 2 +static pthread_barrier_t bar; +static struct +{ + void *p; + pthread_t s; +} ti[N]; +static int sig1; + + +static void +handler (int sig) +{ + pthread_t self = pthread_self (); + size_t i; + + for (i = 0; i < N; ++i) + if (ti[i].s == self) + { + if ((uintptr_t) ti[i].p <= (uintptr_t) &self + && (uintptr_t) ti[i].p + 2 * MINSIGSTKSZ > (uintptr_t) &self) + { + puts ("alt stack not used"); + exit (1); + } + + printf ("thread %zu used alt stack for signal %d\n", i, sig); + + return; + } + + puts ("handler: thread not found"); + exit (1); +} + + +static void * +tf (void *arg) +{ + size_t nr = (uintptr_t) arg; + if (nr >= N) + { + puts ("wrong nr parameter"); + exit (1); + } + + sigset_t ss; + sigemptyset (&ss); + size_t i; + for (i = 0; i < N; ++i) + if (i != nr) + if (sigaddset (&ss, sig1 + i) != 0) + { + puts ("tf: sigaddset failed"); + exit (1); + } + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("tf: sigmask failed"); + exit (1); + } + + void *p = malloc (2 * MINSIGSTKSZ); + if (p == NULL) + { + puts ("tf: malloc failed"); + exit (1); + } + + stack_t s; + s.ss_sp = p; + s.ss_size = 2 * MINSIGSTKSZ; + s.ss_flags = 0; + if (sigaltstack (&s, NULL) != 0) + { + puts ("tf: sigaltstack failed"); + exit (1); + } + + ti[nr].p = p; + ti[nr].s = pthread_self (); + + pthread_barrier_wait (&bar); + + pthread_barrier_wait (&bar); + + return NULL; +} + + +static int +do_test (void) +{ + sig1 = SIGRTMIN; + if (sig1 + N > SIGRTMAX) + { + puts ("too few RT signals"); + return 0; + } + + struct sigaction sa; + sa.sa_handler = handler; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + if (sigaction (sig1, &sa, NULL) != 0 + || sigaction (sig1 + 1, &sa, NULL) != 0 + || sigaction (sig1 + 2, &sa, NULL) != 0) + { + puts ("sigaction failed"); + return 1; + } + + if (pthread_barrier_init (&bar, NULL, 1 + N) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th[N]; + size_t i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], NULL, tf, (void *) (long int) i) != 0) + { + puts ("create failed"); + return 1; + } + + /* Block the three signals. */ + sigset_t ss; + sigemptyset (&ss); + for (i = 0; i <= N; ++i) + sigaddset (&ss, sig1 + i); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("main: sigmask failed"); + return 1; + } + + pthread_barrier_wait (&bar); + + /* Send some signals. */ + pid_t me = getpid (); + kill (me, sig1 + N); + for (i = 0; i < N; ++i) + kill (me, sig1 + i); + kill (me, sig1 + N); + + /* Give the signals a chance to be worked on. */ + sleep (1); + + pthread_barrier_wait (&bar); + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-spin1.c b/test/nptl/tst-spin1.c new file mode 100644 index 000000000..259b4b4d6 --- /dev/null +++ b/test/nptl/tst-spin1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> + + +static int +do_test (void) +{ + pthread_spinlock_t s; + + if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("spin_init failed"); + return 1; + } + + if (pthread_spin_lock (&s) != 0) + { + puts ("spin_lock failed"); + return 1; + } + + if (pthread_spin_unlock (&s) != 0) + { + puts ("spin_unlock failed"); + return 1; + } + + if (pthread_spin_destroy (&s) != 0) + { + puts ("spin_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-spin2.c b/test/nptl/tst-spin2.c new file mode 100644 index 000000000..5b1df6c4a --- /dev/null +++ b/test/nptl/tst-spin2.c @@ -0,0 +1,159 @@ +/* Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <errno.h> +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-spin2.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_spinlock_t *s; + pid_t pid; + char *p; + int err; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + s = (pthread_spinlock_t *) (((uintptr_t) mem + + __alignof (pthread_spinlock_t)) + & ~(__alignof (pthread_spinlock_t) - 1)); + p = (char *) (s + 1); + + if (pthread_spin_init (s, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("spin_init failed"); + return 1; + } + + if (pthread_spin_lock (s) != 0) + { + puts ("spin_lock failed"); + return 1; + } + + err = pthread_spin_trylock (s); + if (err == 0) + { + puts ("1st spin_trylock succeeded"); + return 1; + } + else if (err != EBUSY) + { + puts ("1st spin_trylock didn't return EBUSY"); + return 1; + } + + err = pthread_spin_unlock (s); + if (err != 0) + { + puts ("parent: spin_unlock failed"); + return 1; + } + + err = pthread_spin_trylock (s); + if (err != 0) + { + puts ("2nd spin_trylock failed"); + return 1; + } + + *p = 0; + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + /* Play some lock ping-pong. It's our turn to unlock first. */ + if ((*p)++ != 0) + { + puts ("child: *p != 0"); + return 1; + } + + if (pthread_spin_unlock (s) != 0) + { + puts ("child: 1st spin_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + if (pthread_spin_lock (s) != 0) + { + puts ("parent: 2nd spin_lock failed"); + return 1; + } + + puts ("waiting for child"); + + waitpid (pid, NULL, 0); + + puts ("parent done"); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-spin3.c b/test/nptl/tst-spin3.c new file mode 100644 index 000000000..443774032 --- /dev/null +++ b/test/nptl/tst-spin3.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + pthread_spinlock_t s; + + if (pthread_spin_init (&s, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("spin_init failed"); + return 1; + } + + if (pthread_spin_lock (&s) != 0) + { + puts ("1st spin_lock failed"); + return 1; + } + + /* Set an alarm for 1 second. The wrapper will expect this. */ + alarm (1); + + /* This call should never return. */ + pthread_spin_lock (&s); + + puts ("2nd spin_lock returned"); + return 1; +} + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stack-align.h b/test/nptl/tst-stack-align.h new file mode 100644 index 000000000..59b1e656a --- /dev/null +++ b/test/nptl/tst-stack-align.h @@ -0,0 +1,35 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <stdio.h> +#include <stdint.h> + +#define TEST_STACK_ALIGN() \ + ({ \ + double _d = 12.0; \ + long double _ld = 15.0; \ + int _ret = 0; \ + printf ("double: %g %p %zu\n", _d, &_d, __alignof (double)); \ + if ((((uintptr_t) &_d) & (__alignof (double) - 1)) != 0) \ + _ret = 1; \ + \ + printf ("ldouble: %Lg %p %zu\n", _ld, &_ld, __alignof (long double)); \ + if ((((uintptr_t) &_ld) & (__alignof (long double) - 1)) != 0) \ + _ret = 1; \ + _ret; \ + }) diff --git a/test/nptl/tst-stack1.c b/test/nptl/tst-stack1.c new file mode 100644 index 000000000..93405981d --- /dev/null +++ b/test/nptl/tst-stack1.c @@ -0,0 +1,146 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/param.h> +#include <unistd.h> + + +static void *stack; +static size_t size; + + +static void * +tf (void *a) +{ + int result = 0; + + puts ("child start"); + + pthread_attr_t attr; + if (pthread_getattr_np (pthread_self (), &attr) != 0) + { + puts ("getattr_np failed"); + exit (1); + } + + size_t test_size; + void *test_stack; + if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0) + { + puts ("attr_getstack failed"); + exit (1); + } + + if (test_size != size) + { + printf ("child: reported size differs: is %zu, expected %zu\n", + test_size, size); + result = 1; + } + + if (test_stack != stack) + { + printf ("child: reported stack address differs: is %p, expected %p\n", + test_stack, stack); + result = 1; + } + + puts ("child OK"); + + return result ? (void *) 1l : NULL; +} + + +int +do_test (void) +{ + int result = 0; + + size = MAX (4 * getpagesize (), PTHREAD_STACK_MIN); + if (posix_memalign (&stack, getpagesize (), size) != 0) + { + puts ("out of memory while allocating the stack memory"); + exit (1); + } + + pthread_attr_t attr; + if (pthread_attr_init (&attr) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + puts ("attr_setstack"); + if (pthread_attr_setstack (&attr, stack, size) != 0) + { + puts ("attr_setstack failed"); + exit (1); + } + + size_t test_size; + void *test_stack; + puts ("attr_getstack"); + if (pthread_attr_getstack (&attr, &test_stack, &test_size) != 0) + { + puts ("attr_getstack failed"); + exit (1); + } + + if (test_size != size) + { + printf ("reported size differs: is %zu, expected %zu\n", + test_size, size); + result = 1; + } + + if (test_stack != stack) + { + printf ("reported stack address differs: is %p, expected %p\n", + test_stack, stack); + result = 1; + } + + puts ("create"); + + pthread_t th; + if (pthread_create (&th, &attr, tf, NULL) != 0) + { + puts ("failed to create thread"); + exit (1); + } + + void *status; + if (pthread_join (th, &status) != 0) + { + puts ("join failed"); + exit (1); + } + + result |= status != NULL; + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stack2.c b/test/nptl/tst-stack2.c new file mode 100644 index 000000000..5fcdb18d0 --- /dev/null +++ b/test/nptl/tst-stack2.c @@ -0,0 +1,80 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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. */ + +/* Test whether it is possible to create a thread with PTHREAD_STACK_MIN + stack size. */ + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> + +static int seen; + +static void * +tf (void *p) +{ + ++seen; + return NULL; +} + +static int +do_test (void) +{ + pthread_attr_t attr; + pthread_attr_init (&attr); + + int result = 0; + int res = pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN); + if (res) + { + printf ("pthread_attr_setstacksize failed %d\n", res); + result = 1; + } + + /* Create the thread. */ + pthread_t th; + res = pthread_create (&th, &attr, tf, NULL); + if (res) + { + printf ("pthread_create failed %d\n", res); + result = 1; + } + else + { + res = pthread_join (th, NULL); + if (res) + { + printf ("pthread_join failed %d\n", res); + result = 1; + } + } + + if (seen != 1) + { + printf ("seen %d != 1\n", seen); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stdio1.c b/test/nptl/tst-stdio1.c new file mode 100644 index 000000000..ebb3e2f0b --- /dev/null +++ b/test/nptl/tst-stdio1.c @@ -0,0 +1,57 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <unistd.h> + + +static void *tf (void *a) +{ + flockfile (stdout); + /* This call should never return. */ + return a; +} + + +int +do_test (void) +{ + pthread_t th; + + flockfile (stdout); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + pthread_join (th, NULL); + + puts ("join returned"); + + return 0; +} + + +#define EXPECTED_SIGNAL SIGALRM +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-stdio2.c b/test/nptl/tst-stdio2.c new file mode 100644 index 000000000..08d6addf4 --- /dev/null +++ b/test/nptl/tst-stdio2.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static void *tf (void *a) +{ + puts ("start tf"); + + /* Multiple locking, implicitly or explicitly, must be possible. */ + flockfile (stdout); + + puts ("after first flockfile"); + + flockfile (stdout); + + puts ("foo"); + + funlockfile (stdout); + + puts ("after first funlockfile"); + + funlockfile (stdout); + + puts ("all done"); + + return a; +} + + +int +do_test (void) +{ + pthread_t th; + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + write (2, "create failed\n", 14); + _exit (1); + } + + void *result; + if (pthread_join (th, &result) != 0) + { + puts ("join failed"); + exit (1); + } + else if (result != NULL) + { + printf ("wrong return value: %p, expected %p\n", result, NULL); + exit (1); + } + + puts ("join returned succsefully"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-sysconf.c b/test/nptl/tst-sysconf.c new file mode 100644 index 000000000..3ad1b6a3c --- /dev/null +++ b/test/nptl/tst-sysconf.c @@ -0,0 +1,48 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> + + +static int +do_test (void) +{ + puts ("We expect no limits"); + /* We have no fixed limit on the number of threads. Make sure the + headers tell the right story. */ +#ifdef PTHREAD_THREADS_MAX + printf ("Header report maximum number of threads = %lu\n", + (unsigned long int) PTHREAD_THREADS_MAX); + return 1; +#else + long int r = sysconf (_SC_THREAD_THREADS_MAX); + if (r != -1) + { + printf ("sysconf(_SC_THREAD_THREADS_MAX) return %ld\n", r); + return 1; + } +#endif + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer2.c b/test/nptl/tst-timer2.c new file mode 100644 index 000000000..60026c1ef --- /dev/null +++ b/test/nptl/tst-timer2.c @@ -0,0 +1,65 @@ +/* Test for crashing bugs when trying to create too many timers. */ + +#include <stdio.h> +#include <time.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> + +#if _POSIX_THREADS +# include <pthread.h> + +void +thread (union sigval arg) +{ + puts ("Timeout"); +} + +int +do_test (void) +{ + int i, res; + timer_t timerId; + struct itimerspec itval; + struct sigevent sigev; + + itval.it_interval.tv_sec = 2; + itval.it_interval.tv_nsec = 0; + itval.it_value.tv_sec = 2; + itval.it_value.tv_nsec = 0; + + sigev.sigev_notify = SIGEV_THREAD; + sigev.sigev_signo = SIGRTMIN; + sigev.sigev_notify_function = thread; + sigev.sigev_notify_attributes = 0; + sigev.sigev_value.sival_ptr = (void *) &timerId; + + for (i = 0; i < 100; i++) + { + printf ("cnt = %d\n", i); + + if (timer_create (CLOCK_REALTIME, &sigev, &timerId) < 0) + { + perror ("timer_create"); + continue; + } + + res = timer_settime (timerId, 0, &itval, NULL); + if (res < 0) + perror ("timer_settime"); + + res = timer_delete (timerId); + if (res < 0) + perror ("timer_delete"); + } + + return 0; +} + +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer3.c b/test/nptl/tst-timer3.c new file mode 100644 index 000000000..8113f6690 --- /dev/null +++ b/test/nptl/tst-timer3.c @@ -0,0 +1,86 @@ +/* Test for bogus per-thread deletion of timers. */ + +#include <stdio.h> +#include <error.h> +#include <time.h> +#include <signal.h> +#include <stdint.h> +#include <string.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + + +/* Creating timers in another thread should work too. */ +static void * +do_timer_create (void *arg) +{ + struct sigevent *const sigev = arg; + timer_t *const timerId = sigev->sigev_value.sival_ptr; + if (timer_create (CLOCK_REALTIME, sigev, timerId) < 0) + { + printf ("timer_create: %m\n"); + return NULL; + } + return timerId; +} + + +static int +do_test (void) +{ + int i, res; + timer_t timerId; + struct itimerspec itval; + struct sigevent sigev; + + itval.it_interval.tv_sec = 2; + itval.it_interval.tv_nsec = 0; + itval.it_value.tv_sec = 2; + itval.it_value.tv_nsec = 0; + + sigev.sigev_notify = SIGEV_SIGNAL; + sigev.sigev_signo = SIGALRM; + sigev.sigev_value.sival_ptr = (void *) &timerId; + + for (i = 0; i < 100; i++) + { + printf ("cnt = %d\n", i); + + pthread_t thr; + res = pthread_create (&thr, NULL, &do_timer_create, &sigev); + if (res) + { + printf ("pthread_create: %s\n", strerror (res)); + continue; + } + void *val; + res = pthread_join (thr, &val); + if (res) + { + printf ("pthread_join: %s\n", strerror (res)); + continue; + } + if (val == NULL) + continue; + + res = timer_settime (timerId, 0, &itval, NULL); + if (res < 0) + printf ("timer_settime: %m\n"); + + res = timer_delete (timerId); + if (res < 0) + printf ("timer_delete: %m\n"); + } + + return 0; +} + +# define TEST_FUNCTION do_test () +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer4.c b/test/nptl/tst-timer4.c new file mode 100644 index 000000000..5bec01181 --- /dev/null +++ b/test/nptl/tst-timer4.c @@ -0,0 +1,648 @@ +/* Tests for POSIX timer implementation. + Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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; 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 <errno.h> +#include <signal.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#if _POSIX_THREADS +# include <pthread.h> + +# ifndef TEST_CLOCK +# define TEST_CLOCK CLOCK_REALTIME +# endif + +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2; + +int thr1_cnt, thr1_err; +union sigval thr1_sigval; +struct timespec thr1_ts; + +static void +thr1 (union sigval sigval) +{ + pthread_mutex_lock (&lock); + thr1_err = clock_gettime (TEST_CLOCK, &thr1_ts); + if (thr1_cnt >= 5) + { + struct itimerspec it = { }; + thr1_err |= timer_settime (timer_thr1, 0, &it, NULL); + } + thr1_sigval = sigval; + ++thr1_cnt; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&lock); +} + +int thr2_cnt, thr2_err; +union sigval thr2_sigval; +size_t thr2_guardsize; +struct timespec thr2_ts; + +static void +thr2 (union sigval sigval) +{ + pthread_attr_t nattr; + int err = 0; + size_t guardsize = -1; + int ret = pthread_getattr_np (pthread_self (), &nattr); + if (ret) + { + errno = ret; + printf ("*** pthread_getattr_np failed: %m\n"); + err = 1; + } + else + { + ret = pthread_attr_getguardsize (&nattr, &guardsize); + if (ret) + { + errno = ret; + printf ("*** pthread_attr_getguardsize failed: %m\n"); + err = 1; + } + if (pthread_attr_destroy (&nattr) != 0) + { + puts ("*** pthread_attr_destroy failed"); + err = 1; + } + } + pthread_mutex_lock (&lock); + thr2_err = clock_gettime (TEST_CLOCK, &thr2_ts) | err; + if (thr2_cnt >= 5) + { + struct itimerspec it = { }; + thr2_err |= timer_settime (timer_thr2, 0, &it, NULL); + } + thr2_sigval = sigval; + ++thr2_cnt; + thr2_guardsize = guardsize; + pthread_cond_signal (&cond); + pthread_mutex_unlock (&lock); +} + +volatile int sig1_cnt, sig1_err; +volatile union sigval sig1_sigval; +struct timespec sig1_ts; + +static void +sig1_handler (int sig, siginfo_t *info, void *ctx) +{ + int err = 0; + if (sig != SIGRTMIN) err |= 1 << 0; + if (info->si_signo != SIGRTMIN) err |= 1 << 1; + if (info->si_code != SI_TIMER) err |= 1 << 2; + if (clock_gettime (TEST_CLOCK, &sig1_ts) != 0) + err |= 1 << 3; + if (sig1_cnt >= 5) + { + struct itimerspec it = { }; + if (timer_settime (timer_sig1, 0, &it, NULL)) + err |= 1 << 4; + } + sig1_err |= err; + sig1_sigval = info->si_value; + ++sig1_cnt; +} + +volatile int sig2_cnt, sig2_err; +volatile union sigval sig2_sigval; +struct timespec sig2_ts; + +static void +sig2_handler (int sig, siginfo_t *info, void *ctx) +{ + int err = 0; + if (sig != SIGRTMIN + 1) err |= 1 << 0; + if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1; + if (info->si_code != SI_TIMER) err |= 1 << 2; + if (clock_gettime (TEST_CLOCK, &sig2_ts) != 0) + err |= 1 << 3; + if (sig2_cnt >= 5) + { + struct itimerspec it = { }; + if (timer_settime (timer_sig2, 0, &it, NULL)) + err |= 1 << 4; + } + sig2_err |= err; + sig2_sigval = info->si_value; + ++sig2_cnt; +} + +/* Check if end is later or equal to start + nsec. */ +static int +check_ts (const char *name, const struct timespec *start, + const struct timespec *end, long msec) +{ + struct timespec ts = *start; + + ts.tv_sec += msec / 1000000; + ts.tv_nsec += (msec % 1000000) * 1000; + if (ts.tv_nsec >= 1000000000) + { + ++ts.tv_sec; + ts.tv_nsec -= 1000000000; + } + if (end->tv_sec < ts.tv_sec + || (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec)) + { + printf ("\ +*** timer %s invoked too soon: %ld.%09ld instead of expected %ld.%09ld\n", + name, (long) end->tv_sec, end->tv_nsec, + (long) ts.tv_sec, ts.tv_nsec); + return 1; + } + else + return 0; +} + +#define TIMEOUT 15 +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ + int result = 0; + +#ifdef TEST_CLOCK_MISSING + const char *missing = TEST_CLOCK_MISSING (TEST_CLOCK); + if (missing != NULL) + { + printf ("%s missing, skipping test\n", missing); + return 0; + } +#endif + + struct timespec ts; + if (clock_gettime (TEST_CLOCK, &ts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + else + printf ("clock_gettime returned timespec = { %ld, %ld }\n", + (long) ts.tv_sec, ts.tv_nsec); + + if (clock_getres (TEST_CLOCK, &ts) != 0) + { + printf ("*** clock_getres failed: %m\n"); + result = 1; + } + else + printf ("clock_getres returned timespec = { %ld, %ld }\n", + (long) ts.tv_sec, ts.tv_nsec); + + struct sigevent ev; + memset (&ev, 0x11, sizeof (ev)); + ev.sigev_notify = SIGEV_NONE; + if (timer_create (TEST_CLOCK, &ev, &timer_none) != 0) + { + printf ("*** timer_create for timer_none failed: %m\n"); + return 1; + } + + struct sigaction sa = { .sa_sigaction = sig1_handler, + .sa_flags = SA_SIGINFO }; + sigemptyset (&sa.sa_mask); + sigaction (SIGRTMIN, &sa, NULL); + sa.sa_sigaction = sig2_handler; + sigaction (SIGRTMIN + 1, &sa, NULL); + + memset (&ev, 0x22, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN; + ev.sigev_value.sival_ptr = &ev; + if (timer_create (TEST_CLOCK, &ev, &timer_sig1) != 0) + { + printf ("*** timer_create for timer_sig1 failed: %m\n"); + return 1; + } + + memset (&ev, 0x33, sizeof (ev)); + ev.sigev_notify = SIGEV_SIGNAL; + ev.sigev_signo = SIGRTMIN + 1; + ev.sigev_value.sival_int = 163; + if (timer_create (TEST_CLOCK, &ev, &timer_sig2) != 0) + { + printf ("*** timer_create for timer_sig2 failed: %m\n"); + return 1; + } + + memset (&ev, 0x44, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = thr1; + ev.sigev_notify_attributes = NULL; + ev.sigev_value.sival_ptr = &ev; + if (timer_create (TEST_CLOCK, &ev, &timer_thr1) != 0) + { + printf ("*** timer_create for timer_thr1 failed: %m\n"); + return 1; + } + + pthread_attr_t nattr; + if (pthread_attr_init (&nattr) + || pthread_attr_setguardsize (&nattr, 0)) + { + puts ("*** pthread_attr_t setup failed"); + result = 1; + } + + memset (&ev, 0x55, sizeof (ev)); + ev.sigev_notify = SIGEV_THREAD; + ev.sigev_notify_function = thr2; + ev.sigev_notify_attributes = &nattr; + ev.sigev_value.sival_int = 111; + if (timer_create (TEST_CLOCK, &ev, &timer_thr2) != 0) + { + printf ("*** timer_create for timer_thr2 failed: %m\n"); + return 1; + } + + int ret = timer_getoverrun (timer_thr1); + if (ret != 0) + { + if (ret == -1) + printf ("*** timer_getoverrun failed: %m\n"); + else + printf ("*** timer_getoverrun returned %d != 0\n", ret); + result = 1; + } + + struct itimerspec it; + it.it_value.tv_sec = 0; + it.it_value.tv_nsec = -26; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 0; + if (timer_settime (timer_sig1, 0, &it, NULL) == 0) + { + puts ("*** timer_settime with negative tv_nsec unexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("*** timer_settime with negative tv_nsec did not fail with " + "EINVAL: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000; + it.it_interval.tv_nsec = 1000000000; + if (timer_settime (timer_sig2, 0, &it, NULL) == 0) + { + puts ("\ +*** timer_settime with tv_nsec 1000000000 unexpectedly succeeded"); + result = 1; + } + else if (errno != EINVAL) + { + printf ("*** timer_settime with tv_nsec 1000000000 did not fail with " + "EINVAL: %m\n"); + result = 1; + } + +#if 0 + it.it_value.tv_nsec = 0; + it.it_interval.tv_nsec = -26; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("\ +!!! timer_settime with it_value 0 it_interval invalid failed: %m\n"); + /* FIXME: is this mandated by POSIX? + result = 1; */ + } + + it.it_interval.tv_nsec = 3000000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("\ +!!! timer_settime with it_value 0 it_interval invalid failed: %m\n"); + /* FIXME: is this mandated by POSIX? + result = 1; */ + } +#endif + + struct timespec startts; + if (clock_gettime (TEST_CLOCK, &startts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000000; + it.it_interval.tv_nsec = 0; + if (timer_settime (timer_none, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_none failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 200000000; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 300000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr2 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 400000000; + if (timer_settime (timer_sig1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_sig1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 500000000; + if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0) + { + printf ("*** timer_settime timer_sig2 failed: %m\n"); + result = 1; + } + + pthread_mutex_lock (&lock); + while (thr1_cnt == 0 || thr2_cnt == 0) + pthread_cond_wait (&cond, &lock); + pthread_mutex_unlock (&lock); + + while (sig1_cnt == 0 || sig2_cnt == 0) + { + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + + pthread_mutex_lock (&lock); + + if (thr1_cnt != 1) + { + printf ("*** thr1 not called exactly once, but %d times\n", thr1_cnt); + result = 1; + } + else if (thr1_err) + { + puts ("*** an error occurred in thr1"); + result = 1; + } + else if (thr1_sigval.sival_ptr != &ev) + { + printf ("*** thr1_sigval.sival_ptr %p != %p\n", + thr1_sigval.sival_ptr, &ev); + result = 1; + } + else if (check_ts ("thr1", &startts, &thr1_ts, 200000)) + result = 1; + + if (thr2_cnt != 1) + { + printf ("*** thr2 not called exactly once, but %d times\n", thr2_cnt); + result = 1; + } + else if (thr2_err) + { + puts ("*** an error occurred in thr2"); + result = 1; + } + else if (thr2_sigval.sival_int != 111) + { + printf ("*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int); + result = 1; + } + else if (check_ts ("thr2", &startts, &thr2_ts, 300000)) + result = 1; + else if (thr2_guardsize != 0) + { + printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize); + result = 1; + } + + pthread_mutex_unlock (&lock); + + if (sig1_cnt != 1) + { + printf ("*** sig1 not called exactly once, but %d times\n", sig1_cnt); + result = 1; + } + else if (sig1_err) + { + printf ("*** errors occurred in sig1 handler %x\n", sig1_err); + result = 1; + } + else if (sig1_sigval.sival_ptr != &ev) + { + printf ("*** sig1_sigval.sival_ptr %p != %p\n", + sig1_sigval.sival_ptr, &ev); + result = 1; + } + else if (check_ts ("sig1", &startts, &sig1_ts, 400000)) + result = 1; + + if (sig2_cnt != 1) + { + printf ("*** sig2 not called exactly once, but %d times\n", sig2_cnt); + result = 1; + } + else if (sig2_err) + { + printf ("*** errors occurred in sig2 handler %x\n", sig2_err); + result = 1; + } + else if (sig2_sigval.sival_int != 163) + { + printf ("*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int); + result = 1; + } + else if (check_ts ("sig2", &startts, &sig2_ts, 500000)) + result = 1; + + if (timer_gettime (timer_none, &it) != 0) + { + printf ("*** timer_gettime timer_none failed: %m\n"); + result = 1; + } + else if (it.it_value.tv_sec || it.it_value.tv_nsec + || it.it_interval.tv_sec || it.it_interval.tv_nsec) + { + printf ("\ +*** timer_gettime timer_none returned { %ld.%09ld, %ld.%09ld }\n", + (long) it.it_value.tv_sec, it.it_value.tv_nsec, + (long) it.it_interval.tv_sec, it.it_interval.tv_nsec); + result = 1; + } + + if (clock_gettime (TEST_CLOCK, &startts) != 0) + { + printf ("*** clock_gettime failed: %m\n"); + result = 1; + } + + it.it_value.tv_sec = 1; + it.it_value.tv_nsec = 0; + it.it_interval.tv_sec = 0; + it.it_interval.tv_nsec = 100000000; + if (timer_settime (timer_none, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_none failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 100000000; + it.it_interval.tv_nsec = 200000000; + if (timer_settime (timer_thr1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 200000000; + it.it_interval.tv_nsec = 300000000; + if (timer_settime (timer_thr2, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_thr2 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 300000000; + it.it_interval.tv_nsec = 400000000; + if (timer_settime (timer_sig1, 0, &it, NULL) != 0) + { + printf ("*** timer_settime timer_sig1 failed: %m\n"); + result = 1; + } + + it.it_value.tv_nsec = 400000000; + it.it_interval.tv_nsec = 500000000; + if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0) + { + printf ("*** timer_settime timer_sig2 failed: %m\n"); + result = 1; + } + + pthread_mutex_lock (&lock); + while (thr1_cnt < 6 || thr2_cnt < 6) + pthread_cond_wait (&cond, &lock); + pthread_mutex_unlock (&lock); + + while (sig1_cnt < 6 || sig2_cnt < 6) + { + ts.tv_sec = 0; + ts.tv_nsec = 100000000; + nanosleep (&ts, NULL); + } + + pthread_mutex_lock (&lock); + + if (thr1_err) + { + puts ("*** an error occurred in thr1"); + result = 1; + } + else if (check_ts ("thr1", &startts, &thr1_ts, 1100000 + 4 * 200000)) + result = 1; + + if (thr2_err) + { + puts ("*** an error occurred in thr2"); + result = 1; + } + else if (check_ts ("thr2", &startts, &thr2_ts, 1200000 + 4 * 300000)) + result = 1; + else if (thr2_guardsize != 0) + { + printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize); + result = 1; + } + + pthread_mutex_unlock (&lock); + + if (sig1_err) + { + printf ("*** errors occurred in sig1 handler %x\n", sig1_err); + result = 1; + } + else if (check_ts ("sig1", &startts, &sig1_ts, 1300000 + 4 * 400000)) + result = 1; + + if (sig2_err) + { + printf ("*** errors occurred in sig2 handler %x\n", sig2_err); + result = 1; + } + else if (check_ts ("sig2", &startts, &sig2_ts, 1400000 + 4 * 500000)) + result = 1; + + if (timer_gettime (timer_none, &it) != 0) + { + printf ("*** timer_gettime timer_none failed: %m\n"); + result = 1; + } + else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000) + { + printf ("\ +!!! second timer_gettime timer_none returned it_interval %ld.%09ld\n", + (long) it.it_interval.tv_sec, it.it_interval.tv_nsec); + /* FIXME: For now disabled. + result = 1; */ + } + + if (timer_delete (timer_none) != 0) + { + printf ("*** timer_delete for timer_none failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_sig1) != 0) + { + printf ("*** timer_delete for timer_sig1 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_sig2) != 0) + { + printf ("*** timer_delete for timer_sig2 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_thr1) != 0) + { + printf ("*** timer_delete for timer_thr1 failed: %m\n"); + result = 1; + } + + if (timer_delete (timer_thr2) != 0) + { + printf ("*** timer_delete for timer_thr2 failed: %m\n"); + result = 1; + } + return result; +} +#else +# define TEST_FUNCTION 0 +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-timer5.c b/test/nptl/tst-timer5.c new file mode 100644 index 000000000..6466c8efc --- /dev/null +++ b/test/nptl/tst-timer5.c @@ -0,0 +1,38 @@ +/* Timer test using the monotonic clock. */ + +#include <time.h> +#include <unistd.h> + +#if defined CLOCK_MONOTONIC && defined _POSIX_MONOTONIC_CLOCK + +# define TEST_CLOCK CLOCK_MONOTONIC +# define TEST_CLOCK_MISSING(clock) \ + (setup_test () ? "CLOCK_MONOTONIC" : NULL) + +# include <stdio.h> + +static int +setup_test (void) +{ + if (sysconf (_SC_MONOTONIC_CLOCK) <= 0) + return 1; + + /* The user-level timers implementation doesn't support CLOCK_MONOTONIC, + even though sysconf claims it will. */ + timer_t t; + if (timer_create (TEST_CLOCK, NULL, &t) != 0) + { + printf ("timer_create: %m\n"); + return 1; + } + timer_delete (t); + + return 0; +} + +# include "tst-timer4.c" + +#else +# define TEST_FUNCTION 0 +# include "../test-skeleton.c" +#endif diff --git a/test/nptl/tst-tls1.c b/test/nptl/tst-tls1.c new file mode 100644 index 000000000..541035ea7 --- /dev/null +++ b/test/nptl/tst-tls1.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <tls.h> + +#if HAVE___THREAD +struct test_s +{ + int a; + int b; +}; + +#define INIT_A 1 +#define INIT_B 42 +/* Deliberately not static. */ +__thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) = +{ + .a = INIT_A, + .b = INIT_B +}; + + +static void * +tf (void *arg) +{ + if (s.a != INIT_A || s.b != INIT_B) + { + puts ("initial value of s in child thread wrong"); + exit (1); + } + + ++s.a; + + return NULL; +} +#endif + + +int +do_test (void) +{ +#if !HAVE___THREAD + + puts ("No __thread support in compiler, test skipped."); + + return 0; +#else + + if (s.a != INIT_A || s.b != INIT_B) + { + puts ("initial value of s in main thread wrong"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + +#define N 10 + int i; + for (i = 0; i < N; ++i) + { +#define M 10 + pthread_t th[M]; + int j; + for (j = 0; j < M; ++j, ++s.a) + if (pthread_create (&th[j], &a, tf, NULL) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + for (j = 0; j < M; ++j) + if (pthread_join (th[j], NULL) != 0) + { + puts ("pthread_join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + return 0; +#endif +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls2.c b/test/nptl/tst-tls2.c new file mode 100644 index 000000000..3615d1b81 --- /dev/null +++ b/test/nptl/tst-tls2.c @@ -0,0 +1,216 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <errno.h> +#include <pthread.h> +#include <signal.h> +#include <semaphore.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD + +#define N 10 +static pthread_t th[N]; + + +#define CB(n) \ +static void \ +cb##n (void) \ +{ \ + if (th[n] != pthread_self ()) \ + { \ + write (STDOUT_FILENO, "wrong callback\n", 15); \ + _exit (1); \ + } \ +} +CB (0) +CB (1) +CB (2) +CB (3) +CB (4) +CB (5) +CB (6) +CB (7) +CB (8) +CB (9) +static void (*cbs[]) (void) = +{ + cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9 +}; + + +static __thread void (*fp) (void) __attribute__ ((tls_model ("local-exec"))); + + +static sem_t s; + + +#define THE_SIG SIGUSR1 +static void +handler (int sig) +{ + if (sig != THE_SIG) + { + write (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + + fp (); + + if (sem_post (&s) != 0) + { + write (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } +} + + +static pthread_barrier_t b; + +#define TOTAL_SIGS 1000 +static int nsigs; + + +static void * +tf (void *arg) +{ + fp = arg; + + pthread_barrier_wait (&b); + + pthread_barrier_wait (&b); + + if (nsigs != TOTAL_SIGS) + { + puts ("barrier_wait prematurely returns"); + exit (1); + } + + return NULL; +} +#endif + +int +do_test (void) +{ +#if !HAVE___THREAD + + puts ("No __thread support in compiler, test skipped."); + + return 0; +#else + + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&s, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + struct sigaction sa; + sa.sa_handler = handler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (THE_SIG, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &a, tf, cbs[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + pthread_barrier_wait (&b); + + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, THE_SIG); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + /* Start sending signals. */ + for (i = 0; i < TOTAL_SIGS; ++i) + { + if (kill (getpid (), THE_SIG) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) != 0) + { + puts ("sem_wait failed"); + exit (1); + } + + ++nsigs; + } + + pthread_barrier_wait (&b); + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + + return 0; +#endif +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls3.c b/test/nptl/tst-tls3.c new file mode 100644 index 000000000..abc5f4cb6 --- /dev/null +++ b/test/nptl/tst-tls3.c @@ -0,0 +1,225 @@ +/* Copyright (C) 2003, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <dlfcn.h> +#include <errno.h> +#include <pthread.h> +#include <signal.h> +#include <semaphore.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthreaddef.h> +#include <tls.h> + +#define THE_SIG SIGUSR1 + + +#define N 10 +static pthread_t th[N]; + + +#define CB(n) \ +static void \ +cb##n (void) \ +{ \ + if (th[n] != pthread_self ()) \ + { \ + write (STDOUT_FILENO, "wrong callback\n", 15); \ + _exit (1); \ + } \ +} +CB (0) +CB (1) +CB (2) +CB (3) +CB (4) +CB (5) +CB (6) +CB (7) +CB (8) +CB (9) +static void (*cbs[]) (void) = +{ + cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9 +}; + + +sem_t s; + + +pthread_barrier_t b; + +#define TOTAL_SIGS 1000 +int nsigs; + + +int +do_test (void) +{ +#if !HAVE___THREAD + + puts ("No __thread support in compiler, test skipped."); + + return 0; +#else + + if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1)) + { + puts ("initial thread's struct pthread not aligned enough"); + exit (1); + } + + if (pthread_barrier_init (&b, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (sem_init (&s, 0, 0) != 0) + { + puts ("sem_init failed"); + exit (1); + } + + void *h = dlopen ("tst-tls3mod.so", RTLD_LAZY); + if (h == NULL) + { + puts ("dlopen failed"); + exit (1); + } + + void *(*tf) (void *) = dlsym (h, "tf"); + if (tf == NULL) + { + puts ("dlsym for tf failed"); + exit (1); + } + + void (*setup_tf) (pthread_barrier_t*, int*, sem_t*) = dlsym(h, "setup_tf"); + if (setup_tf == NULL) + { + puts ("dlsym for setup_tf failed"); + exit(1); + } + + setup_tf (&b, &nsigs, &s); + + struct sigaction sa; + sa.sa_handler = dlsym (h, "handler"); + if (sa.sa_handler == NULL) + { + puts ("dlsym for handler failed"); + exit (1); + } + sigemptyset (&sa.sa_mask); + sa.sa_flags = 0; + if (sigaction (THE_SIG, &sa, NULL) != 0) + { + puts ("sigaction failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int r; + for (r = 0; r < 10; ++r) + { + int i; + for (i = 0; i < N; ++i) + if (pthread_create (&th[i], &a, tf, cbs[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + nsigs = 0; + + pthread_barrier_wait (&b); + + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, THE_SIG); + if (pthread_sigmask (SIG_BLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + /* Start sending signals. */ + for (i = 0; i < TOTAL_SIGS; ++i) + { + if (kill (getpid (), THE_SIG) != 0) + { + puts ("kill failed"); + exit (1); + } + + if (TEMP_FAILURE_RETRY (sem_wait (&s)) != 0) + { + puts ("sem_wait failed"); + exit (1); + } + + ++nsigs; + } + + pthread_barrier_wait (&b); + + if (pthread_sigmask (SIG_UNBLOCK, &ss, NULL) != 0) + { + puts ("pthread_sigmask failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + return 0; +#endif +} + + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls3mod.c b/test/nptl/tst-tls3mod.c new file mode 100644 index 000000000..53206d30d --- /dev/null +++ b/test/nptl/tst-tls3mod.c @@ -0,0 +1,106 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <semaphore.h> +#include <signal.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <pthreaddef.h> +#include <tls.h> + +#if HAVE___THREAD + +static pthread_barrier_t* b = NULL; + +#define TOTAL_SIGS 1000 +static int* nsigs = NULL; + +static sem_t* s = NULL; + +static __thread void (*fp) (void); + + +#define THE_SIG SIGUSR1 +void +handler (int sig) +{ + if (sig != THE_SIG) + { + write (STDOUT_FILENO, "wrong signal\n", 13); + _exit (1); + } + + fp (); + + if (sem_post (s) != 0) + { + write (STDOUT_FILENO, "sem_post failed\n", 16); + _exit (1); + } +} + +void +setup_tf (pthread_barrier_t* t_b, int* t_nsigs, sem_t* t_s) +{ + b = t_b; + nsigs = t_nsigs; + s = t_s; +} + +void * +tf (void *arg) +{ + if (!b || !s || !nsigs) + { + puts ("need to call setup_tf first"); + exit (1); + } + + if ((uintptr_t) pthread_self () & (TCB_ALIGNMENT - 1)) + { + puts ("thread's struct pthread not aligned enough"); + exit (1); + } + + if (fp != NULL) + { + printf("fp=%p\n", (void *)&fp); + puts ("fp not initially NULL"); + exit (1); + } + + fp = arg; + + pthread_barrier_wait (b); + + pthread_barrier_wait (b); + + if (*nsigs != TOTAL_SIGS) + { + puts ("barrier_wait prematurely returns"); + exit (1); + } + + return NULL; +} + +#endif diff --git a/test/nptl/tst-tls4.c b/test/nptl/tst-tls4.c new file mode 100644 index 000000000..52775dee8 --- /dev/null +++ b/test/nptl/tst-tls4.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <dlfcn.h> +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE + +#define N 3 + +void (*test1) (void), (*test2) (void); + +pthread_barrier_t b2, b3; + +static void * +tf (void *arg) +{ + int i; + + for (i = 0; i <= (uintptr_t) arg; ++i) + { + int r = pthread_barrier_wait (&b3); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + } + + test1 (); + + for (i = 0; i < 3; ++i) + { + int r = pthread_barrier_wait (&b3); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + } + + test2 (); + + for (i = 0; i < 3 - (uintptr_t) arg; ++i) + { + int r = pthread_barrier_wait (&b3); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + } + + return NULL; +} + +static void * +tf2 (void *arg) +{ + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("tf2: barrier_wait failed"); + exit (1); + } + + int i; + for (i = 0; i < N; ++i) + tf (arg); + return NULL; +} + +int +do_test (void) +{ + pthread_t th[2]; + const char *modules[N] + = { "tst-tls4moda.so", "tst-tls4moda.so", "tst-tls4modb.so" }; + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (&b3, NULL, 3) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_create (&th[0], NULL, tf2, (void *) (uintptr_t) 1)) + { + puts ("pthread_create failed"); + return 1; + } + + int r = pthread_barrier_wait (&b2); + if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + return 1; + } + + int i; + for (i = 0; i < N; ++i) + { + void *h = dlopen (modules[i], RTLD_LAZY); + if (h == NULL) + { + printf ("dlopen failed %s\n", dlerror ()); + return 1; + } + + test1 = dlsym (h, "test1"); + if (test1 == NULL) + { + printf ("dlsym for test1 failed %s\n", dlerror ()); + return 1; + } + + test2 = dlsym (h, "test2"); + if (test2 == NULL) + { + printf ("dlsym for test2 failed %s\n", dlerror ()); + return 1; + } + + if (pthread_create (&th[1], NULL, tf, (void *) (uintptr_t) 2)) + { + puts ("pthread_create failed"); + return 1; + } + + tf ((void *) (uintptr_t) 0); + + if (pthread_join (th[1], NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (dlclose (h)) + { + puts ("dlclose failed"); + return 1; + } + + printf ("test %d with %s succeeded\n", i, modules[i]); + } + + if (pthread_join (th[0], NULL) != 0) + { + puts ("join failed"); + return 1; + } + + return 0; +} + +#define TIMEOUT 5 +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls4moda.c b/test/nptl/tst-tls4moda.c new file mode 100644 index 000000000..ff7ee5604 --- /dev/null +++ b/test/nptl/tst-tls4moda.c @@ -0,0 +1,56 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE + +static __thread unsigned char foo [32] + __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *)))); + +void +test1 (void) +{ + size_t s; + + for (s = 0; s < sizeof (foo); ++s) + { + if (foo [s]) + abort (); + foo [s] = s; + } +} + +void +test2 (void) +{ + size_t s; + + for (s = 0; s < sizeof (foo); ++s) + { + if (foo [s] != s) + abort (); + foo [s] = sizeof (foo) - s; + } +} + +#endif diff --git a/test/nptl/tst-tls4modb.c b/test/nptl/tst-tls4modb.c new file mode 100644 index 000000000..99f3b5405 --- /dev/null +++ b/test/nptl/tst-tls4modb.c @@ -0,0 +1,65 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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 <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <tls.h> + +#if HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE + +static int i; +int bar; + +static __thread void *foo [32 / sizeof (void *)] + __attribute__ ((tls_model ("initial-exec"), aligned (sizeof (void *)))) + = { &i, &bar }; + +void +test1 (void) +{ + size_t s; + + if (foo [0] != &i || foo [1] != &bar) + abort (); + + foo [0] = NULL; + foo [1] = NULL; + for (s = 0; s < sizeof (foo) / sizeof (void *); ++s) + { + if (foo [s]) + abort (); + foo [s] = &foo[s]; + } +} + +void +test2 (void) +{ + size_t s; + + for (s = 0; s < sizeof (foo) / sizeof (void *); ++s) + { + if (foo [s] != &foo [s]) + abort (); + foo [s] = &foo [s ^ 1]; + } +} + +#endif diff --git a/test/nptl/tst-tls5.c b/test/nptl/tst-tls5.c new file mode 100644 index 000000000..476f09aa1 --- /dev/null +++ b/test/nptl/tst-tls5.c @@ -0,0 +1,119 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 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. */ + +/* Check alignment, overlapping and layout of TLS variables. */ +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <sys/param.h> + +#include "tst-tls5.h" + +#ifdef TLS_REGISTER + +struct tls_obj tls_registry[64]; + +static int +tls_addr_cmp (const void *a, const void *b) +{ + if (((struct tls_obj *)a)->addr < ((struct tls_obj *)b)->addr) + return -1; + if (((struct tls_obj *)a)->addr > ((struct tls_obj *)b)->addr) + return 1; + return 0; +} + +static int +do_test (void) +{ + size_t cnt, i; + int res = 0; + uintptr_t min_addr = ~(uintptr_t) 0, max_addr = 0; + + for (cnt = 0; tls_registry[cnt].name; ++cnt); + tls_registry[cnt].name = NULL; + tls_registry[cnt].addr = (uintptr_t) pthread_self (); + tls_registry[cnt].size = sizeof (struct pthread); + tls_registry[cnt++].align = __alignof__ (struct pthread); + + qsort (tls_registry, cnt, sizeof (struct tls_obj), tls_addr_cmp); + + for (i = 0; i < cnt; ++i) + { + printf ("%s%s = %p, size %zd, align %zd", + tls_registry[i].name ? "&" : "", + tls_registry[i].name ?: "pthread_self ()", + (void *) tls_registry[i].addr, + tls_registry[i].size, tls_registry[i].align); + if (tls_registry[i].addr & (tls_registry[i].align - 1)) + { + fputs (", WRONG ALIGNMENT", stdout); + res = 1; + } + if (i > 0 + && (tls_registry[i - 1].addr + tls_registry[i - 1].size + > tls_registry[i].addr)) + { + fputs (", ADDRESS OVERLAP", stdout); + res = 1; + } + puts (""); + if (tls_registry[i].name) + { + min_addr = MIN (tls_registry[i].addr, min_addr); + max_addr = MAX (tls_registry[i].addr + tls_registry[i].size, + max_addr); + } + } + + if (cnt > 1) + { +#if defined(TLS_TCB_AT_TP) + if (tls_registry[cnt - 1].name) + { + puts ("pthread_self () not larger than all TLS addresses"); + res = 1; + } + else + max_addr = MAX (tls_registry[cnt - 1].addr, max_addr); +#elif defined(TLS_DTV_AT_TP) + if (tls_registry[0].name) + { + puts ("pthread_self () not smaller than all TLS addresses"); + res = 1; + } +#else + abort (); +#endif + printf ("Initial TLS used block size %zd\n", + (size_t) (max_addr - min_addr)); + } + return res; +} + +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tls5.h b/test/nptl/tst-tls5.h new file mode 100644 index 000000000..b7c14eb82 --- /dev/null +++ b/test/nptl/tst-tls5.h @@ -0,0 +1,28 @@ +#include <stdint.h> +#include <stdlib.h> +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +struct tls_obj +{ + const char *name; + uintptr_t addr; + size_t size; + size_t align; +}; +extern struct tls_obj tls_registry[]; + +#define TLS_REGISTER(x) \ +static void __attribute__((constructor)) \ +tls_register_##x (void) \ +{ \ + size_t i; \ + for (i = 0; tls_registry[i].name; ++i); \ + tls_registry[i].name = #x; \ + tls_registry[i].addr = (uintptr_t) &x; \ + tls_registry[i].size = sizeof (x); \ + tls_registry[i].align = __alignof__ (x); \ +} + +#endif diff --git a/test/nptl/tst-tls5mod.c b/test/nptl/tst-tls5mod.c new file mode 100644 index 000000000..4616a20e9 --- /dev/null +++ b/test/nptl/tst-tls5mod.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +/* Ensure tls_registry is exported from the binary. */ +void *tst_tls5mod attribute_hidden = tls_registry; +#endif diff --git a/test/nptl/tst-tls5moda.c b/test/nptl/tst-tls5moda.c new file mode 100644 index 000000000..4644d763a --- /dev/null +++ b/test/nptl/tst-tls5moda.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread char a [32] __attribute__ ((aligned (64))); +TLS_REGISTER (a) +#endif diff --git a/test/nptl/tst-tls5modb.c b/test/nptl/tst-tls5modb.c new file mode 100644 index 000000000..09b439670 --- /dev/null +++ b/test/nptl/tst-tls5modb.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int b; +TLS_REGISTER (b) +#endif diff --git a/test/nptl/tst-tls5modc.c b/test/nptl/tst-tls5modc.c new file mode 100644 index 000000000..bbd89633d --- /dev/null +++ b/test/nptl/tst-tls5modc.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int c; +TLS_REGISTER (c) +#endif diff --git a/test/nptl/tst-tls5modd.c b/test/nptl/tst-tls5modd.c new file mode 100644 index 000000000..8b54d168c --- /dev/null +++ b/test/nptl/tst-tls5modd.c @@ -0,0 +1,6 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int d; +TLS_REGISTER (d) +#endif diff --git a/test/nptl/tst-tls5mode.c b/test/nptl/tst-tls5mode.c new file mode 100644 index 000000000..d30b06752 --- /dev/null +++ b/test/nptl/tst-tls5mode.c @@ -0,0 +1,8 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +static __thread int e1 = 24; +static __thread char e2 [32] __attribute__ ((aligned (64))); +TLS_REGISTER (e1) +TLS_REGISTER (e2) +#endif diff --git a/test/nptl/tst-tls5modf.c b/test/nptl/tst-tls5modf.c new file mode 100644 index 000000000..52dcb9495 --- /dev/null +++ b/test/nptl/tst-tls5modf.c @@ -0,0 +1,9 @@ +#include "tst-tls5.h" + +#ifdef TLS_REGISTER +char tst_tls5modf[60] attribute_hidden = { 26 }; +static __thread int f1 = 24; +static __thread char f2 [32] __attribute__ ((aligned (64))); +TLS_REGISTER (f1) +TLS_REGISTER (f2) +#endif diff --git a/test/nptl/tst-tsd1.c b/test/nptl/tst-tsd1.c new file mode 100644 index 000000000..51b2d0cb2 --- /dev/null +++ b/test/nptl/tst-tsd1.c @@ -0,0 +1,118 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> + + +static int +do_test (void) +{ + pthread_key_t key1; + pthread_key_t key2; + void *value; + int result = 0; + int err; + + err = pthread_key_create (&key1, NULL); + if (err != 0) + { + printf ("1st key_create failed: %s\n", strerror (err)); + return 1; + } + + /* Initial value must be NULL. */ + value = pthread_getspecific (key1); + if (value != NULL) + { + puts ("1st getspecific != NULL"); + result = 1; + } + + err = pthread_setspecific (key1, (void *) -2l); + if (err != 0) + { + printf ("1st setspecific failed: %s\n", strerror (err)); + return 1; + } + + value = pthread_getspecific (key1); + if (value == NULL) + { + puts ("2nd getspecific == NULL\n"); + result = 1; + } + else if (value != (void *) -2l) + { + puts ("2nd getspecific != -2l\n"); + result = 1; + } + + err = pthread_setspecific (key1, (void *) -3l); + if (err != 0) + { + printf ("2nd setspecific failed: %s\n", strerror (err)); + return 1; + } + + value = pthread_getspecific (key1); + if (value == NULL) + { + puts ("3rd getspecific == NULL\n"); + result = 1; + } + else if (value != (void *) -3l) + { + puts ("3rd getspecific != -2l\n"); + result = 1; + } + + err = pthread_key_delete (key1); + if (err != 0) + { + printf ("key_delete failed: %s\n", strerror (err)); + result = 1; + } + + + err = pthread_key_create (&key2, NULL); + if (err != 0) + { + printf ("2nd key_create failed: %s\n", strerror (err)); + return 1; + } + + if (key1 != key2) + puts ("key1 != key2; no more tests performed"); + else + { + value = pthread_getspecific (key2); + if (value != NULL) + { + puts ("4th getspecific != NULL"); + result = 1; + } + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd2.c b/test/nptl/tst-tsd2.c new file mode 100644 index 000000000..19d8a69f9 --- /dev/null +++ b/test/nptl/tst-tsd2.c @@ -0,0 +1,97 @@ +/* Copyright (C) 2002, 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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. */ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> + + +static int result; + + +static void +destr (void *arg) +{ + if (arg != (void *) -2l) + result = 2; + else + result = 0; +} + + +static void * +tf (void *arg) +{ + pthread_key_t key = (pthread_key_t) (long int) arg; + int err; + + err = pthread_setspecific (key, (void *) -2l); + if (err != 0) + result = 3; + + return NULL; +} + + +static int +do_test (void) +{ + pthread_key_t key; + pthread_t th; + int err; + + err = pthread_key_create (&key, destr); + if (err != 0) + { + printf ("key_create failed: %s\n", strerror (err)); + return 1; + } + + result = 1; + + err = pthread_create (&th, NULL, tf, (void *) (long int) key); + if (err != 0) + { + printf ("create failed: %s\n", strerror (err)); + return 1; + } + + /* Wait for the thread to terminate. */ + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("join failed: %s\n", strerror (err)); + return 1; + } + + if (result == 1) + puts ("destructor not called"); + else if (result == 2) + puts ("destructor got passed a wrong value"); + else if (result == 3) + puts ("setspecific in child failed"); + else if (result != 0) + puts ("result != 0"); + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd3.c b/test/nptl/tst-tsd3.c new file mode 100644 index 000000000..6cdf74991 --- /dev/null +++ b/test/nptl/tst-tsd3.c @@ -0,0 +1,129 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_key_t key1; +static pthread_key_t key2; + + +static int left; + + +static void +destr1 (void *arg) +{ + if (--left > 0) + { + puts ("set key2"); + + if (pthread_setspecific (key2, (void *) 1l) != 0) + { + puts ("destr1: setspecific failed"); + exit (1); + } + } +} + + +static void +destr2 (void *arg) +{ + if (--left > 0) + { + puts ("set key1"); + + if (pthread_setspecific (key1, (void *) 1l) != 0) + { + puts ("destr2: setspecific failed"); + exit (1); + } + } +} + + +static void * +tf (void *arg) +{ + /* Let the destructors work. */ + left = 7; + + if (pthread_setspecific (key1, (void *) 1l) != 0 + || pthread_setspecific (key2, (void *) 1l) != 0) + { + puts ("tf: setspecific failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + /* Allocate two keys, both with destructors. */ + if (pthread_key_create (&key1, destr1) != 0 + || pthread_key_create (&key2, destr2) != 0) + { + puts ("key_create failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (left != 0) + { + printf ("left == %d\n", left); + return 1; + } + + if (pthread_getspecific (key1) != NULL) + { + puts ("key1 data != NULL"); + return 1; + } + if (pthread_getspecific (key2) != NULL) + { + puts ("key2 data != NULL"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd4.c b/test/nptl/tst-tsd4.c new file mode 100644 index 000000000..44bbadb42 --- /dev/null +++ b/test/nptl/tst-tsd4.c @@ -0,0 +1,103 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <limits.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + + +static pthread_key_t key; + + +static int rounds; + + +static void +destr (void *arg) +{ + ++rounds; + + if (pthread_setspecific (key, (void *) 1l) != 0) + { + puts ("destr: setspecific failed"); + exit (1); + } +} + + +static void * +tf (void *arg) +{ + if (pthread_setspecific (key, (void *) 1l) != 0) + { + puts ("tf: setspecific failed"); + exit (1); + } + + return NULL; +} + + +/* This test check non-standard behavior. The standard does not + require that the implementation has to stop calling TSD destructors + when they are set over and over again. But NPTL does. */ +static int +do_test (void) +{ + /* Allocate two keys, both with destructors. */ + if (pthread_key_create (&key, destr) != 0) + { + puts ("key_create failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + if (pthread_join (th, NULL) != 0) + { + puts ("join failed"); + return 1; + } + + if (rounds < PTHREAD_DESTRUCTOR_ITERATIONS) + { + printf ("rounds == %d, PTHREAD_DESTRUCTOR_ITERATIONS = %d\n", + rounds, PTHREAD_DESTRUCTOR_ITERATIONS); + return 1; + } + + if (pthread_getspecific (key) != NULL) + { + puts ("key data != NULL"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-tsd5.c b/test/nptl/tst-tsd5.c new file mode 100644 index 000000000..8793e339a --- /dev/null +++ b/test/nptl/tst-tsd5.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + + +static void +cl (void *p) +{ + pthread_mutex_unlock (&m); +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&m) != 0) + { + puts ("2nd mutex_lock failed"); + exit (1); + } + + exit (0); +} + + +static int +do_test (void) +{ + pthread_key_t k; + if (pthread_key_create (&k, cl) != 0) + { + puts ("key_create failed"); + return 1; + } + if (pthread_setspecific (k, (void *) 1) != 0) + { + puts ("setspecific failed"); + return 1; + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + return 1; + } + + pthread_exit (NULL); +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/nptl/tst-umask1.c b/test/nptl/tst-umask1.c new file mode 100644 index 000000000..d64a8be3d --- /dev/null +++ b/test/nptl/tst-umask1.c @@ -0,0 +1,137 @@ +/* Copyright (C) 2003 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 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 <fcntl.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + + +static struct +{ + int (*fp) (const char *, mode_t); + const char *name; + bool is_fd; +} fcts[] = +{ + { creat, "creat", true }, + { mkdir, "mkdir", false }, + { mkfifo, "mkfifo", false }, +}; +#define nfcts (sizeof (fcts) / sizeof (fcts[0])) + + +static int +work (const char *fname, int mask) +{ + int result = 0; + size_t i; + for (i = 0; i < nfcts; ++i) + { + remove (fname); + int fd = fcts[i].fp (fname, 0777); + if (fd == -1) + { + printf ("cannot %s %s: %m\n", fcts[i].name, fname); + exit (1); + } + if (fcts[i].is_fd) + close (fd); + struct stat64 st; + if (stat64 (fname, &st) == -1) + { + printf ("cannot stat %s after %s: %m\n", fname, fcts[i].name); + exit (1); + } + + if ((st.st_mode & mask) != 0) + { + printf ("mask not successful after %s: %x still set\n", + fcts[i].name, (unsigned int) (st.st_mode & mask)); + result = 1; + } + } + + return result; +} + + +static pthread_barrier_t bar; + + +static void * +tf (void *arg) +{ + pthread_barrier_wait (&bar); + + int result = work (arg, 022); + + pthread_barrier_wait (&bar); + + pthread_barrier_wait (&bar); + + return (work (arg, 0) | result) ? (void *) -1l : NULL; +} + + +static int +do_test (const char *fname) +{ + int result = 0; + + umask (0); + result |= work (fname, 0); + + pthread_barrier_init (&bar, NULL, 2); + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) fname) != 0) + { + puts ("cannot create thread"); + exit (1); + } + + umask (022); + result |= work (fname, 022); + + pthread_barrier_wait (&bar); + + pthread_barrier_wait (&bar); + + umask (0); + + pthread_barrier_wait (&bar); + + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("join failed"); + exit (1); + } + + remove (fname); + + return result || res != NULL; +} + +#define TEST_FUNCTION do_test (argc < 2 ? "/tmp/tst-umask.tmp" : argv[1]) +#include "../test-skeleton.c" diff --git a/test/pthread/Makefile.in b/test/pthread/Makefile.in index d3412f6b8..c50748d69 100644 --- a/test/pthread/Makefile.in +++ b/test/pthread/Makefile.in @@ -1,6 +1,7 @@ # uClibc pthread tests # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. +TESTS_DISABLED += cancellation-points EXTRA_LDFLAGS := -lpthread diff --git a/test/tls/Makefile b/test/tls/Makefile new file mode 100644 index 000000000..a99c5d16f --- /dev/null +++ b/test/tls/Makefile @@ -0,0 +1,7 @@ +# uClibc NPTL tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +top_builddir=../../ +include ../Rules.mak +-include Makefile.in +include ../Test.mak diff --git a/test/tls/Makefile.in b/test/tls/Makefile.in new file mode 100644 index 000000000..69a8eaf27 --- /dev/null +++ b/test/tls/Makefile.in @@ -0,0 +1,138 @@ +# uClibc TLS tests +# Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + +TESTS := tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 \ + tst-tls8 tst-tls9 tst-tls10 tst-tls11 tst-tls12 tst-tls13 \ + tst-tls14 tst-tls15 tst-tls16 tst-tls17 tst-tls18 tst-tls-at-ctor \ + tst-tls1-static tst-tls2-static tst-tls9-static +TESTS_DISABLED := tst-tls1-static tst-tls2-static tst-tls9-static + +# All these tests need tls.h, which is not installed with glibc +GLIBC_TESTS_DISABLED := $(addsuffix _glibc,$(filter-out $(TESTS_DISABLED),$(TESTS))) + + +PTDIR := $(top_builddir)libpthread/nptl + +EXTRA_CFLAGS := -DNOT_IN_libc=1 \ + -std=gnu99 -I. -I$(PTDIR) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/$(TARGET_ARCH) \ + -I$(PTDIR)/sysdeps/unix/sysv/linux \ + -I$(PTDIR)/sysdeps/pthread \ + -I$(PTDIR)/sysdeps/pthread/bits \ + -I$(PTDIR)/sysdeps/generic \ + -I$(top_builddir)ldso/include \ + -I$(top_builddir)ldso/ldso/$(TARGET_ARCH) \ + -I$(top_builddir)include \ + -include $(top_builddir)include/libc-symbols.h + +tlsmod17a-suffixes := 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 +tlsmod18a-suffixes := 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 +CFLAGS_tst-tlsmod1.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod2.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod3.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod4.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod5.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod6.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod7.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod8.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod9.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod10.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod11.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod12.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod13.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod13a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod14a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod14b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod15a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod15b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod16a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod16b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod17a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod17b.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod18a.so := -fPIC -DSHARED -shared +CFLAGS_tst-tlsmod-at-ctor.so := -fPIC -DSHARED -shared + +LDFLAGS_tst-tlsmod1.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod2.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod3.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod2.so +LDFLAGS_tst-tlsmod4.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod5.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod6.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod7.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod8.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod7.so +LDFLAGS_tst-tlsmod9.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod8.so +LDFLAGS_tst-tlsmod10.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod9.so +LDFLAGS_tst-tlsmod11.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod12.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod11.so +LDFLAGS_tst-tlsmod13.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod13a.so := -shared -static-libgcc -L$(top_builddir)lib \ + tst-tlsmod13.so +LDFLAGS_tst-tlsmod14a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod14b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod15a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod15b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod16a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod16b.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod17a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod17b.so := -shared -static-libgcc -L$(top_builddir)lib \ + $(patsubst %,tst-tlsmod17a%.so,$(tlsmod17a-suffixes)) +LDFLAGS_tst-tlsmod18a.so := -shared -static-libgcc -L$(top_builddir)lib +LDFLAGS_tst-tlsmod-at-ctor.so := -shared -static-libgcc -L$(top_builddir)lib + +LDFLAGS_tst-tls3 := tst-tlsmod1.so tst-tlsmod4.so +LDFLAGS_tst-tls4 := -ldl +LDFLAGS_tst-tls5 := -ldl +LDFLAGS_tst-tls6 := -ldl +LDFLAGS_tst-tls7 := -ldl +LDFLAGS_tst-tls8 := -ldl +LDFLAGS_tst-tls9 := -ldl +LDFLAGS_tst-tls10 := -Wl,-rpath-link=. tst-tlsmod8.so +LDFLAGS_tst-tls11 := -Wl,-rpath-link=. tst-tlsmod10.so +LDFLAGS_tst-tls12 := -Wl,-rpath-link=. tst-tlsmod12.so +LDFLAGS_tst-tls13 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls14 := -ldl -Wl,-rpath-link=. tst-tlsmod14a.so +LDFLAGS_tst-tls15 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls16 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls17 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls18 := -ldl -Wl,-rpath-link=. +LDFLAGS_tst-tls-at-ctor := tst-tlsmod-at-ctor.so + +tst-tls3: tst-tlsmod1.so tst-tlsmod4.so +tst-tls4: tst-tlsmod2.so +tst-tls5: tst-tlsmod2.so +tst-tls6: tst-tlsmod2.so +tst-tls7: tst-tlsmod2.so tst-tlsmod3.so +tst-tls8: tst-tlsmod2.so tst-tlsmod3.so tst-tlsmod4.so +tst-tls9: tst-tlsmod5.so tst-tlsmod6.so +tst-tls10: tst-tlsmod7.so tst-tlsmod8.so +tst-tls11: tst-tlsmod9.so tst-tlsmod10.so +tst-tls12: tst-tlsmod11.so tst-tlsmod12.so +tst-tls13: tst-tlsmod13.so tst-tlsmod13a.so +tst-tls14: tst-tlsmod14a.so tst-tlsmod14b.so +tst-tls15: tst-tlsmod15b.so +tst-tls16: tst-tlsmod16a.so tst-tlsmod16b.so +tst-tls17: tst-tlsmod17b.so +tst-tlsmod17b.so: $(patsubst %,tst-tlsmod17a%.so,$(tlsmod17a-suffixes)) +tst-tlsmod17a%.so: tst-tlsmod17a.c + $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_tst-tlsmod17a.so) $< -o $@ \ + -DN=$* -Wl,-soname,$@ $(LDFLAGS) $(EXTRA_LIBS) \ + $(LDFLAGS_tst-tlsmod17a.so) +tst-tls18: $(patsubst %,tst-tlsmod18a%.so,$(tlsmod18a-suffixes)) +tst-tlsmod18a%.so: tst-tlsmod18a.c + $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_tst-tlsmod18a.so) $< -o $@ \ + -DN=$* -Wl,-soname,$@ $(LDFLAGS) $(EXTRA_LIBS) \ + $(LDFLAGS_tst-tlsmod18a.so) +tst-tls-at-ctor: tst-tlsmod-at-ctor.so + +RET_tst-tls13 := 1 +ifeq ($(TARGET_ARCH),mips) +RET_tst-tls15 := 1 +endif + +WRAPPER := env LD_LIBRARY_PATH="$$PWD:.:$(LD_LIBRARY_PATH)" diff --git a/test/tls/README b/test/tls/README new file mode 100644 index 000000000..06c9eb743 --- /dev/null +++ b/test/tls/README @@ -0,0 +1,8 @@ +These tests were imported from 'glibc/elf' and are responsible for testing +the TLS functionality of the dynamic loader. The file 'tls-macros-mips.h' +is a copy of 'glibc/sysdeps/mips/tls-macros.h'. Dependency and link orders +are critical and should NOT be changed. Even if you think you know what +you are doing, do not touch the Makefile without posting to the uClibc +development mailing list. + +-Steve <sjhill@uclibc.org> diff --git a/test/tls/tls-macros-arm.h b/test/tls/tls-macros-arm.h new file mode 100644 index 000000000..13d0f9752 --- /dev/null +++ b/test/tls/tls-macros-arm.h @@ -0,0 +1,51 @@ +#define TLS_LE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "add %0, %1, %0; " \ + "b 2f; " \ + "1: .word " #x "(tpoff); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_IE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "3: ldr %0, [pc, %0];" \ + "add %0, %1, %0; " \ + "b 2f; " \ + "1: .word " #x "(gottpoff) + (. - 3b - 8); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_LD(x) \ + ({ char *__result; \ + int __offset; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsldm) + (. - 1b - 8); " \ + "3: " \ + : "=r" (__result)); \ + __result = (char *)__tls_get_addr (__result); \ + __asm__ ("ldr %0, 1f; " \ + "b 2f; " \ + "1: .word " #x "(tlsldo); " \ + "2: " \ + : "=r" (__offset)); \ + (int *) (__result + __offset); }) + +#define TLS_GD(x) \ + ({ int *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsgd) + (. - 1b - 8); " \ + "3: " \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) diff --git a/test/tls/tls-macros-mips.h b/test/tls/tls-macros-mips.h new file mode 100644 index 000000000..0db383032 --- /dev/null +++ b/test/tls/tls-macros-mips.h @@ -0,0 +1,88 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#if _MIPS_SIM != _ABI64 + +/* These versions are for o32 and n32. */ + +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("addiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#else +# define TLS_GD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("daddiu %0, $28, %%tlsgd(" #x ")" \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) +#endif + +#if _MIPS_SIM != _ABI64 +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("addiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lw $3,%%gottprel(" #x ")($28)\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "addiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "addu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) + +#else + +/* These versions are for n64. */ + +# define TLS_LD(x) \ + ({ void *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("daddiu %0, $28, %%tlsldm(" #x ")" \ + : "=r" (__result)); \ + __result = __tls_get_addr (__result); \ + __asm__ ("lui $3,%%dtprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%dtprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_IE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("ld $3,%%gottprel(" #x ")($28)\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +# define TLS_LE(x) \ + ({ void *__result; \ + __asm__ (".set push\n\t.set mips32r2\n\t" \ + "rdhwr\t%0,$29\n\t.set pop" \ + : "=v" (__result)); \ + __asm__ ("lui $3,%%tprel_hi(" #x ")\n\t" \ + "daddiu $3,$3,%%tprel_lo(" #x ")\n\t" \ + "daddu %0,%0,$3" \ + : "+r" (__result) : : "$3"); \ + __result; }) +#endif diff --git a/test/tls/tls-macros-thumb.h b/test/tls/tls-macros-thumb.h new file mode 100644 index 000000000..dfa6582a5 --- /dev/null +++ b/test/tls/tls-macros-thumb.h @@ -0,0 +1,57 @@ +#define TLS_LE(x) \ + ({ int *__result; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "add %0, %1, %0; " \ + "b 2f; " \ + ".align 2; " \ + "1: .word " #x "(tpoff); " \ + "2: " \ + : "=&r" (__result) : "r" (tp)); \ + __result; }) + +#define TLS_IE(x) \ + ({ int *__result; \ + int tmp; \ + void *tp = __builtin_thread_pointer (); \ + __asm__ ("ldr %0, 1f; " \ + "adr %1, 1f; " \ + "ldr %0, [%1, %0]; " \ + "add %0, %2, %0; " \ + "b 2f; " \ + ".align 2; " \ + "1: .word " #x "(gottpoff); " \ + "2: " \ + : "=&r" (__result), "=&r"(tmp) : "r" (tp)); \ + __result; }) + +#define TLS_LD(x) \ + ({ char *__result; \ + int __offset; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + ".align 2; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsldm) + (. - 1b - 4); " \ + "3: " \ + : "=r" (__result)); \ + __result = (char *)__tls_get_addr (__result); \ + __asm__ ("ldr %0, 1f; " \ + "b 2f; " \ + "1: .word " #x "(tlsldo); " \ + "2: " \ + : "=r" (__offset)); \ + (int *) (__result + __offset); }) + +#define TLS_GD(x) \ + ({ int *__result; \ + extern void *__tls_get_addr (void *); \ + __asm__ ("ldr %0, 2f; " \ + ".align 2; " \ + "1: add %0, pc, %0; " \ + "b 3f; " \ + "2: .word " #x "(tlsgd) + (. - 1b - 4); " \ + "3: " \ + : "=r" (__result)); \ + (int *)__tls_get_addr (__result); }) diff --git a/test/tls/tls-macros.h b/test/tls/tls-macros.h new file mode 100644 index 000000000..cd31100cf --- /dev/null +++ b/test/tls/tls-macros.h @@ -0,0 +1,861 @@ +/* Macros to support TLS testing in times of missing compiler support. */ + +#define COMMON_INT_DEF(x) \ + __asm__ (".tls_common " #x ",4,4") +/* XXX Until we get compiler support we don't need declarations. */ +#define COMMON_INT_DECL(x) + +/* XXX This definition will probably be machine specific, too. */ +#define VAR_INT_DEF(x) \ + __asm__ (".section .tdata\n\t" \ + ".globl " #x "\n" \ + ".balign 4\n" \ + #x ":\t.long 0\n\t" \ + ".size " #x ",4\n\t" \ + ".previous") +/* XXX Until we get compiler support we don't need declarations. */ +#define VAR_INT_DECL(x) + +#ifdef __mips__ +#include <tls-macros-mips.h> +#endif + +#ifdef __arm__ +#ifdef __thumb__ +#include <tls-macros-thumb.h> +#else +#include <tls-macros-arm.h> +#endif +#endif + + /* XXX Each architecture must have its own asm for now. */ +#ifdef __i386__ +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("movl %%gs:0,%0\n\t" \ + "subl $" #x "@tpoff,%0" \ + : "=r" (__l)); \ + __l; }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("movl %%gs:0,%0\n\t" \ + "subl " #x "@gottpoff(%%ebx),%0" \ + : "=r" (__l)); \ + __l; }) +# else +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "movl %%gs:0,%0\n\t" \ + "subl " #x "@gottpoff(%%ebx),%0" \ + : "=r" (__l)); \ + __l; }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "leal " #x "@dtpoff(%%eax), %%eax" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# else +# define TLS_LD(x) \ + ({ int *__l, __b, __c, __d; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "leal " #x "@tlsldm(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "leal " #x "@dtpoff(%%eax), %%eax" \ + : "=a" (__l), "=&b" (__b), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "nop" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# else +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("call 1f\n\t" \ + ".subsection 1\n" \ + "1:\tmovl (%%esp), %%ebx\n\t" \ + "ret\n\t" \ + ".previous\n\t" \ + "addl $_GLOBAL_OFFSET_TABLE_, %%ebx\n\t" \ + "leal " #x "@tlsgd(%%ebx),%%eax\n\t" \ + "call ___tls_get_addr@plt\n\t" \ + "nop" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d)); \ + __l; }) +# endif + +#elif defined __x86_64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("movq %%fs:0,%0\n\t" \ + "leaq " #x "@tpoff(%0), %0" \ + : "=r" (__l)); \ + __l; }) + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("movq %%fs:0,%0\n\t" \ + "addq " #x "@gottpoff(%%rip),%0" \ + : "=r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l, __c, __d; \ + __asm__ ("leaq " #x "@tlsld(%%rip),%%rdi\n\t" \ + "call __tls_get_addr@plt\n\t" \ + "leaq " #x "@dtpoff(%%rax), %%rax" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d) \ + : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l, __c, __d; \ + __asm__ (".byte 0x66\n\t" \ + "leaq " #x "@tlsgd(%%rip),%%rdi\n\t" \ + ".word 0x6666\n\t" \ + "rex64\n\t" \ + "call __tls_get_addr@plt" \ + : "=a" (__l), "=&c" (__c), "=&d" (__d) \ + : : "rdi", "rsi", "r8", "r9", "r10", "r11"); \ + __l; }) + +#elif defined __sh__ + +# define TLS_LE(x) \ + ({ int *__l; void *__tp; \ + __asm__ ("stc gbr,%1\n\t" \ + "mov.l 1f,%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tpoff\n\t" \ + "2:" \ + : "=r" (__l), "=r" (__tp)); \ + __l; }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ int *__l; void *__tp; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r0\n\t" \ + "stc gbr,%1\n\t" \ + "mov.l @(r0,r12),%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@gottpoff\n\t" \ + "2:" \ + : "=r" (__l), "=r" (__tp) : "r" (__gp) : "r0"); \ + __l; }) +# else +# define TLS_IE(x) \ + ({ int *__l; void *__tp; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r0\n\t" \ + "stc gbr,%1\n\t" \ + "mov.l @(r0,r12),%0\n\t" \ + "bra 2f\n\t" \ + " add %1,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@gottpoff\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "2: mov.l @r15+,r12" \ + : "=r" (__l), "=r" (__tp) : : "r0"); \ + __l; }) +#endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ int *__l; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 4f\n\t" \ + " nop\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsldm\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "4: mov.l 3f,%0\n\t" \ + "bra 5f\n\t" \ + " add r0,%0\n\t" \ + ".align 2\n\t" \ + "3: .long " #x "@dtpoff\n\t" \ + "5:" \ + : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "pr", "t"); \ + __l; }) +# else +# define TLS_LD(x) \ + ({ int *__l; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 4f\n\t" \ + " nop\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsldm\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "4: mov.l 3f,%0\n\t" \ + "bra 5f\n\t" \ + " add r0,%0\n\t" \ + ".align 2\n\t" \ + "3: .long " #x "@dtpoff\n\t" \ + "5: mov.l @r15+,r12" \ + : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pr", "t"); \ + __l; }) +#endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ int *__l; \ + register void *__gp __asm__("r12"); \ + __asm__ ("mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 3f\n\t" \ + " mov r0,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsgd\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "3:" \ + : "=r" (__l) : "r" (__gp) : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "pr", "t"); \ + __l; }) +# else +# define TLS_GD(x) \ + ({ int *__l; \ + __asm__ ("mov.l r12,@-r15\n\t" \ + "mova 0f,r0\n\t" \ + "mov.l 0f,r12\n\t" \ + "add r0,r12\n\t" \ + "mov.l 1f,r4\n\t" \ + "mova 2f,r0\n\t" \ + "mov.l 2f,r1\n\t" \ + "add r0,r1\n\t" \ + "jsr @r1\n\t" \ + " add r12,r4\n\t" \ + "bra 3f\n\t" \ + " mov r0,%0\n\t" \ + ".align 2\n\t" \ + "1: .long " #x "@tlsgd\n\t" \ + "2: .long __tls_get_addr@plt\n\t" \ + "0: .long _GLOBAL_OFFSET_TABLE_\n\t" \ + "3: mov.l @r15+,r12" \ + : "=r" (__l) : : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "pr", "t"); \ + __l; }) +#endif + +#elif defined __alpha__ + +register void *__gp __asm__("$29"); + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("call_pal 158\n\tlda $0," #x "($0)\t\t!tprel" : "=v"(__l)); \ + __l; }) + +# define TLS_IE(x) \ + ({ char *__tp; unsigned long __o; \ + __asm__ ("call_pal 158\n\tldq %1," #x "($gp)\t\t!gottprel" \ + : "=v"(__tp), "=r"(__o) : "r"(__gp)); \ + (int *)(__tp + __o); }) + +# define TLS_LD(x) \ + ({ extern void *__tls_get_addr(void *); int *__l; void *__i; \ + __asm__ ("lda %0," #x "($gp)\t\t!tlsldm" : "=r" (__i) : "r"(__gp)); \ + __i = __tls_get_addr(__i); \ + __asm__ ("lda %0, " #x "(%1)\t\t!dtprel" : "=r"(__l) : "r"(__i)); \ + __l; }) + +# define TLS_GD(x) \ + ({ extern void *__tls_get_addr(void *); void *__i; \ + __asm__ ("lda %0," #x "($gp)\t\t!tlsgd" : "=r" (__i) : "r"(__gp)); \ + (int *) __tls_get_addr(__i); }) + + +#elif defined __ia64__ + +# define TLS_LE(x) \ + ({ void *__l; \ + __asm__ ("mov r2=r13\n\t" \ + ";;\n\t" \ + "addl %0=@tprel(" #x "),r2\n\t" \ + : "=r" (__l) : : "r2" ); __l; }) + +# define TLS_IE(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "addl r16=@ltoff(@tprel(" #x ")),gp\n\t" \ + ";;\n\t" \ + "ld8 r17=[r16]\n\t" \ + ";;\n\t" \ + "add %0=r13,r17\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "r16", "r17" ); __l; }) + +# define __TLS_CALL_CLOBBERS \ + "r2", "r3", "r8", "r9", "r10", "r11", "r14", "r15", "r16", "r17", \ + "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", \ + "r27", "r28", "r29", "r30", "r31", \ + "p6", "p7", "p8", "p9", "p10", "p11", "p12", "p13", "p14", "p15", \ + "f6", "f7", "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \ + "b6", "b7", \ + "out0", "out1", "out2", "out3", "out4", "out5", "out6", "out7" + +# define TLS_LD(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "mov loc0=gp\n\t" \ + "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ + "addl out1=@dtprel(" #x "),r0\n\t" \ + ";;\n\t" \ + "ld8 out0=[r16]\n\t" \ + "br.call.sptk.many b0=__tls_get_addr" \ + ";;\n\t" \ + "mov gp=loc0\n\t" \ + "mov %0=r8\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ + __l; }) + +# define TLS_GD(x) \ + ({ void *__l; \ + register long __gp __asm__ ("gp"); \ + __asm__ (";;\n\t" \ + "mov loc0=gp\n\t" \ + "addl r16=@ltoff(@dtpmod(" #x ")),gp\n\t" \ + "addl r17=@ltoff(@dtprel(" #x ")),gp\n\t" \ + ";;\n\t" \ + "ld8 out0=[r16]\n\t" \ + "ld8 out1=[r17]\n\t" \ + "br.call.sptk.many b0=__tls_get_addr" \ + ";;\n\t" \ + "mov gp=loc0\n\t" \ + "mov %0=r8\n\t" \ + ";;\n\t" \ + : "=r" (__l) : "r" (__gp) : "loc0", __TLS_CALL_CLOBBERS); \ + __l; }) + +#elif defined __sparc__ && !defined __arch64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# ifdef __PIC__ +# define TLS_LOAD_PIC \ + ({ register long pc __asm__ ("%o7"); \ + long got; \ + __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ + "call .+8\n\t" \ + "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ + "add %1, %0, %1\n\t" \ + : "=r" (pc), "=r" (got)); \ + got; }) +# else +# define TLS_LOAD_PIC \ + ({ long got; \ + __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ + "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ + "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ + : "=r" (got)); \ + got; }) +# endif + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("ld [%1 + %2], %0, %%tie_ld(" #x ")" \ + : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + long __o; \ + __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ + __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ + __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ + : "r" (__o0), "r" (__o)); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __o0; }) + +#elif defined __sparc__ && defined __arch64__ + +# define TLS_LE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tle_hix22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("xor %1, %%tle_lox10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %%g7, %1, %0" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# ifdef __PIC__ +# define TLS_LOAD_PIC \ + ({ long pc, got; \ + __asm__ ("sethi %%hi(_GLOBAL_OFFSET_TABLE_-4), %1\n\t" \ + "rd %%pc, %0\n\t" \ + "add %1, %%lo(_GLOBAL_OFFSET_TABLE_+4), %1\n\t" \ + "add %1, %0, %1\n\t" \ + : "=r" (pc), "=r" (got)); \ + got; }) +# else +# define TLS_LOAD_PIC \ + ({ long got; \ + __asm__ (".hidden _GLOBAL_OFFSET_TABLE_\n\t" \ + "sethi %%hi(_GLOBAL_OFFSET_TABLE_), %0\n\t" \ + "or %0, %%lo(_GLOBAL_OFFSET_TABLE_), %0" \ + : "=r" (got)); \ + got; }) +# endif + +# define TLS_IE(x) \ + ({ int *__l; \ + __asm__ ("sethi %%tie_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tie_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("ldx [%1 + %2], %0, %%tie_ldx(" #x ")" \ + : "=r" (__l) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("add %%g7, %1, %0, %%tie_add(" #x ")" : "=r" (__l) : "r" (__l)); \ + __l; }) + +# define TLS_LD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + long __o; \ + __asm__ ("sethi %%tldm_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tldm_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tldm_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __asm__ ("sethi %%tldo_hix22(" #x "), %0" : "=r" (__o)); \ + __asm__ ("xor %1, %%tldo_lox10(" #x "), %0" : "=r" (__o) : "r" (__o)); \ + __asm__ ("add %1, %2, %0, %%tldo_add(" #x ")" : "=r" (__l) \ + : "r" (__o0), "r" (__o)); \ + __l; }) + +# define TLS_GD(x) \ + ({ int *__l; register void *__o0 __asm__ ("%o0"); \ + __asm__ ("sethi %%tgd_hi22(" #x "), %0" : "=r" (__l)); \ + __asm__ ("add %1, %%tgd_lo10(" #x "), %0" : "=r" (__l) : "r" (__l)); \ + __asm__ ("add %1, %2, %0, %%tgd_add(" #x ")" \ + : "=r" (__o0) : "r" (TLS_LOAD_PIC), "r" (__l)); \ + __asm__ ("call __tls_get_addr, %%tgd_call(" #x ")\n\t" \ + " nop" \ + : "=r" (__o0) : "0" (__o0) \ + : "g1", "g2", "g3", "g4", "g5", "g6", "o1", "o2", "o3", "o4", \ + "o5", "o7", "cc"); \ + __o0; }) + +#elif defined __s390x__ + +# define TLS_LE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@ntpoff\n" \ + "1:\tlg %0,0(%0)" \ + : "=a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@gotntpoff\n" \ + "1:\tlg %0,0(%0)\n\t" \ + "lg %0,0(%0,%%r12):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@indntpoff\n" \ + "1:\t lg %0,0(%0)\n\t" \ + "lg %0,0(%0):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsldm\n\t" \ + ".quad " #x "@dtpoff\n" \ + "1:\tlgr %1,%%r12\n\t" \ + "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ + "lg %0,8(%0)\n\t" \ + "algr %0,%%r2\n\t" \ + "lgr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_LD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsldm\n\t" \ + ".quad " #x "@dtpoff\n" \ + "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_ldcall:" #x "\n\t" \ + "lg %0,8(%0)\n\t" \ + "algr %0,%%r2" \ + : "=&a" (__offset) \ + : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsgd\n" \ + "1:\tlgr %1,%%r12\n\t" \ + "larl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ + "lgr %0,%%r2\n\t" \ + "lgr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_GD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.quad " #x "@tlsgd\n" \ + "1:\tlarl %%r12,_GLOBAL_OFFSET_TABLE_\n\t" \ + "lg %%r2,0(%0)\n\t" \ + "brasl %%r14,__tls_get_offset@plt:tls_gdcall:" #x "\n\t" \ + "lgr %0,%%r2" \ + : "=&a" (__offset) \ + : : "cc", "0", "1", "2", "3", "4", "5", "12", "14" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +#elif defined __s390__ + +# define TLS_LE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@ntpoff\n" \ + "1:\tl %0,0(%0)" \ + : "=a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) + +# ifdef PIC +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@gotntpoff\n" \ + "1:\tl %0,0(%0)\n\t" \ + "l %0,0(%0,%%r12):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_IE(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long " #x "@indntpoff\n" \ + "1:\t l %0,0(%0)\n\t" \ + "l %0,0(%0):tls_load:" #x \ + : "=&a" (__offset) : : "cc" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_LD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ + ".long __tls_get_offset@plt-0b\n\t" \ + ".long " #x "@tlsldm\n\t" \ + ".long " #x "@dtpoff\n" \ + "1:\tlr %1,%%r12\n\t" \ + "l %%r12,0(%0)\n\t" \ + "la %%r12,0(%%r12,%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1,%0):tls_ldcall:" #x "\n\t" \ + "l %0,12(%0)\n\t" \ + "alr %0,%%r2\n\t" \ + "lr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_LD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ + ".long __tls_get_offset@plt\n\t" \ + ".long " #x "@tlsldm\n\t" \ + ".long " #x "@dtpoff\n" \ + "1:\tl %%r12,0(%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1):tls_ldcall:" #x "\n\t" \ + "l %0,12(%0)\n\t" \ + "alr %0,%%r2" \ + : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +# ifdef PIC +# define TLS_GD(x) \ + ({ unsigned long __offset, __save12; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_-0b\n\t" \ + ".long __tls_get_offset@plt-0b\n\t" \ + ".long " #x "@tlsgd\n" \ + "1:\tlr %1,%%r12\n\t" \ + "l %%r12,0(%0)\n\t" \ + "la %%r12,0(%%r12,%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1,%0):tls_gdcall:" #x "\n\t" \ + "lr %0,%%r2\n\t" \ + "lr %%r12,%1" \ + : "=&a" (__offset), "=&a" (__save12) \ + : : "cc", "0", "1", "2", "3", "4", "5" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# else +# define TLS_GD(x) \ + ({ unsigned long __offset; \ + __asm__ ("bras %0,1f\n" \ + "0:\t.long _GLOBAL_OFFSET_TABLE_\n\t" \ + ".long __tls_get_offset@plt\n\t" \ + ".long " #x "@tlsgd\n" \ + "1:\tl %%r12,0(%0)\n\t" \ + "l %%r1,4(%0)\n\t" \ + "l %%r2,8(%0)\n\t" \ + "bas %%r14,0(%%r1):tls_gdcall:" #x "\n\t" \ + "lr %0,%%r2" \ + : "=&a" (__offset) : : "cc", "0", "1", "2", "3", "4", "5", "12" ); \ + (int *) (__builtin_thread_pointer() + __offset); }) +# endif + +#elif defined __powerpc__ && !defined __powerpc64__ + +#include "config.h" + +# define __TLS_CALL_CLOBBERS \ + "0", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", \ + "lr", "ctr", "cr0", "cr1", "cr5", "cr6", "cr7" + +/* PowerPC32 Local Exec TLS access. */ +# define TLS_LE(x) \ + ({ int *__result; \ + __asm__ ("addi %0,2," #x "@tprel" \ + : "=r" (__result)); \ + __result; }) + +/* PowerPC32 Initial Exec TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_IE(x) \ + ({ int *__result; \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr %0\n\t" \ + "addis %0,%0,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi %0,%0,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "lwz %0," #x "@got@tprel(%0)\n\t" \ + "add %0,%0," #x "@tls" \ + : "=b" (__result) : \ + : "lr"); \ + __result; }) +# else +# define TLS_IE(x) \ + ({ int *__result; \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr %0\n\t" \ + "lwz %0," #x "@got@tprel(%0)\n\t" \ + "add %0,%0," #x "@tls" \ + : "=b" (__result) : \ + : "lr"); \ + __result; }) +# endif + +/* PowerPC32 Local Dynamic TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_LD(x) \ + ({ int *__result; \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr 3\n\t" \ + "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "addi 3,3," #x "@got@tlsld\n\t" \ + "bl __tls_get_addr@plt\n\t" \ + "addi %0,3," #x "@dtprel" \ + : "=r" (__result) : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# else +# define TLS_LD(x) \ + ({ int *__result; \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr 3\n\t" \ + "addi 3,3," #x "@got@tlsld\n\t" \ + "bl __tls_get_addr@plt\n\t" \ + "addi %0,3," #x "@dtprel" \ + : "=r" (__result) : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# endif + +/* PowerPC32 General Dynamic TLS access. */ +# ifdef HAVE_ASM_PPC_REL16 +# define TLS_GD(x) \ + ({ register int *__result __asm__ ("r3"); \ + __asm__ ("bcl 20,31,1f\n1:\t" \ + "mflr 3\n\t" \ + "addis 3,3,_GLOBAL_OFFSET_TABLE_-1b@ha\n\t" \ + "addi 3,3,_GLOBAL_OFFSET_TABLE_-1b@l\n\t" \ + "addi 3,3," #x "@got@tlsgd\n\t" \ + "bl __tls_get_addr@plt" \ + : : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# else +# define TLS_GD(x) \ + ({ register int *__result __asm__ ("r3"); \ + __asm__ ("bl _GLOBAL_OFFSET_TABLE_@local-4\n\t" \ + "mflr 3\n\t" \ + "addi 3,3," #x "@got@tlsgd\n\t" \ + "bl __tls_get_addr@plt" \ + : : \ + : __TLS_CALL_CLOBBERS); \ + __result; }) +# endif + +#elif defined __powerpc__ && defined __powerpc64__ + +/* PowerPC64 Local Exec TLS access. */ +# define TLS_LE(x) \ + ({ int * __result; \ + __asm__ ( \ + " addis %0,13," #x "@tprel@ha\n" \ + " addi %0,%0," #x "@tprel@l\n" \ + : "=b" (__result) ); \ + __result; \ + }) +/* PowerPC64 Initial Exec TLS access. */ +# define TLS_IE(x) \ + ({ int * __result; \ + __asm__ ( \ + " ld %0," #x "@got@tprel(2)\n" \ + " add %0,%0," #x "@tls\n" \ + : "=b" (__result) ); \ + __result; \ + }) +/* PowerPC64 Local Dynamic TLS access. */ +# define TLS_LD(x) \ + ({ int * __result; \ + __asm__ ( \ + " addi 3,2," #x "@got@tlsld\n" \ + " bl .__tls_get_addr\n" \ + " nop \n" \ + " addis %0,3," #x "@dtprel@ha\n" \ + " addi %0,%0," #x "@dtprel@l\n" \ + : "=b" (__result) : \ + : "0", "3", "4", "5", "6", "7", \ + "8", "9", "10", "11", "12", \ + "lr", "ctr", \ + "cr0", "cr1", "cr5", "cr6", "cr7"); \ + __result; \ + }) +/* PowerPC64 General Dynamic TLS access. */ +# define TLS_GD(x) \ + ({ int * __result; \ + __asm__ ( \ + " addi 3,2," #x "@got@tlsgd\n" \ + " bl .__tls_get_addr\n" \ + " nop \n" \ + " mr %0,3\n" \ + : "=b" (__result) : \ + : "0", "3", "4", "5", "6", "7", \ + "8", "9", "10", "11", "12", \ + "lr", "ctr", \ + "cr0", "cr1", "cr5", "cr6", "cr7"); \ + __result; \ + }) + +#elif !defined TLS_LE || !defined TLS_IE \ + || !defined TLS_LD || !defined TLS_GD +# error "No support for this architecture so far." +#endif diff --git a/test/tls/tst-tls-at-ctor.c b/test/tls/tst-tls-at-ctor.c new file mode 100644 index 000000000..53aece181 --- /dev/null +++ b/test/tls/tst-tls-at-ctor.c @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <stdlib.h> +#include <tls.h> + +#define TLS_VAR_INIT_VALUE 99 + +#ifdef USE_TLS +extern __thread int tls_var; +#endif + +int main(void) +{ + int ret = EXIT_SUCCESS; +#ifdef USE_TLS + if (tls_var != TLS_VAR_INIT_VALUE) { + printf("tls_var = %d - Expected value = %d\n", tls_var, TLS_VAR_INIT_VALUE); + ret = EXIT_FAILURE; + } +#endif + return ret; +} diff --git a/test/tls/tst-tls1-static.c b/test/tls/tst-tls1-static.c new file mode 100644 index 000000000..a01008073 --- /dev/null +++ b/test/tls/tst-tls1-static.c @@ -0,0 +1 @@ +#include "tst-tls1.c" diff --git a/test/tls/tst-tls1.c b/test/tls/tst-tls1.c new file mode 100644 index 000000000..f5ac6d2bc --- /dev/null +++ b/test/tls/tst-tls1.c @@ -0,0 +1,92 @@ +/* glibc test for TLS in ld.so. */ +#undef _LIBC +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* Two common 'int' variables in TLS. */ +COMMON_INT_DEF(foo); +COMMON_INT_DEF(bar); +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp; + + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); + ap = TLS_LE (bar); + *ap = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo and bar (LD)", stdout); + ap = TLS_LD (foo); + bp = TLS_LD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls10.c b/test/tls/tst-tls10.c new file mode 100644 index 000000000..fc0677072 --- /dev/null +++ b/test/tls/tst-tls10.c @@ -0,0 +1,40 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A local = { 1, 2, 3 }; +#endif + +#define CHECK(N, S) \ + p = f##N##a (); \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ + struct A *p; + if (local.a != 1 || local.b != 2 || local.c != 3) + abort (); +#ifdef USE_TLS__THREAD + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + check1 (); + check2 (); + if (f1a () != &a1 || f2a () != &a2 || f3a () != &a3 || f4a () != &a4) + abort (); + CHECK (5, 16); + CHECK (6, 19); + if (f7a () != &a2 || f8a () != &a4) + abort (); + CHECK (9, 28); + CHECK (10, 31); +#endif + exit (0); +} diff --git a/test/tls/tst-tls10.h b/test/tls/tst-tls10.h new file mode 100644 index 000000000..1be6adc29 --- /dev/null +++ b/test/tls/tst-tls10.h @@ -0,0 +1,38 @@ +#include <tls.h> +#include <stdlib.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +# define USE_TLS__THREAD + +struct A +{ + char a; + int b; + long long c; +}; + +extern __thread struct A a1, a2, a3, a4; +extern struct A *f1a (void); +extern struct A *f2a (void); +extern struct A *f3a (void); +extern struct A *f4a (void); +extern struct A *f5a (void); +extern struct A *f6a (void); +extern struct A *f7a (void); +extern struct A *f8a (void); +extern struct A *f9a (void); +extern struct A *f10a (void); +extern int f1b (void); +extern int f2b (void); +extern int f3b (void); +extern int f4b (void); +extern int f5b (void); +extern int f6b (void); +extern int f7b (void); +extern int f8b (void); +extern int f9b (void); +extern int f10b (void); +extern void check1 (void); +extern void check2 (void); +#endif diff --git a/test/tls/tst-tls11.c b/test/tls/tst-tls11.c new file mode 100644 index 000000000..816cf5cc2 --- /dev/null +++ b/test/tls/tst-tls11.c @@ -0,0 +1,27 @@ +#include "tst-tls10.h" + +#define CHECK(N, S) \ + p = f##N##a (); \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ +#ifdef USE_TLS__THREAD + struct A *p; + check1 (); + check2 (); + CHECK (1, 4); + CHECK (2, 22); + CHECK (3, 10); + CHECK (4, 25); + CHECK (5, 16); + CHECK (6, 19); + CHECK (7, 22); + CHECK (8, 25); + CHECK (9, 28); + CHECK (10, 31); +#endif + exit (0); +} diff --git a/test/tls/tst-tls12.c b/test/tls/tst-tls12.c new file mode 100644 index 000000000..84aa7d35c --- /dev/null +++ b/test/tls/tst-tls12.c @@ -0,0 +1,18 @@ +#include "tst-tls10.h" + +#define CHECK(N, S) \ + p = &a##N; \ + if (p->a != S || p->b != S + 1 || p->c != S + 2) \ + abort () + +int +main (void) +{ +#ifdef USE_TLS__THREAD + struct A *p; + check1 (); + CHECK (1, 4); + CHECK (2, 7); +#endif + exit (0); +} diff --git a/test/tls/tst-tls13.c b/test/tls/tst-tls13.c new file mode 100644 index 000000000..55fb62e54 --- /dev/null +++ b/test/tls/tst-tls13.c @@ -0,0 +1,30 @@ +/* Check unloading modules with data in static TLS block. */ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + + +static int +do_test (void) +{ + int i; + for (i = 0; i < 1000;) + { + printf ("round %d\n",++i); + + void *h = dlopen ("tst-tlsmod13a.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot load: %s\n", dlerror ()); + exit (1); + } + + dlclose (h); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 3 +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls14.c b/test/tls/tst-tls14.c new file mode 100644 index 000000000..428fd5293 --- /dev/null +++ b/test/tls/tst-tls14.c @@ -0,0 +1,66 @@ +/* Check alignment of TLS variable. */ +#include <dlfcn.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +extern int in_dso1 (void); + + +static int +do_test (void) +{ + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + result |= in_dso1 (); + + void *h = dlopen ("tst-tlsmod14b.so", RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open tst-tlsmod14b.so: %m\n"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso2"); + if (fp == NULL) + { + puts ("cannot find in_dso2"); + exit (1); + } + + result |= fp (); + + return result; +} + +#define TEST_FUNCTION do_test () + +#else + +#define TEST_FUNCTION 0 + +#endif + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls15.c b/test/tls/tst-tls15.c new file mode 100644 index 000000000..2c2df251b --- /dev/null +++ b/test/tls/tst-tls15.c @@ -0,0 +1,33 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + void *h = dlopen ("tst-tlsmod15a.so", RTLD_NOW); + if (h != NULL) + { + puts ("unexpectedly succeeded to open tst-tlsmod15a.so"); + exit (1); + } + + h = dlopen ("tst-tlsmod15b.so", RTLD_NOW); + if (h == NULL) + { + puts ("failed to open tst-tlsmod15b.so"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso"); + if (fp == NULL) + { + puts ("cannot find in_dso"); + exit (1); + } + + return fp (); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls16.c b/test/tls/tst-tls16.c new file mode 100644 index 000000000..17912dc30 --- /dev/null +++ b/test/tls/tst-tls16.c @@ -0,0 +1,53 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + void *h = dlopen ("tst-tlsmod16a.so", RTLD_LAZY | RTLD_GLOBAL); + if (h == NULL) + { + puts ("unexpectedly failed to open tst-tlsmod16a.so"); + exit (1); + } + + void *p = dlsym (h, "tlsvar"); + + /* This dlopen should indeed fail, because tlsvar was assigned to + dynamic TLS, and the new module requests it to be in static TLS. + However, there's a possibility that dlopen succeeds if the + variable is, for whatever reason, assigned to static TLS, or if + the module fails to require static TLS, or even if TLS is not + supported. */ + h = dlopen ("tst-tlsmod16b.so", RTLD_NOW | RTLD_GLOBAL); + if (h == NULL) + { + return 0; + } + + puts ("unexpectedly succeeded to open tst-tlsmod16b.so"); + + + void *(*fp) (void) = (void *(*) (void)) dlsym (h, "in_dso"); + if (fp == NULL) + { + puts ("cannot find in_dso"); + exit (1); + } + + /* If the dlopen passes, at least make sure the address returned by + dlsym is the same as that returned by the initial-exec access. + If the variable was assigned to dynamic TLS during dlsym, this + portion will fail. */ + if (fp () != p) + { + puts ("returned values do not match"); + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls17.c b/test/tls/tst-tls17.c new file mode 100644 index 000000000..c1bc7d8f4 --- /dev/null +++ b/test/tls/tst-tls17.c @@ -0,0 +1,29 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + void *h = dlopen ("tst-tlsmod17b.so", RTLD_LAZY); + if (h == NULL) + { + puts ("unexpectedly failed to open tst-tlsmod17b.so"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "tlsmod17b"); + if (fp == NULL) + { + puts ("cannot find tlsmod17b"); + exit (1); + } + + if (fp ()) + exit (1); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls18.c b/test/tls/tst-tls18.c new file mode 100644 index 000000000..00dcdff4e --- /dev/null +++ b/test/tls/tst-tls18.c @@ -0,0 +1,38 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +static int +do_test (void) +{ + char modname[sizeof "tst-tlsmod18aXX.so"]; + void *h[20]; + for (int i = 0; i < 20; i++) + { + snprintf (modname, sizeof modname, "tst-tlsmod18a%d.so", i); + h[i] = dlopen (modname, RTLD_LAZY); + if (h[i] == NULL) + { + printf ("unexpectedly failed to open %s", modname); + exit (1); + } + } + + for (int i = 0; i < 20; i++) + { + int (*fp) (void) = (int (*) (void)) dlsym (h[i], "test"); + if (fp == NULL) + { + printf ("cannot find test in tst-tlsmod18a%d.so", i); + exit (1); + } + + if (fp ()) + exit (1); + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls2-static.c b/test/tls/tst-tls2-static.c new file mode 100644 index 000000000..55ffa5744 --- /dev/null +++ b/test/tls/tst-tls2-static.c @@ -0,0 +1 @@ +#include "tst-tls2.c" diff --git a/test/tls/tst-tls2.c b/test/tls/tst-tls2.c new file mode 100644 index 000000000..417489968 --- /dev/null +++ b/test/tls/tst-tls2.c @@ -0,0 +1,91 @@ +/* glibc test for TLS in ld.so. */ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* Two 'int' variables in TLS. */ +VAR_INT_DEF(foo); +VAR_INT_DEF(bar); +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp; + + + /* Set the variable using the local exec model. */ + puts ("set bar to 1 (LE)"); + ap = TLS_LE (bar); + *ap = 1; + + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo and bar (LD)", stdout); + ap = TLS_LD (foo); + bp = TLS_LD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 1; + if (*ap != 0) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 1) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls3.c b/test/tls/tst-tls3.c new file mode 100644 index 000000000..84be43575 --- /dev/null +++ b/test/tls/tst-tls3.c @@ -0,0 +1,76 @@ +/* glibc test for TLS in ld.so. */ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +/* One define int variable, two externs. */ +COMMON_INT_DECL(foo); +VAR_INT_DECL(bar); +VAR_INT_DEF(baz); +#endif + + +extern int in_dso (void); + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + int result = 0; + int *ap, *bp, *cp; + + + /* Set the variable using the local exec model. */ + puts ("set baz to 3 (LE)"); + ap = TLS_LE (baz); + *ap = 3; + + + /* Get variables using initial exec model. */ + puts ("set variables foo and bar (IE)"); + ap = TLS_IE (foo); + *ap = 1; + bp = TLS_IE (bar); + *bp = 2; + + + /* Get variables using local dynamic model. */ + fputs ("get sum of foo, bar (GD) and baz (LD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + cp = TLS_LD (baz); + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + if (*cp != 3) + { + printf ("baz = %d\n", *cp); + result = 1; + } + + + result |= in_dso (); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls4.c b/test/tls/tst-tls4.c new file mode 100644 index 000000000..f92ee53ce --- /dev/null +++ b/test/tls/tst-tls4.c @@ -0,0 +1,56 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int (*fp) (int, int *); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (0, NULL); + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls5.c b/test/tls/tst-tls5.c new file mode 100644 index 000000000..a571d2cd3 --- /dev/null +++ b/test/tls/tst-tls5.c @@ -0,0 +1,72 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int *foop2; + int (*fp) (int, int *); + void *h; + + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo': %s\n", dlerror ()); + exit (1); + } + + *foop = 42; + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (42, foop); + + foop2 = dlsym (h, "foo"); + if (foop2 == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + + if (foop != foop2) + { + puts ("address of 'foo' different the second time"); + result = 1; + } + else if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls6.c b/test/tls/tst-tls6.c new file mode 100644 index 000000000..e692aca6b --- /dev/null +++ b/test/tls/tst-tls6.c @@ -0,0 +1,108 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod2.so"; + int result = 0; + int *foop; + int *foop2; + int (*fp) (int, int *); + void *h; + int i; + int modid = -1; + + for (i = 0; i < 10; ++i) + { + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid == -1) + modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid + != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, + ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid, + modid); + result = 1; + } +#else + if (modid == -1) + modid = ((struct link_map *) h)->l_tls_modid; + else if (((struct link_map *) h)->l_tls_modid != modid) + { + printf ("round %d: modid now %zd, initially %d\n", + i, ((struct link_map *) h)->l_tls_modid, modid); + result = 1; + } +#endif + + foop = dlsym (h, "foo"); + if (foop == NULL) + { + printf ("cannot get symbol 'foo': %s\n", dlerror ()); + exit (1); + } + + *foop = 42 + i; + + fp = dlsym (h, "in_dso"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso': %s\n", dlerror ()); + exit (1); + } + + result |= fp (42 + i, foop); + + foop2 = dlsym (h, "foo"); + if (foop2 == NULL) + { + printf ("cannot get symbol 'foo' the second time: %s\n", dlerror ()); + exit (1); + } + + if (foop != foop2) + { + puts ("address of 'foo' different the second time"); + result = 1; + } + else if (*foop != 16) + { + puts ("foo != 16"); + result = 1; + } + + dlclose (h); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls7.c b/test/tls/tst-tls7.c new file mode 100644 index 000000000..41da2708d --- /dev/null +++ b/test/tls/tst-tls7.c @@ -0,0 +1,79 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname[] = "tst-tlsmod3.so"; + int result = 0; + int (*fp) (void); + void *h; + int i; + int modid = -1; + + for (i = 0; i < 10; ++i) + { + h = dlopen (modname, RTLD_LAZY); + if (h == NULL) + { + printf ("cannot open '%s': %s\n", modname, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid == -1) + modid = ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid + != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, + ((struct link_map *)((struct dyn_elf *)h)->dyn)->l_tls_modid, + modid); + result = 1; + } +#else + if (modid == -1) + modid = ((struct link_map *) h)->l_tls_modid; + else if (((struct link_map *) h)->l_tls_modid != (size_t) modid) + { + printf ("round %d: modid now %zu, initially %d\n", + i, ((struct link_map *) h)->l_tls_modid, modid); + result = 1; + } +#endif + + fp = dlsym (h, "in_dso2"); + if (fp == NULL) + { + printf ("cannot get symbol 'in_dso2': %s\n", dlerror ()); + exit (1); + } + + result |= fp (); + + dlclose (h); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls8.c b/test/tls/tst-tls8.c new file mode 100644 index 000000000..2541609f1 --- /dev/null +++ b/test/tls/tst-tls8.c @@ -0,0 +1,230 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <tls.h> +#include <link.h> +#ifdef __UCLIBC__ +#include "dl-elf.h" +#include "dl-hash.h" +#endif + + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname1[] = "tst-tlsmod3.so"; + static const char modname2[] = "tst-tlsmod4.so"; + int result = 0; + int (*fp1) (void); + int (*fp2) (int, int *); + void *h1; + void *h2; + int i; + size_t modid1 = (size_t) -1; + size_t modid2 = (size_t) -1; + int *bazp; + + for (i = 0; i < 10; ++i) + { + h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid1 == (size_t) -1) + modid1 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != (size_t) modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid1); + result = 1; + } +#else + if (modid1 == (size_t) -1) + modid1 = ((struct link_map *) h1)->l_tls_modid; + else if (((struct link_map *) h1)->l_tls_modid != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid1); + result = 1; + } +#endif + + fp1 = dlsym (h1, "in_dso2"); + if (fp1 == NULL) + { + printf ("cannot get symbol 'in_dso2' in %s\n", modname1); + exit (1); + } + + result |= fp1 (); + + + + h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (modid2 == (size_t) -1) + modid2 = ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid; + else if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != (size_t) modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid2); + result = 1; + } +#else + if (modid2 == (size_t) -1) + modid2 = ((struct link_map *) h1)->l_tls_modid; + else if (((struct link_map *) h1)->l_tls_modid != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid2); + result = 1; + } +#endif + + bazp = dlsym (h2, "baz"); + if (bazp == NULL) + { + printf ("cannot get symbol 'baz' in %s\n", modname2); + exit (1); + } + + *bazp = 42 + i; + + fp2 = dlsym (h2, "in_dso"); + if (fp2 == NULL) + { + printf ("cannot get symbol 'in_dso' in %s\n", modname2); + exit (1); + } + + result |= fp2 (42 + i, bazp); + + dlclose (h1); + dlclose (h2); + + + h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid1); + result = 1; + } +#else + if (((struct link_map *) h1)->l_tls_modid != modid1) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid1); + result = 1; + } +#endif + + fp1 = dlsym (h1, "in_dso2"); + if (fp1 == NULL) + { + printf ("cannot get symbol 'in_dso2' in %s\n", modname1); + exit (1); + } + + result |= fp1 (); + + + + h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + exit (1); + } + + /* Dirty test code here: we peek into a private data structure. + We make sure that the module gets assigned the same ID every + time. The value of the first round is used. */ +#ifdef __UCLIBC__ + if (((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid + != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, + ((struct link_map *)((struct dyn_elf *)h1)->dyn)->l_tls_modid, + modid2); + result = 1; + } +#else + if (((struct link_map *) h1)->l_tls_modid != modid2) + { + printf ("round %d: modid now %zd, initially %zd\n", + i, ((struct link_map *) h1)->l_tls_modid, modid2); + result = 1; + } +#endif + + bazp = dlsym (h2, "baz"); + if (bazp == NULL) + { + printf ("cannot get symbol 'baz' in %s\n", modname2); + exit (1); + } + + *bazp = 62 + i; + + fp2 = dlsym (h2, "in_dso"); + if (fp2 == NULL) + { + printf ("cannot get symbol 'in_dso' in %s\n", modname2); + exit (1); + } + + result |= fp2 (62 + i, bazp); + + /* This time the dlclose calls are in reverse order. */ + dlclose (h2); + dlclose (h1); + } + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tls9-static.c b/test/tls/tst-tls9-static.c new file mode 100644 index 000000000..51812ccc7 --- /dev/null +++ b/test/tls/tst-tls9-static.c @@ -0,0 +1 @@ +#include "tst-tls9.c" diff --git a/test/tls/tst-tls9.c b/test/tls/tst-tls9.c new file mode 100644 index 000000000..e317696df --- /dev/null +++ b/test/tls/tst-tls9.c @@ -0,0 +1,42 @@ +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +#include <link.h> +#include <tls.h> + +#define TEST_FUNCTION do_test () +static int +do_test (void) +{ +#ifdef USE_TLS + static const char modname1[] = "tst-tlsmod5.so"; + static const char modname2[] = "tst-tlsmod6.so"; + int result = 0; + + void *h1 = dlopen (modname1, RTLD_LAZY); + if (h1 == NULL) + { + printf ("cannot open '%s': %s\n", modname1, dlerror ()); + result = 1; + } + void *h2 = dlopen (modname2, RTLD_LAZY); + if (h2 == NULL) + { + printf ("cannot open '%s': %s\n", modname2, dlerror ()); + result = 1; + } + + if (h1 != NULL) + dlclose (h1); + if (h2 != NULL) + dlclose (h2); + + return result; +#else + return 0; +#endif +} + + +#include "../test-skeleton.c" diff --git a/test/tls/tst-tlsmod-at-ctor.c b/test/tls/tst-tlsmod-at-ctor.c new file mode 100644 index 000000000..bd04b5081 --- /dev/null +++ b/test/tls/tst-tlsmod-at-ctor.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <tls.h> + +#define TLS_VAR_INIT_VALUE 99 + +#ifdef USE_TLS +__thread int tls_var __attribute__((tls_model("global-dynamic"))); +static __thread int local_tls_var __attribute__((tls_model("local-dynamic"))); +#endif + +void __attribute__((constructor)) libtls_ctor(void); +void libtls_ctor(void) +{ + printf("libtls: constructor!\n"); +#ifdef USE_TLS + local_tls_var = TLS_VAR_INIT_VALUE; + tls_var = local_tls_var; +#endif +} + +void __attribute__((destructor)) libtls_dtor(void); +void libtls_dtor(void) +{ + printf("libtls: destructor!\n"); +} diff --git a/test/tls/tst-tlsmod1.c b/test/tls/tst-tlsmod1.c new file mode 100644 index 000000000..b4954ca3e --- /dev/null +++ b/test/tls/tst-tlsmod1.c @@ -0,0 +1,68 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + + +/* One define int variable, two externs. */ +COMMON_INT_DEF(foo); +VAR_INT_DEF(bar); +VAR_INT_DECL(baz); +#endif + +extern int in_dso (void); + +int +in_dso (void) +{ + int result = 0; +#ifdef USE_TLS + int *ap, *bp, *cp; + + /* Get variables using initial exec model. */ + fputs ("get sum of foo and bar (IE)", stdout); + __asm__ ("" ::: "memory"); + ap = TLS_IE (foo); + bp = TLS_IE (bar); + printf (" = %d\n", *ap + *bp); + result |= *ap + *bp != 3; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + + + /* Get variables using generic dynamic model. */ + fputs ("get sum of foo and bar and baz (GD)", stdout); + ap = TLS_GD (foo); + bp = TLS_GD (bar); + cp = TLS_GD (baz); + printf (" = %d\n", *ap + *bp + *cp); + result |= *ap + *bp + *cp != 6; + if (*ap != 1) + { + printf ("foo = %d\n", *ap); + result = 1; + } + if (*bp != 2) + { + printf ("bar = %d\n", *bp); + result = 1; + } + if (*cp != 3) + { + printf ("baz = %d\n", *cp); + result = 1; + } +#endif + + return result; +} diff --git a/test/tls/tst-tlsmod10.c b/test/tls/tst-tlsmod10.c new file mode 100644 index 000000000..32e54f3c0 --- /dev/null +++ b/test/tls/tst-tlsmod10.c @@ -0,0 +1 @@ +#include "tst-tlsmod8.c" diff --git a/test/tls/tst-tlsmod11.c b/test/tls/tst-tlsmod11.c new file mode 100644 index 000000000..9938b5753 --- /dev/null +++ b/test/tls/tst-tlsmod11.c @@ -0,0 +1,6 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a2 = { 7, 8, 9 }; +#endif diff --git a/test/tls/tst-tlsmod12.c b/test/tls/tst-tlsmod12.c new file mode 100644 index 000000000..4602709a1 --- /dev/null +++ b/test/tls/tst-tlsmod12.c @@ -0,0 +1,14 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +extern __thread struct A a2 __attribute__((tls_model("initial-exec"))); + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 7 || a2.b != 8 || a2.c != 9) + abort (); +} +#endif diff --git a/test/tls/tst-tlsmod13.c b/test/tls/tst-tlsmod13.c new file mode 100644 index 000000000..beca89f6f --- /dev/null +++ b/test/tls/tst-tlsmod13.c @@ -0,0 +1,14 @@ +#include <tls.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +__thread int a[2] __attribute__ ((tls_model ("initial-exec"))); +#else +int a[2]; +#endif + +int +foo (void) +{ + return a[0]; +} diff --git a/test/tls/tst-tlsmod13a.c b/test/tls/tst-tlsmod13a.c new file mode 100644 index 000000000..14b12b032 --- /dev/null +++ b/test/tls/tst-tlsmod13a.c @@ -0,0 +1,16 @@ +#include <tls.h> + +#if defined USE_TLS && defined HAVE___THREAD \ + && defined HAVE_TLS_MODEL_ATTRIBUTE +__thread int b[2] __attribute__ ((tls_model ("initial-exec"))); +#else +int b[2]; +#endif + +extern int foo (void); + +int +bar (void) +{ + return foo () + b[0]; +} diff --git a/test/tls/tst-tlsmod14a.c b/test/tls/tst-tlsmod14a.c new file mode 100644 index 000000000..0bb393d9c --- /dev/null +++ b/test/tls/tst-tlsmod14a.c @@ -0,0 +1,41 @@ +#include <stdint.h> +#include <stdio.h> + +#include <tls.h> + +#if USE_TLS && HAVE___THREAD + +#define AL 4096 +struct foo +{ + int i; +} __attribute ((aligned (AL))); + +static __thread struct foo f; +static struct foo g; + + +#ifndef FCT +# define FCT in_dso1 +#endif + + +int +FCT (void) +{ + puts (__func__); + + int result = 0; + + int fail = (((uintptr_t) &f) & (AL - 1)) != 0; + printf ("&f = %p %s\n", &f, fail ? "FAIL" : "OK"); + result |= fail; + + fail = (((uintptr_t) &g) & (AL - 1)) != 0; + printf ("&g = %p %s\n", &g, fail ? "FAIL" : "OK"); + result |= fail; + + return result; +} + +#endif diff --git a/test/tls/tst-tlsmod14b.c b/test/tls/tst-tlsmod14b.c new file mode 100644 index 000000000..24d9ceaf7 --- /dev/null +++ b/test/tls/tst-tlsmod14b.c @@ -0,0 +1,2 @@ +#define FCT in_dso2 +#include "tst-tlsmod14a.c" diff --git a/test/tls/tst-tlsmod15a.c b/test/tls/tst-tlsmod15a.c new file mode 100644 index 000000000..66c707129 --- /dev/null +++ b/test/tls/tst-tlsmod15a.c @@ -0,0 +1,6 @@ +extern int nonexistent_dummy_var; +int * +foo (void) +{ + return &nonexistent_dummy_var; +} diff --git a/test/tls/tst-tlsmod15b.c b/test/tls/tst-tlsmod15b.c new file mode 100644 index 000000000..4f63eab14 --- /dev/null +++ b/test/tls/tst-tlsmod15b.c @@ -0,0 +1,17 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int mod15b_var __attribute__((tls_model("initial-exec"))); + +int +in_dso (void) +{ + return mod15b_var; +} +#else +int +in_dso (void) +{ + return 0; +} +#endif diff --git a/test/tls/tst-tlsmod16a.c b/test/tls/tst-tlsmod16a.c new file mode 100644 index 000000000..847c8090f --- /dev/null +++ b/test/tls/tst-tlsmod16a.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE +int __thread tlsvar; +#else +int tlsvar; +#endif diff --git a/test/tls/tst-tlsmod16b.c b/test/tls/tst-tlsmod16b.c new file mode 100644 index 000000000..308e6bae9 --- /dev/null +++ b/test/tls/tst-tlsmod16b.c @@ -0,0 +1,13 @@ +#include <tls.h> + +#if defined HAVE___THREAD && defined HAVE_TLS_MODEL_ATTRIBUTE +extern __thread int tlsvar __attribute__((tls_model("initial-exec"))); +#else +extern int tlsvar; +#endif + +void * +in_dso (void) +{ + return &tlsvar; +} diff --git a/test/tls/tst-tlsmod17a.c b/test/tls/tst-tlsmod17a.c new file mode 100644 index 000000000..eb599e726 --- /dev/null +++ b/test/tls/tst-tlsmod17a.c @@ -0,0 +1,23 @@ +#include <stdio.h> + +#ifndef N +#define N 0 +#endif +#define CONCAT1(s, n) s##n +#define CONCAT(s, n) CONCAT1(s, n) + +__thread int CONCAT (v, N) = 4; + +int +CONCAT (tlsmod17a, N) (void) +{ + int *p = &CONCAT (v, N); + /* GCC assumes &var is never NULL, add optimization barrier. */ + __asm __volatile ("" : "+r" (p)); + if (p == NULL || *p != 4) + { + printf ("fail %d %p\n", N, p); + return 1; + } + return 0; +} diff --git a/test/tls/tst-tlsmod17b.c b/test/tls/tst-tlsmod17b.c new file mode 100644 index 000000000..617882873 --- /dev/null +++ b/test/tls/tst-tlsmod17b.c @@ -0,0 +1,15 @@ +#define P(N) extern int tlsmod17a##N (void); +#define PS P(0) P(1) P(2) P(3) P(4) P(5) P(6) P(7) P(8) P(9) \ + P(10) P(12) P(13) P(14) P(15) P(16) P(17) P(18) P(19) +PS +#undef P + +int +tlsmod17b (void) +{ + int res = 0; +#define P(N) res |= tlsmod17a##N (); + PS +#undef P + return res; +} diff --git a/test/tls/tst-tlsmod18a.c b/test/tls/tst-tlsmod18a.c new file mode 100644 index 000000000..9aba607ed --- /dev/null +++ b/test/tls/tst-tlsmod18a.c @@ -0,0 +1,21 @@ +#include <stdio.h> + +#ifndef N +# define N 0 +#endif + +static __thread int var = 4; + +int +test (void) +{ + int *p = &var; + /* GCC assumes &var is never NULL, add optimization barrier. */ + __asm __volatile ("" : "+r" (p)); + if (p == NULL || *p != 4) + { + printf ("fail %d %p\n", N, p); + return 1; + } + return 0; +} diff --git a/test/tls/tst-tlsmod2.c b/test/tls/tst-tlsmod2.c new file mode 100644 index 000000000..4547c9716 --- /dev/null +++ b/test/tls/tst-tlsmod2.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + + +COMMON_INT_DEF(foo); + + +int +in_dso (int n, int *caller_foop) +{ + int *foop; + int result = 0; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + foop = TLS_GD (foo); + + if (caller_foop != NULL && foop != caller_foop) + { + printf ("callers address of foo differs: %p vs %p\n", caller_foop, foop); + result = 1; + } + else if (*foop != n) + { + printf ("foo != %d\n", n); + result = 1; + } + + *foop = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod3.c b/test/tls/tst-tlsmod3.c new file mode 100644 index 000000000..12505f623 --- /dev/null +++ b/test/tls/tst-tlsmod3.c @@ -0,0 +1,41 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + +extern int in_dso (int n, int *caller_foop); + +COMMON_INT_DEF(comm_n); + + + + +int +in_dso2 (void) +{ + int *foop; + int result = 0; + static int n; + int *np; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + foop = TLS_GD (foo); + np = TLS_GD (comm_n); + + if (n != *np) + { + printf ("n = %d != comm_n = %d\n", n, *np); + result = 1; + } + + result |= in_dso (*foop = 42 + n++, foop); + + *foop = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod4.c b/test/tls/tst-tlsmod4.c new file mode 100644 index 000000000..4893cdae7 --- /dev/null +++ b/test/tls/tst-tlsmod4.c @@ -0,0 +1,38 @@ +#include <stdio.h> + +#include <tls.h> + +#ifdef USE_TLS +# include "tls-macros.h" + + +COMMON_INT_DEF(baz); + + +int +in_dso (int n, int *caller_bazp) +{ + int *bazp; + int result = 0; + + puts ("foo"); /* Make sure PLT is used before macros. */ + __asm__ ("" ::: "memory"); + + bazp = TLS_GD (baz); + + if (caller_bazp != NULL && bazp != caller_bazp) + { + printf ("callers address of baz differs: %p vs %p\n", caller_bazp, bazp); + result = 1; + } + else if (*bazp != n) + { + printf ("baz != %d\n", n); + result = 1; + } + + *bazp = 16; + + return result; +} +#endif diff --git a/test/tls/tst-tlsmod5.c b/test/tls/tst-tlsmod5.c new file mode 100644 index 000000000..2ec69e13b --- /dev/null +++ b/test/tls/tst-tlsmod5.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + +COMMON_INT_DEF(foo); +#endif diff --git a/test/tls/tst-tlsmod6.c b/test/tls/tst-tlsmod6.c new file mode 100644 index 000000000..0fda51b22 --- /dev/null +++ b/test/tls/tst-tlsmod6.c @@ -0,0 +1,7 @@ +#include <tls.h> + +#ifdef USE_TLS +#include "tls-macros.h" + +COMMON_INT_DEF(bar); +#endif diff --git a/test/tls/tst-tlsmod7.c b/test/tls/tst-tlsmod7.c new file mode 100644 index 000000000..944b97f9c --- /dev/null +++ b/test/tls/tst-tlsmod7.c @@ -0,0 +1,103 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a2 = { 7, 8, 9 }; +__thread struct A a3 __attribute__((tls_model("initial-exec"))) + = { 10, 11, 12 }; +__thread struct A a4 __attribute__((tls_model("initial-exec"))) + = { 13, 14, 15 }; +static __thread struct A local1 = { 16, 17, 18 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 19, 20, 21 }; + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 16 || local1.b != 17 || local1.c != 18) + abort (); + if (local2.a != 19 || local2.b != 20 || local2.c != 21) + abort (); +} + +struct A * +f1a (void) +{ + return &a1; +} + +struct A * +f2a (void) +{ + return &a2; +} + +struct A * +f3a (void) +{ + return &a3; +} + +struct A * +f4a (void) +{ + return &a4; +} + +struct A * +f5a (void) +{ + return &local1; +} + +struct A * +f6a (void) +{ + return &local2; +} + +int +f1b (void) +{ + return a1.a; +} + +int +f2b (void) +{ + return a2.b; +} + +int +f3b (void) +{ + return a3.c; +} + +int +f4b (void) +{ + return a4.a; +} + +int +f5b (void) +{ + return local1.b; +} + +int +f6b (void) +{ + return local2.c; +} +#endif diff --git a/test/tls/tst-tlsmod8.c b/test/tls/tst-tlsmod8.c new file mode 100644 index 000000000..c1822fc0c --- /dev/null +++ b/test/tls/tst-tlsmod8.c @@ -0,0 +1,72 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread long long dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a2 = { 22, 23, 24 }; +__thread struct A a4 __attribute__((tls_model("initial-exec"))) + = { 25, 26, 27 }; +static __thread struct A local1 = { 28, 29, 30 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 31, 32, 33 }; + +void +check2 (void) +{ + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 28 || local1.b != 29 || local1.c != 30) + abort (); + if (local2.a != 31 || local2.b != 32 || local2.c != 33) + abort (); +} + +struct A * +f7a (void) +{ + return &a2; +} + +struct A * +f8a (void) +{ + return &a4; +} + +struct A * +f9a (void) +{ + return &local1; +} + +struct A * +f10a (void) +{ + return &local2; +} + +int +f7b (void) +{ + return a2.b; +} + +int +f8b (void) +{ + return a4.a; +} + +int +f9b (void) +{ + return local1.b; +} + +int +f10b (void) +{ + return local2.c; +} +#endif diff --git a/test/tls/tst-tlsmod9.c b/test/tls/tst-tlsmod9.c new file mode 100644 index 000000000..e124144e4 --- /dev/null +++ b/test/tls/tst-tlsmod9.c @@ -0,0 +1,101 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int dummy __attribute__((visibility ("hidden"))) = 12; +__thread struct A a1 = { 4, 5, 6 }; +__thread struct A a3 __attribute__((tls_model("initial-exec"))) + = { 10, 11, 12 }; +extern __thread struct A a4 __attribute__((tls_model("initial-exec"))); +static __thread struct A local1 = { 16, 17, 18 }; +static __thread struct A local2 __attribute__((tls_model("initial-exec"))) + = { 19, 20, 21 }; + +void +check1 (void) +{ + if (a1.a != 4 || a1.b != 5 || a1.c != 6) + abort (); + if (a2.a != 22 || a2.b != 23 || a2.c != 24) + abort (); + if (a3.a != 10 || a3.b != 11 || a3.c != 12) + abort (); + if (a4.a != 25 || a4.b != 26 || a4.c != 27) + abort (); + if (local1.a != 16 || local1.b != 17 || local1.c != 18) + abort (); + if (local2.a != 19 || local2.b != 20 || local2.c != 21) + abort (); +} + +struct A * +f1a (void) +{ + return &a1; +} + +struct A * +f2a (void) +{ + return &a2; +} + +struct A * +f3a (void) +{ + return &a3; +} + +struct A * +f4a (void) +{ + return &a4; +} + +struct A * +f5a (void) +{ + return &local1; +} + +struct A * +f6a (void) +{ + return &local2; +} + +int +f1b (void) +{ + return a1.a; +} + +int +f2b (void) +{ + return a2.b; +} + +int +f3b (void) +{ + return a3.c; +} + +int +f4b (void) +{ + return a4.a; +} + +int +f5b (void) +{ + return local1.b; +} + +int +f6b (void) +{ + return local2.c; +} +#endif |