Browse Source

tests: Added new nptl tests

tests: Added several nptl tests from glibc 2.10.1

Signed-off-by: Salvatore Cro <salvatore.cro@st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Salvatore Cro 13 years ago
parent
commit
447c70a5dc
58 changed files with 4877 additions and 1 deletions
  1. 69 1
      test/nptl/Makefile.in
  2. 57 0
      test/nptl/tst-align3.c
  3. 75 0
      test/nptl/tst-basic7.c
  4. 174 0
      test/nptl/tst-cancel18.c
  5. 1 0
      test/nptl/tst-cancel23.c
  6. 171 0
      test/nptl/tst-cancel25.c
  7. 2374 0
      test/nptl/tst-cancel4.c
  8. 1 0
      test/nptl/tst-cancel5.c
  9. 1 0
      test/nptl/tst-cancelx10.c
  10. 1 0
      test/nptl/tst-cancelx11.c
  11. 1 0
      test/nptl/tst-cancelx12.c
  12. 1 0
      test/nptl/tst-cancelx13.c
  13. 1 0
      test/nptl/tst-cancelx14.c
  14. 1 0
      test/nptl/tst-cancelx15.c
  15. 1 0
      test/nptl/tst-cancelx16.c
  16. 1 0
      test/nptl/tst-cancelx18.c
  17. 1 0
      test/nptl/tst-cancelx2.c
  18. 1 0
      test/nptl/tst-cancelx20.c
  19. 1 0
      test/nptl/tst-cancelx21.c
  20. 1 0
      test/nptl/tst-cancelx3.c
  21. 1 0
      test/nptl/tst-cancelx4.c
  22. 1 0
      test/nptl/tst-cancelx6.c
  23. 1 0
      test/nptl/tst-cancelx7.c
  24. 1 0
      test/nptl/tst-cancelx8.c
  25. 1 0
      test/nptl/tst-cancelx9.c
  26. 1 0
      test/nptl/tst-cleanupx0.c
  27. 1 0
      test/nptl/tst-cleanupx1.c
  28. 1 0
      test/nptl/tst-cleanupx2.c
  29. 1 0
      test/nptl/tst-cleanupx3.c
  30. 1 0
      test/nptl/tst-cleanupx4.c
  31. 160 0
      test/nptl/tst-cond22.c
  32. 184 0
      test/nptl/tst-cond23.c
  33. 66 0
      test/nptl/tst-dlsym1.c
  34. 35 0
      test/nptl/tst-fini1.c
  35. 72 0
      test/nptl/tst-fini1mod.c
  36. 122 0
      test/nptl/tst-getpid1.c
  37. 2 0
      test/nptl/tst-getpid2.c
  38. 114 0
      test/nptl/tst-getpid3.c
  39. 1 0
      test/nptl/tst-initializers1-c89.c
  40. 1 0
      test/nptl/tst-initializers1-c99.c
  41. 1 0
      test/nptl/tst-initializers1-gnu89.c
  42. 1 0
      test/nptl/tst-initializers1-gnu99.c
  43. 2 0
      test/nptl/tst-join6.c
  44. 1 0
      test/nptl/tst-oddstacklimit.c
  45. 1 0
      test/nptl/tst-oncex3.c
  46. 1 0
      test/nptl/tst-oncex4.c
  47. 2 0
      test/nptl/tst-rwlock2a.c
  48. 88 0
      test/nptl/tst-sem10.c
  49. 76 0
      test/nptl/tst-sem11.c
  50. 14 0
      test/nptl/tst-sem12.c
  51. 59 0
      test/nptl/tst-signal7.c
  52. 89 0
      test/nptl/tst-tsd6.c
  53. 96 0
      test/nptl/tst-typesizes.c
  54. 47 0
      test/nptl/tst-unload.c
  55. 150 0
      test/nptl/tst-vfork1.c
  56. 150 0
      test/nptl/tst-vfork1x.c
  57. 199 0
      test/nptl/tst-vfork2.c
  58. 199 0
      test/nptl/tst-vfork2x.c

+ 69 - 1
test/nptl/Makefile.in

@@ -31,7 +31,19 @@ TESTS := tst-align tst-align2 tst-atfork1 tst-attr1 tst-attr2 tst-attr3	\
 	tst-signal5 tst-signal6 tst-spin1 tst-spin2 tst-spin3		\
 	tst-stack1 tst-stack2 tst-stdio1 tst-stdio2 tst-sysconf		\
 	tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tsd1 tst-tsd2	\
-	tst-tsd3 tst-tsd4 tst-tsd5 tst-umask1
+	tst-tsd3 tst-tsd4 tst-tsd5 tst-umask1 \
+	tst-align3 tst-cancel4 tst-cancel5 tst-cancel18 tst-cancel23 \
+	tst-cancel25 tst-cancelx2 tst-cancelx3 tst-cancelx4 tst-cancelx6 \
+	tst-cancelx7 tst-cancelx8 tst-cancelx9 tst-cancelx10 tst-cancelx11 \
+	tst-cancelx12 tst-cancelx13 tst-cancelx14 tst-cancelx15 tst-cancelx16 \
+	tst-cancelx18 tst-cancelx20 tst-cancelx21 tst-cleanupx0 tst-cleanupx1 \
+	tst-cleanupx2 tst-cleanupx3 tst-cleanupx4 tst-cond22 tst-cond23 \
+	tst-dlsym1 tst-getpid1 tst-getpid2 tst-getpid3 tst-join6 tst-tsd6 \
+	tst-oddstacklimit tst-oncex3 tst-oncex4 tst-rwlock2a  \
+	tst-basic7 tst-fini1 tst-signal7 \
+	tst-unload tst-vfork1x tst-vfork2x tst-sem10 tst-sem11 tst-sem12 \
+	tst-typesizes tst-initializers1-c89 tst-initializers1-c99 \
+	tst-initializers1-gnu89 tst-initializers1-gnu99
 
 #
 # These are for the RT library and POSIX timers.
@@ -97,9 +109,60 @@ CFLAGS_tst-tls5modd.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
 CFLAGS_tst-tls5mode.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
 CFLAGS_tst-tls5modf.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
 
+CFLAGS_tst-fini1mod.so := -fPIC -DPIC -DSHARED -shared -DNOT_IN_libc
+LDFLAGS_tst-cond11 = -lrt
+LDFLAGS_tst-cond19 = -lrt
+LDFLAGS_tst-cancel18 = -lrt
+LDFLAGS_tst-cancelx18 = -lrt
+LDFLAGS_tst-clock2 = -lrt
+LDFLAGS_tst-rwlock14 = -lrt
+LDFLAGS_tst-fini1 = -Wl,-rpath=./ tst-fini1mod.so
+LDFLAGS_tst-fini1mod.so = -Wl,-soname=tst-fini1mod.so
+LDFLAGS_tst-unload = -ldl
+LDFLAGS_tst-cancel5 := -lpthread -lpthread_nonshared
+LDFLAGS_tst-cancel23 := -lc -lpthread
+LDFLAGS_tst-vfork1x := -lc -lpthread
+LDFLAGS_tst-vfork2x := -lc -lpthread
+
+CFLAGS_tst-cancelx2 += -fexceptions
+CFLAGS_tst-cancelx3 += -fexceptions
+CFLAGS_tst-cancelx4 += -fexceptions
+CFLAGS_tst-cancelx6 += -fexceptions
+CFLAGS_tst-cancelx7 += -fexceptions
+CFLAGS_tst-cancelx8 += -fexceptions
+CFLAGS_tst-cancelx9 += -fexceptions
+CFLAGS_tst-cancelx10 += -fexceptions
+CFLAGS_tst-cancelx11 += -fexceptions
+CFLAGS_tst-cancelx12 += -fexceptions
+CFLAGS_tst-cancelx13 += -fexceptions
+CFLAGS_tst-cancelx14 += -fexceptions
+CFLAGS_tst-cancelx15 += -fexceptions
+CFLAGS_tst-cancelx16 += -fexceptions
+CFLAGS_tst-cancelx18 += -fexceptions
+CFLAGS_tst-cancelx20 += -fexceptions -fasynchronous-unwind-tables
+CFLAGS_tst-cancelx21 += -fexceptions -fasynchronous-unwind-tables
+CFLAGS_tst-cleanupx0 += -fexceptions -fasynchronous-unwind-tables
+CFLAGS_tst-cleanupx1 += -fexceptions -fasynchronous-unwind-tables
+CFLAGS_tst-cleanupx2 += -fexceptions
+CFLAGS_tst-cleanupx3 += -fexceptions
+
+CFLAGS_tst-oncex3 += -fexceptions
+CFLAGS_tst-oncex4 += -fexceptions
+CFLAGS_tst-align += $(stack-align-test-flags)
+CFLAGS_tst-align3 += $(stack-align-test-flags)
+CFLAGS_tst-initializers1 = -W -Wall -Werror
+CFLAGS_tst-sem11 += -fexceptions -fasynchronous-unwind-tables
+CFLAGS_tst-sem12 += -fexceptions -fasynchronous-unwind-tables
+CFLAGS_tst-initializers1 = -W -Wall -Werror
+CFLAGS_tst-initializers1-c89 = $(CFLAGS-tst-initializers1) -std=c89
+CFLAGS_tst-initializers1-c99 = $(CFLAGS-tst-initializers1) -std=c99
+CFLAGS_tst-initializers1-gnu89 = $(CFLAGS-tst-initializers1) -std=gnu89
+CFLAGS_tst-initializers1-gnu99 = $(CFLAGS-tst-initializers1) -std=gnu99
+
 EXTRA_LDFLAGS = $(if $(findstring -lpthread,$(LDFLAGS_$@)),,-lpthread)
 
 LDFLAGS_tst-cleanup4 := tst-cleanup4aux.o
+LDFLAGS_tst-cleanupx4 := tst-cleanup4aux.o
 LDFLAGS_tst-clock2 := -lrt
 LDFLAGS_tst-cond11 := -lrt
 LDFLAGS_tst-cond19 := -lrt
@@ -127,6 +190,7 @@ LDFLAGS_tst-timer2 := -lrt -lpthread
 LDFLAGS_tst-timer3 := -lrt -lpthread
 LDFLAGS_tst-timer4 := -lrt -lpthread
 LDFLAGS_tst-timer5 := -lrt -lpthread
+LDFLAGS_tst-dlsym1 := -ldl -rdynamic
 LDFLAGS_tst-tls3mod.so := -shared -static-libgcc -lpthread
 LDFLAGS_tst-tls4moda.so := -shared -static-libgcc
 LDFLAGS_tst-tls4modb.so := -shared -static-libgcc
@@ -137,6 +201,7 @@ LDFLAGS_tst-tls5modc.so := -shared -static-libgcc
 LDFLAGS_tst-tls5modd.so := -shared -static-libgcc
 LDFLAGS_tst-tls5mode.so := -shared -static-libgcc
 LDFLAGS_tst-tls5modf.so := -shared -static-libgcc
+LDFLAGS_tst-cleanupx4 := tst-cleanup4aux.o
 
 #
 # Special case
@@ -149,6 +214,9 @@ tst-tls3: tst-tls3mod.so
 tst-tls4: tst-tls4moda.so tst-tls4modb.so
 tst-tls5: tst-tls5mod.so
 
+tst-cleanupx4 : tst-cleanup4aux.o
+tst-fini1: tst-fini1mod.so
+
 OPTS_tst-cancel7 = --command ./tst-cancel7
 OPTS_tst-mqueue7 = -- ./tst-mqueue7
 OPTS_tst-exec4 = ./tst-exec4

+ 57 - 0
test/nptl/tst-align3.c

@@ -0,0 +1,57 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <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>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "tst-stack-align.h"
+
+static bool ok = true;
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+static void
+once_test (void)
+{
+  puts ("in once_test");
+
+  if (TEST_STACK_ALIGN ())
+    ok = false;
+}
+
+static int
+do_test (void)
+{
+  puts ("in main");
+
+  if (TEST_STACK_ALIGN ())
+    ok = false;
+
+  if (pthread_once (&once, once_test))
+    {
+      puts ("pthread once failed");
+      return 1;
+    }
+
+  return ok ? 0 : 1;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 75 - 0
test/nptl/tst-basic7.c

@@ -0,0 +1,75 @@
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include <sys/resource.h>
+
+static void use_stack (size_t needed);
+
+void (*use_stack_ptr) (size_t) = use_stack;
+
+static void
+use_stack (size_t needed)
+{
+  size_t sz = sysconf (_SC_PAGESIZE);
+  char *buf = alloca (sz);
+  memset (buf, '\0', sz);
+
+  if (needed > sz)
+    use_stack_ptr (needed  - sz);
+}
+
+static void
+use_up_memory (void)
+{
+  struct rlimit rl;
+  getrlimit (RLIMIT_AS, &rl);
+  rl.rlim_cur = 10 * 1024 * 1024;
+  setrlimit (RLIMIT_AS, &rl);
+
+  char *c;
+  int PAGESIZE = getpagesize ();
+  while (1)
+    {
+      c = mmap (NULL, PAGESIZE, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
+      if (c == MAP_FAILED)
+	break;
+    }
+}
+
+static void *
+child (void *arg)
+{
+  sleep (1);
+  return arg;
+}
+
+static int
+do_test (void)
+{
+  int err;
+  pthread_t tid;
+
+  /* Allocate the memory needed for the stack.  */
+  use_stack_ptr (PTHREAD_STACK_MIN);
+
+  use_up_memory ();
+
+  err = pthread_create (&tid, NULL, child, NULL);
+  if (err != 0)
+    {
+      printf ("pthread_create returns %d: %s\n", err,
+	      err == EAGAIN ? "OK" : "FAIL");
+      return err != EAGAIN;
+    }
+
+  /* We did not fail to allocate memory despite the preparation.  Oh well.  */
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 174 - 0
test/nptl/tst-cancel18.c

@@ -0,0 +1,174 @@
+/* Copyright (C) 2003 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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>
+
+
+static pthread_barrier_t b;
+
+
+/* Cleanup handling test.  */
+static int cl_called;
+
+static void
+cl (void *arg)
+{
+  ++cl_called;
+}
+
+
+static void *
+tf (void *arg)
+{
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 };
+  TEMP_FAILURE_RETRY (clock_nanosleep (CLOCK_REALTIME, 0, &ts, &ts));
+
+  pthread_cleanup_pop (0);
+
+  puts ("clock_nanosleep returned");
+
+  exit (1);
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      return 1;
+    }
+
+  int r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+  while (nanosleep (&ts, &ts) != 0)
+    continue;
+
+  puts ("going to cancel in-time");
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("1st cancel failed");
+      return 1;
+    }
+
+  void *status;
+  if (pthread_join (th, &status) != 0)
+    {
+      puts ("1st join failed");
+      return 1;
+    }
+  if (status != PTHREAD_CANCELED)
+    {
+      puts ("1st thread not canceled");
+      return 1;
+    }
+
+  if (cl_called == 0)
+    {
+      puts ("cleanup handler not called");
+      return 1;
+    }
+  if (cl_called > 1)
+    {
+      puts ("cleanup handler called more than once");
+      return 1;
+    }
+
+  puts ("in-time cancellation succeeded");
+
+
+  cl_called = 0;
+
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("2nd create failed");
+      return 1;
+    }
+
+  puts ("going to cancel early");
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("2nd cancel failed");
+      return 1;
+    }
+
+  r = pthread_barrier_wait (&b);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  if (pthread_join (th, &status) != 0)
+    {
+      puts ("2nd join failed");
+      return 1;
+    }
+  if (status != PTHREAD_CANCELED)
+    {
+      puts ("2nd thread not canceled");
+      return 1;
+    }
+
+  if (cl_called == 0)
+    {
+      printf ("cleanup handler not called\n");
+      return 1;
+    }
+  if (cl_called > 1)
+    {
+      printf ("cleanup handler called more than once\n");
+      return 1;
+    }
+
+  puts ("early cancellation succeeded");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 1 - 0
test/nptl/tst-cancel23.c

@@ -0,0 +1 @@
+#include "tst-cancel22.c"

+ 171 - 0
test/nptl/tst-cancel25.c

@@ -0,0 +1,171 @@
+#include <pthreadP.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_barrier_t b;
+static pthread_t th2;
+
+
+static void *
+tf2 (void *arg)
+{
+  sigset_t mask;
+  if (pthread_sigmask (SIG_SETMASK, NULL, &mask) != 0)
+    {
+      puts ("pthread_sigmask failed");
+      exit (1);
+    }
+  if (sigismember (&mask, SIGCANCEL))
+    {
+      puts ("SIGCANCEL blocked in new thread");
+      exit (1);
+    }
+
+  /* Sync with the main thread so that we do not test anything else.  */
+  int e = pthread_barrier_wait (&b);
+  if (e != 0  && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  while (1)
+    {
+      /* Just a cancelable call.  */
+      struct timespec ts = { 10000, 0 };
+      nanosleep (&ts, 0);
+    }
+
+  return NULL;
+}
+
+
+static void
+unwhand (void *arg)
+{
+  if (pthread_create (&th2, NULL, tf2, NULL) != 0)
+    {
+      puts ("unwhand: create failed");
+      exit (1);
+    }
+}
+
+
+static void *
+tf (void *arg)
+{
+  pthread_cleanup_push (unwhand, NULL);
+
+  /* Sync with the main thread so that we do not test anything else.  */
+  int e = pthread_barrier_wait (&b);
+  if (e != 0  && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      exit (1);
+    }
+
+  while (1)
+    {
+      /* Just a cancelable call.  */
+      struct timespec ts = { 10000, 0 };
+      nanosleep (&ts, 0);
+    }
+
+  pthread_cleanup_pop (0);
+
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th1;
+  if (pthread_create (&th1, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      return 1;
+    }
+
+  int e = pthread_barrier_wait (&b);
+  if (e != 0  && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  /* Make sure tf1 enters nanosleep.  */
+  struct timespec ts = { 0, 500000000 };
+  while (nanosleep (&ts, &ts) != 0)
+    ;
+
+  if (pthread_cancel (th1) != 0)
+    {
+      puts ("1st cancel failed");
+      return 1;
+    }
+
+  void *res;
+  if (pthread_join (th1, &res) != 0)
+    {
+      puts ("1st join failed");
+      return 1;
+    }
+  if (res != PTHREAD_CANCELED)
+    {
+      puts ("1st thread not canceled");
+      return 1;
+    }
+
+  e = pthread_barrier_wait (&b);
+  if (e != 0  && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("barrier_wait failed");
+      return 1;
+    }
+
+  /* Make sure tf2 enters nanosleep.  */
+  ts.tv_sec = 0;
+  ts.tv_nsec = 500000000;
+  while (nanosleep (&ts, &ts) != 0)
+    ;
+
+  puts ("calling pthread_cancel the second time");
+  if (pthread_cancel (th2) != 0)
+    {
+      puts ("2nd cancel failed");
+      return 1;
+    }
+
+  puts ("calling pthread_join the second time");
+  if (pthread_join (th2, &res) != 0)
+    {
+      puts ("2nd join failed");
+      return 1;
+    }
+  if (res != PTHREAD_CANCELED)
+    {
+      puts ("2nd thread not canceled");
+      return 1;
+    }
+
+  if (pthread_barrier_destroy (&b) != 0)
+    {
+      puts ("barrier_destroy failed");
+      return 0;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#define TIMEOUT 4
+#include "../test-skeleton.c"

+ 2374 - 0
test/nptl/tst-cancel4.c

@@ -0,0 +1,2374 @@
+/* Copyright (C) 2002, 2003, 2004, 2006, 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/msg.h>
+#include <sys/poll.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+
+#include "pthreadP.h"
+
+
+/* Since STREAMS are not supported in the standard Linux kernel and
+   there we don't advertise STREAMS as supported is no need to test
+   the STREAMS related functions.  This affects
+     getmsg()              getpmsg()          putmsg()
+     putpmsg()
+
+   lockf() and fcntl() are tested in tst-cancel16.
+
+   pthread_join() is tested in tst-join5.
+
+   pthread_testcancel()'s only purpose is to allow cancellation.  This
+   is tested in several places.
+
+   sem_wait() and sem_timedwait() are checked in tst-cancel1[2345] tests.
+
+   mq_send(), mq_timedsend(), mq_receive() and mq_timedreceive() are checked
+   in tst-mqueue8{,x} tests.
+
+   aio_suspend() is tested in tst-cancel17.
+
+   clock_nanosleep() is tested in tst-cancel18.
+*/
+
+/* Pipe descriptors.  */
+static int fds[2];
+
+/* Temporary file descriptor, to be closed after each round.  */
+static int tempfd = -1;
+static int tempfd2 = -1;
+/* Name of temporary file to be removed after each round.  */
+static char *tempfname;
+/* Temporary message queue.  */
+static int tempmsg = -1;
+
+/* Often used barrier for two threads.  */
+static pthread_barrier_t b2;
+
+
+#ifndef IPC_ADDVAL
+# define IPC_ADDVAL 0
+#endif
+
+#define WRITE_BUFFER_SIZE 4096
+
+/* Cleanup handling test.  */
+static int cl_called;
+
+static void
+cl (void *arg)
+{
+  ++cl_called;
+}
+
+
+
+static void *
+tf_read  (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[0];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  ssize_t s;
+  pthread_cleanup_push (cl, NULL);
+
+  char buf[100];
+  s = read (fd, buf, sizeof (buf));
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: read returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_readv  (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[0];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  ssize_t s;
+  pthread_cleanup_push (cl, NULL);
+
+  char buf[100];
+  struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
+  s = readv (fd, iov, 1);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: readv returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_write  (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[1];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  ssize_t s;
+  pthread_cleanup_push (cl, NULL);
+
+  char buf[WRITE_BUFFER_SIZE];
+  memset (buf, '\0', sizeof (buf));
+  s = write (fd, buf, sizeof (buf));
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: write returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_writev  (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[1];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  ssize_t s;
+  pthread_cleanup_push (cl, NULL);
+
+  char buf[WRITE_BUFFER_SIZE];
+  memset (buf, '\0', sizeof (buf));
+  struct iovec iov[1] = { [0] = { .iov_base = buf, .iov_len = sizeof (buf) } };
+  s = writev (fd, iov, 1);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: writev returns with %zd\n", __FUNCTION__, s);
+
+  exit (1);
+}
+
+
+static void *
+tf_sleep (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  sleep (arg == NULL ? 1000000 : 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sleep returns\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_usleep (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  usleep (arg == NULL ? (useconds_t) ULONG_MAX : 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: usleep returns\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_nanosleep (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  struct timespec ts = { .tv_sec = arg == NULL ? 10000000 : 0, .tv_nsec = 0 };
+  TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: nanosleep returns\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_select (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[0];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  fd_set rfs;
+  FD_ZERO (&rfs);
+  FD_SET (fd, &rfs);
+
+  int s;
+  pthread_cleanup_push (cl, NULL);
+
+  s = select (fd + 1, &rfs, NULL, NULL, NULL);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: select returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_pselect (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[0];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  fd_set rfs;
+  FD_ZERO (&rfs);
+  FD_SET (fd, &rfs);
+
+  int s;
+  pthread_cleanup_push (cl, NULL);
+
+  s = pselect (fd + 1, &rfs, NULL, NULL, NULL, NULL);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: pselect returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_poll (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[0];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } };
+
+  int s;
+  pthread_cleanup_push (cl, NULL);
+
+  s = poll (rfs, 1, -1);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: poll returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_ppoll (void *arg)
+{
+  int fd;
+  int r;
+
+  if (arg == NULL)
+    fd = fds[0];
+  else
+    {
+      char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+      tempfd = fd = mkstemp (fname);
+      if (fd == -1)
+	printf ("%s: mkstemp failed\n", __FUNCTION__);
+      unlink (fname);
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  struct pollfd rfs[1] = { [0] = { .fd = fd, .events = POLLIN } };
+
+  int s;
+  pthread_cleanup_push (cl, NULL);
+
+  s = ppoll (rfs, 1, NULL, NULL);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: ppoll returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_wait (void *arg)
+{
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make the program disappear after a while.  */
+      if (arg == NULL)
+	sleep (10);
+      exit (0);
+    }
+
+  int r;
+  if (arg != NULL)
+    {
+      struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      while (nanosleep (&ts, &ts) != 0)
+	continue;
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int s;
+  pthread_cleanup_push (cl, NULL);
+
+  s = wait (NULL);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: wait returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_waitpid (void *arg)
+{
+
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make the program disappear after a while.  */
+      if (arg == NULL)
+	sleep (10);
+      exit (0);
+    }
+
+  int r;
+  if (arg != NULL)
+    {
+      struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      while (nanosleep (&ts, &ts) != 0)
+	continue;
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int s;
+ pthread_cleanup_push (cl, NULL);
+
+  s = waitpid (-1, NULL, 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: waitpid returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_waitid (void *arg)
+{
+  pid_t pid = fork ();
+  if (pid == -1)
+    {
+      puts ("fork failed");
+      exit (1);
+    }
+
+  if (pid == 0)
+    {
+      /* Make the program disappear after a while.  */
+      if (arg == NULL)
+	sleep (10);
+      exit (0);
+    }
+
+  int r;
+  if (arg != NULL)
+    {
+      struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      while (nanosleep (&ts, &ts) != 0)
+	continue;
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int s;
+  pthread_cleanup_push (cl, NULL);
+
+#ifndef WEXITED
+# define WEXITED 0
+#endif
+  siginfo_t si;
+  s = waitid (P_PID, pid, &si, WEXITED);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: waitid returns with %d (%s)\n", __FUNCTION__, s,
+	  strerror (errno));
+
+  exit (1);
+}
+
+
+static void *
+tf_sigpause (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  /* Just for fun block the cancellation signal.  We need to use
+     __xpg_sigpause since otherwise we will get the BSD version.  */
+  //__xpg_sigpause (SIGCANCEL);
+
+  __sigpause (SIGCANCEL, 1);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sigpause returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_sigsuspend (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  /* Just for fun block all signals.  */
+  sigset_t mask;
+  sigfillset (&mask);
+  sigsuspend (&mask);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sigsuspend returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_sigwait (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  /* Block SIGUSR1.  */
+  sigset_t mask;
+  sigemptyset (&mask);
+  sigaddset (&mask, SIGUSR1);
+  if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0)
+    {
+      printf ("%s: pthread_sigmask failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int sig;
+  pthread_cleanup_push (cl, NULL);
+
+  /* Wait for SIGUSR1.  */
+  sigwait (&mask, &sig);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sigwait returned with signal %d\n", __FUNCTION__, sig);
+
+  exit (1);
+}
+
+
+static void *
+tf_sigwaitinfo (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  /* Block SIGUSR1.  */
+  sigset_t mask;
+  sigemptyset (&mask);
+  sigaddset (&mask, SIGUSR1);
+  if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0)
+    {
+      printf ("%s: pthread_sigmask failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  siginfo_t info;
+  pthread_cleanup_push (cl, NULL);
+
+  /* Wait for SIGUSR1.  */
+  sigwaitinfo (&mask, &info);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sigwaitinfo returned with signal %d\n", __FUNCTION__,
+	  info.si_signo);
+
+  exit (1);
+}
+
+
+static void *
+tf_sigtimedwait (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  /* Block SIGUSR1.  */
+  sigset_t mask;
+  sigemptyset (&mask);
+  sigaddset (&mask, SIGUSR1);
+  if (pthread_sigmask (SIG_BLOCK, &mask, NULL) != 0)
+    {
+      printf ("%s: pthread_sigmask failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  /* Wait for SIGUSR1.  */
+  siginfo_t info;
+  struct timespec ts = { .tv_sec = 60, .tv_nsec = 0 };
+  pthread_cleanup_push (cl, NULL);
+
+  sigtimedwait (&mask, &info, &ts);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sigtimedwait returned with signal %d\n", __FUNCTION__,
+	  info.si_signo);
+
+  exit (1);
+}
+
+
+static void *
+tf_pause (void *arg)
+{
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  pause ();
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: pause returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_accept (void *arg)
+{
+  struct sockaddr_un sun;
+  /* To test a non-blocking accept call we make the call file by using
+     a datagrame socket.  */
+  int pf = arg == NULL ? SOCK_STREAM : SOCK_DGRAM;
+
+  tempfd = socket (AF_UNIX, pf, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-1-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+
+  unlink (sun.sun_path);
+
+  listen (tempfd, 5);
+
+  socklen_t len = sizeof (sun);
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  accept (tempfd, (struct sockaddr *) &sun, &len);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: accept returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_send (void *arg)
+{
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-2-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+
+  listen (tempfd, 5);
+
+  tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)) != 0)
+    {
+      printf ("%s: connect failed\n", __FUNCTION__);
+      exit(1);
+    }
+
+  unlink (sun.sun_path);
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  /* Very large block, so that the send call blocks.  */
+  char mem[700000];
+
+  send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: send returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_recv (void *arg)
+{
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-3-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+
+  listen (tempfd, 5);
+
+  tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun)) != 0)
+    {
+      printf ("%s: connect failed\n", __FUNCTION__);
+      exit(1);
+    }
+
+  unlink (sun.sun_path);
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[70];
+
+  recv (tempfd2, mem, arg == NULL ? sizeof (mem) : 0, 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: recv returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_recvfrom (void *arg)
+{
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-4-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+
+  tempfname = strdup (sun.sun_path);
+
+  tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[70];
+  socklen_t len = sizeof (sun);
+
+  recvfrom (tempfd2, mem, arg == NULL ? sizeof (mem) : 0, 0,
+	    (struct sockaddr *) &sun, &len);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: recvfrom returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_recvmsg (void *arg)
+{
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-5-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+
+  tempfname = strdup (sun.sun_path);
+
+  tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[70];
+  struct iovec iov[1];
+  iov[0].iov_base = mem;
+  iov[0].iov_len = arg == NULL ? sizeof (mem) : 0;
+
+  struct msghdr m;
+  m.msg_name = &sun;
+  m.msg_namelen = sizeof (sun);
+  m.msg_iov = iov;
+  m.msg_iovlen = 1;
+  m.msg_control = NULL;
+  m.msg_controllen = 0;
+
+  recvmsg (tempfd2, &m, 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: recvmsg returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_open (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which open()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  open ("Makefile", O_RDONLY);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: open returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_close (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which close()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  char fname[] = "/tmp/tst-cancel-fd-XXXXXX";
+  tempfd = mkstemp (fname);
+  if (tempfd == -1)
+    {
+      printf ("%s: mkstemp failed\n", __FUNCTION__);
+      exit (1);
+    }
+  unlink (fname);
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  close (tempfd);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: close returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_pread (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which pread()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  tempfd = open ("Makefile", O_RDONLY);
+  if (tempfd == -1)
+    {
+      printf ("%s: cannot open Makefile\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[10];
+  pread (tempfd, mem, sizeof (mem), 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: pread returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_pwrite (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which pwrite()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  char fname[] = "/tmp/tst-cancel4-fd-XXXXXX";
+  tempfd = mkstemp (fname);
+  if (tempfd == -1)
+    {
+      printf ("%s: mkstemp failed\n", __FUNCTION__);
+      exit (1);
+    }
+  unlink (fname);
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[10];
+  pwrite (tempfd, mem, sizeof (mem), 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: pwrite returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_fsync (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which fsync()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  tempfd = open ("Makefile", O_RDONLY);
+  if (tempfd == -1)
+    {
+      printf ("%s: cannot open Makefile\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  fsync (tempfd);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: fsync returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_fdatasync (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which fdatasync()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  tempfd = open ("Makefile", O_RDONLY);
+  if (tempfd == -1)
+    {
+      printf ("%s: cannot open Makefile\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  fdatasync (tempfd);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: fdatasync returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_msync (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which msync()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  tempfd = open ("Makefile", O_RDONLY);
+  if (tempfd == -1)
+    {
+      printf ("%s: cannot open Makefile\n", __FUNCTION__);
+      exit (1);
+    }
+  void *p = mmap (NULL, 10, PROT_READ, MAP_SHARED, tempfd, 0);
+  if (p == MAP_FAILED)
+    {
+      printf ("%s: mmap failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  msync (p, 10, 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: msync returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_sendto (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which sendto()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-6-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+  tempfname = strdup (sun.sun_path);
+
+  tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[1];
+
+  sendto (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0,
+	  (struct sockaddr *) &sun,
+	  offsetof (struct sockaddr_un, sun_path) + strlen (sun.sun_path) + 1);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sendto returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_sendmsg (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which sendmsg()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-7-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+  tempfname = strdup (sun.sun_path);
+
+  tempfd2 = socket (AF_UNIX, SOCK_DGRAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  char mem[1];
+  struct iovec iov[1];
+  iov[0].iov_base = mem;
+  iov[0].iov_len = 1;
+
+  struct msghdr m;
+  m.msg_name = &sun;
+  m.msg_namelen = (offsetof (struct sockaddr_un, sun_path)
+		   + strlen (sun.sun_path) + 1);
+  m.msg_iov = iov;
+  m.msg_iovlen = 1;
+  m.msg_control = NULL;
+  m.msg_controllen = 0;
+
+  sendmsg (tempfd2, &m, 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: sendmsg returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_creat (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which sendmsg()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  creat ("tmp/tst-cancel-4-should-not-exist", 0666);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: creat returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_connect (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which connect()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  struct sockaddr_un sun;
+
+  tempfd = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (tempfd == -1)
+    {
+      printf ("%s: first socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int tries = 0;
+  do
+    {
+      if (++tries > 10)
+	{
+	  printf ("%s: too many unsuccessful bind calls\n", __FUNCTION__);
+	}
+
+      strcpy (sun.sun_path, "/tmp/tst-cancel4-socket-2-XXXXXX");
+      if (mktemp (sun.sun_path) == NULL)
+	{
+	  printf ("%s: cannot generate temp file name\n", __FUNCTION__);
+	  exit (1);
+	}
+
+      sun.sun_family = AF_UNIX;
+    }
+  while (bind (tempfd, (struct sockaddr *) &sun,
+	       offsetof (struct sockaddr_un, sun_path)
+	       + strlen (sun.sun_path) + 1) != 0);
+  tempfname = strdup (sun.sun_path);
+
+  listen (tempfd, 5);
+
+  tempfd2 = socket (AF_UNIX, SOCK_STREAM, 0);
+  if (tempfd2 == -1)
+    {
+      printf ("%s: second socket call failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  connect (tempfd2, (struct sockaddr *) &sun, sizeof (sun));
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: connect returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_tcdrain (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which tcdrain()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  /* Regardless of stderr being a terminal, the tcdrain call should be
+     canceled.  */
+  tcdrain (STDERR_FILENO);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: tcdrain returned\n", __FUNCTION__);
+
+  exit (1);
+}
+
+
+static void *
+tf_msgrcv (void *arg)
+{
+  tempmsg = msgget (IPC_PRIVATE, 0666 | IPC_CREAT);
+  if (tempmsg == -1)
+    {
+      printf ("%s: msgget failed: %s\n", __FUNCTION__, strerror (errno));
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  if (arg != NULL)
+    {
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+	  exit (1);
+	}
+    }
+
+  ssize_t s;
+
+  pthread_cleanup_push (cl, NULL);
+
+  struct
+  {
+    long int type;
+    char mem[10];
+  } m;
+  int randnr;
+  /* We need a positive random number.  */
+  do
+    randnr = random () % 64000;
+  while (randnr <= 0);
+  do
+    {
+      errno = 0;
+      s = msgrcv (tempmsg, (struct msgbuf *) &m, 10, randnr, 0);
+    }
+  while (errno == EIDRM || errno == EINTR);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: msgrcv returned %zd with errno = %m\n", __FUNCTION__, s);
+
+  msgctl (tempmsg, IPC_RMID, NULL);
+
+  exit (1);
+}
+
+
+static void *
+tf_msgsnd (void *arg)
+{
+  if (arg == NULL)
+    // XXX If somebody can provide a portable test case in which msgsnd()
+    // blocks we can enable this test to run in both rounds.
+    abort ();
+
+  tempmsg = msgget (IPC_PRIVATE, 0666 | IPC_CREAT);
+  if (tempmsg == -1)
+    {
+      printf ("%s: msgget failed: %s\n", __FUNCTION__, strerror (errno));
+      exit (1);
+    }
+
+  int r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  r = pthread_barrier_wait (&b2);
+  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: 2nd barrier_wait failed\n", __FUNCTION__);
+      exit (1);
+    }
+
+  pthread_cleanup_push (cl, NULL);
+
+  struct
+  {
+    long int type;
+    char mem[1];
+  } m;
+  /* We need a positive random number.  */
+  do
+    m.type = random () % 64000;
+  while (m.type <= 0);
+  msgsnd (tempmsg, (struct msgbuf *) &m, sizeof (m.mem), 0);
+
+  pthread_cleanup_pop (0);
+
+  printf ("%s: msgsnd returned\n", __FUNCTION__);
+
+  msgctl (tempmsg, IPC_RMID, NULL);
+
+  exit (1);
+}
+
+
+static struct
+{
+  const char *name;
+  void *(*tf) (void *);
+  int nb;
+  int only_early;
+} tests[] =
+{
+#define ADD_TEST(name, nbar, early) { #name, tf_##name, nbar, early }
+  ADD_TEST (read, 2, 0),
+  ADD_TEST (readv, 2, 0),
+  ADD_TEST (select, 2, 0),
+  ADD_TEST (pselect, 2, 0),
+  ADD_TEST (poll, 2, 0),
+  ADD_TEST (ppoll, 2, 0),
+  ADD_TEST (write, 2, 0),
+  ADD_TEST (writev, 2, 0),
+  ADD_TEST (sleep, 2, 0),
+  ADD_TEST (usleep, 2, 0),
+  ADD_TEST (nanosleep, 2, 0),
+  ADD_TEST (wait, 2, 0),
+  ADD_TEST (waitid, 2, 0),
+  ADD_TEST (waitpid, 2, 0),
+  ADD_TEST (sigpause, 2, 0),
+  ADD_TEST (sigsuspend, 2, 0),
+  ADD_TEST (sigwait, 2, 0),
+  ADD_TEST (sigwaitinfo, 2, 0),
+  ADD_TEST (sigtimedwait, 2, 0),
+  ADD_TEST (pause, 2, 0),
+  ADD_TEST (accept, 2, 0),
+  ADD_TEST (send, 2, 0),
+  ADD_TEST (recv, 2, 0),
+  ADD_TEST (recvfrom, 2, 0),
+  ADD_TEST (recvmsg, 2, 0),
+  ADD_TEST (open, 2, 1),
+  ADD_TEST (close, 2, 1),
+  ADD_TEST (pread, 2, 1),
+  ADD_TEST (pwrite, 2, 1),
+  ADD_TEST (fsync, 2, 1),
+  ADD_TEST (fdatasync, 2, 1),
+  ADD_TEST (msync, 2, 1),
+  ADD_TEST (sendto, 2, 1),
+  ADD_TEST (sendmsg, 2, 1),
+  ADD_TEST (creat, 2, 1),
+  ADD_TEST (connect, 2, 1),
+  ADD_TEST (tcdrain, 2, 1),
+  ADD_TEST (msgrcv, 2, 0),
+  ADD_TEST (msgsnd, 2, 1),
+};
+#define ntest_tf (sizeof (tests) / sizeof (tests[0]))
+
+
+static int
+do_test (void)
+{
+  int val;
+  socklen_t len;
+
+  if (socketpair (AF_UNIX, SOCK_STREAM, PF_UNIX, fds) != 0)
+    {
+      perror ("socketpair");
+      exit (1);
+    }
+
+  val = 1;
+  len = sizeof(val);
+  setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
+  if (getsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, &len) < 0)
+    {
+      perror ("getsockopt");
+      exit (1);
+    }
+  if (val >= WRITE_BUFFER_SIZE)
+    {
+      puts ("minimum write buffer size too large");
+      exit (1);
+    }
+  setsockopt (fds[1], SOL_SOCKET, SO_SNDBUF, &val, sizeof(val));
+
+  int result = 0;
+  size_t cnt;
+  for (cnt = 0; cnt < ntest_tf; ++cnt)
+    {
+      if (tests[cnt].only_early)
+	continue;
+
+      if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0)
+	{
+	  puts ("b2 init failed");
+	  exit (1);
+	}
+
+      /* Reset the counter for the cleanup handler.  */
+      cl_called = 0;
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tests[cnt].tf, NULL) != 0)
+	{
+	  printf ("create for '%s' test failed\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      int r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  result = 1;
+	  continue;
+	}
+
+      struct timespec  ts = { .tv_sec = 0, .tv_nsec = 100000000 };
+      while (nanosleep (&ts, &ts) != 0)
+	continue;
+
+      if (pthread_cancel (th) != 0)
+	{
+	  printf ("cancel for '%s' failed\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+	{
+	  printf ("join for '%s' failed\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+      if (status != PTHREAD_CANCELED)
+	{
+	  printf ("thread for '%s' not canceled\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      if (pthread_barrier_destroy (&b2) != 0)
+	{
+	  puts ("barrier_destroy failed");
+	  result = 1;
+	  continue;
+	}
+
+      if (cl_called == 0)
+	{
+	  printf ("cleanup handler not called for '%s'\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+      if (cl_called > 1)
+	{
+	  printf ("cleanup handler called more than once for '%s'\n",
+		  tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      printf ("in-time cancel test of '%s' successful\n", tests[cnt].name);
+
+      if (tempfd != -1)
+	{
+	  close (tempfd);
+	  tempfd = -1;
+	}
+      if (tempfd2 != -1)
+	{
+	  close (tempfd2);
+	  tempfd2 = -1;
+	}
+      if (tempfname != NULL)
+	{
+	  unlink (tempfname);
+	  free (tempfname);
+	  tempfname = NULL;
+	}
+      if (tempmsg != -1)
+	{
+	  msgctl (tempmsg, IPC_RMID, NULL);
+	  tempmsg = -1;
+	}
+    }
+
+  for (cnt = 0; cnt < ntest_tf; ++cnt)
+    {
+      if (pthread_barrier_init (&b2, NULL, tests[cnt].nb) != 0)
+	{
+	  puts ("b2 init failed");
+	  exit (1);
+	}
+
+      /* Reset the counter for the cleanup handler.  */
+      cl_called = 0;
+
+      pthread_t th;
+      if (pthread_create (&th, NULL, tests[cnt].tf, (void *) 1l) != 0)
+	{
+	  printf ("create for '%s' test failed\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      int r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  result = 1;
+	  continue;
+	}
+
+      if (pthread_cancel (th) != 0)
+	{
+	  printf ("cancel for '%s' failed\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      r = pthread_barrier_wait (&b2);
+      if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+	{
+	  printf ("%s: barrier_wait failed\n", __FUNCTION__);
+	  result = 1;
+	  continue;
+	}
+
+      void *status;
+      if (pthread_join (th, &status) != 0)
+	{
+	  printf ("join for '%s' failed\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+      if (status != PTHREAD_CANCELED)
+	{
+	  printf ("thread for '%s' not canceled\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      if (pthread_barrier_destroy (&b2) != 0)
+	{
+	  puts ("barrier_destroy failed");
+	  result = 1;
+	  continue;
+	}
+
+      if (cl_called == 0)
+	{
+	  printf ("cleanup handler not called for '%s'\n", tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+      if (cl_called > 1)
+	{
+	  printf ("cleanup handler called more than once for '%s'\n",
+		  tests[cnt].name);
+	  result = 1;
+	  continue;
+	}
+
+      printf ("early cancel test of '%s' successful\n", tests[cnt].name);
+
+      if (tempfd != -1)
+	{
+	  close (tempfd);
+	  tempfd = -1;
+	}
+      if (tempfd2 != -1)
+	{
+	  close (tempfd2);
+	  tempfd2 = -1;
+	}
+      if (tempfname != NULL)
+	{
+	  unlink (tempfname);
+	  free (tempfname);
+	  tempfname = NULL;
+	}
+      if (tempmsg != -1)
+	{
+	  msgctl (tempmsg, IPC_RMID, NULL);
+	  tempmsg = -1;
+	}
+    }
+
+  return result;
+}
+
+#define TIMEOUT 60
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 1 - 0
test/nptl/tst-cancel5.c

@@ -0,0 +1 @@
+#include "tst-cancel4.c"

+ 1 - 0
test/nptl/tst-cancelx10.c

@@ -0,0 +1 @@
+#include "tst-cancel10.c"

+ 1 - 0
test/nptl/tst-cancelx11.c

@@ -0,0 +1 @@
+#include "tst-cancel11.c"

+ 1 - 0
test/nptl/tst-cancelx12.c

@@ -0,0 +1 @@
+#include "tst-cancel12.c"

+ 1 - 0
test/nptl/tst-cancelx13.c

@@ -0,0 +1 @@
+#include "tst-cancel13.c"

+ 1 - 0
test/nptl/tst-cancelx14.c

@@ -0,0 +1 @@
+#include "tst-cancel14.c"

+ 1 - 0
test/nptl/tst-cancelx15.c

@@ -0,0 +1 @@
+#include "tst-cancel15.c"

+ 1 - 0
test/nptl/tst-cancelx16.c

@@ -0,0 +1 @@
+#include "tst-cancel16.c"

+ 1 - 0
test/nptl/tst-cancelx18.c

@@ -0,0 +1 @@
+#include "tst-cancel18.c"

+ 1 - 0
test/nptl/tst-cancelx2.c

@@ -0,0 +1 @@
+#include "tst-cancel2.c"

+ 1 - 0
test/nptl/tst-cancelx20.c

@@ -0,0 +1 @@
+#include "tst-cancel20.c"

+ 1 - 0
test/nptl/tst-cancelx21.c

@@ -0,0 +1 @@
+#include "tst-cancel21.c"

+ 1 - 0
test/nptl/tst-cancelx3.c

@@ -0,0 +1 @@
+#include "tst-cancel3.c"

+ 1 - 0
test/nptl/tst-cancelx4.c

@@ -0,0 +1 @@
+#include "tst-cancel4.c"

+ 1 - 0
test/nptl/tst-cancelx6.c

@@ -0,0 +1 @@
+#include "tst-cancel6.c"

+ 1 - 0
test/nptl/tst-cancelx7.c

@@ -0,0 +1 @@
+#include "tst-cancel7.c"

+ 1 - 0
test/nptl/tst-cancelx8.c

@@ -0,0 +1 @@
+#include "tst-cancel8.c"

+ 1 - 0
test/nptl/tst-cancelx9.c

@@ -0,0 +1 @@
+#include "tst-cancel9.c"

+ 1 - 0
test/nptl/tst-cleanupx0.c

@@ -0,0 +1 @@
+#include "tst-cleanup0.c"

+ 1 - 0
test/nptl/tst-cleanupx1.c

@@ -0,0 +1 @@
+#include "tst-cleanup1.c"

+ 1 - 0
test/nptl/tst-cleanupx2.c

@@ -0,0 +1 @@
+#include "tst-cleanup2.c"

+ 1 - 0
test/nptl/tst-cleanupx3.c

@@ -0,0 +1 @@
+#include "tst-cleanup3.c"

+ 1 - 0
test/nptl/tst-cleanupx4.c

@@ -0,0 +1 @@
+#include "tst-cleanup4.c"

+ 160 - 0
test/nptl/tst-cond22.c

@@ -0,0 +1,160 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static pthread_barrier_t b;
+static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+
+
+static void
+cl (void *arg)
+{
+  pthread_mutex_unlock (&m);
+}
+
+
+static void *
+tf (void *arg)
+{
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      printf ("%s: mutex_lock failed\n", __func__);
+      exit (1);
+    }
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      printf ("%s: barrier_wait failed\n", __func__);
+      exit (1);
+    }
+  pthread_cleanup_push (cl, NULL);
+  /* We have to loop here because the cancellation might come after
+     the cond_wait call left the cancelable area and is then waiting
+     on the mutex.  In this case the beginning of the second cond_wait
+     call will cause the cancellation to happen.  */
+  do
+    if (pthread_cond_wait (&c, &m) != 0)
+      {
+	printf ("%s: cond_wait failed\n", __func__);
+	exit (1);
+      }
+  while (arg == NULL);
+  pthread_cleanup_pop (0);
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      printf ("%s: mutex_unlock failed\n", __func__);
+      exit (1);
+    }
+  return NULL;
+}
+
+
+static int
+do_test (void)
+{
+  int status = 0;
+
+  if (pthread_barrier_init (&b, NULL, 2) != 0)
+    {
+      puts ("barrier_init failed");
+      return 1;
+    }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("1st create failed");
+      return 1;
+    }
+  int e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("1st barrier_wait failed");
+      return 1;
+    }
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("1st mutex_lock failed");
+      return 1;
+    }
+  if (pthread_cond_signal (&c) != 0)
+    {
+      puts ("1st cond_signal failed");
+      return 1;
+    }
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      return 1;
+    }
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("1st mutex_unlock failed");
+      return 1;
+    }
+  void *res;
+  if (pthread_join (th, &res) != 0)
+    {
+      puts ("1st join failed");
+      return 1;
+    }
+  if (res != PTHREAD_CANCELED)
+    {
+      puts ("first thread not canceled");
+      status = 1;
+    }
+
+  printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n",
+	  c.__data.__lock, c.__data.__futex, c.__data.__total_seq,
+	  c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex,
+	  c.__data.__nwaiters, c.__data.__broadcast_seq);
+
+  if (pthread_create (&th, NULL, tf, (void *) 1l) != 0)
+    {
+      puts ("2nd create failed");
+      return 1;
+    }
+  e = pthread_barrier_wait (&b);
+  if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
+    {
+      puts ("2nd barrier_wait failed");
+      return 1;
+    }
+  if (pthread_mutex_lock (&m) != 0)
+    {
+      puts ("2nd mutex_lock failed");
+      return 1;
+    }
+  if (pthread_cond_signal (&c) != 0)
+    {
+      puts ("2nd cond_signal failed");
+      return 1;
+    }
+  if (pthread_mutex_unlock (&m) != 0)
+    {
+      puts ("2nd mutex_unlock failed");
+      return 1;
+    }
+  if (pthread_join (th, &res) != 0)
+    {
+      puts ("2nd join failed");
+      return 1;
+    }
+  if (res != NULL)
+    {
+      puts ("2nd thread canceled");
+      status = 1;
+    }
+
+  printf ("cond = { %d, %x, %lld, %lld, %lld, %p, %u, %u }\n",
+	  c.__data.__lock, c.__data.__futex, c.__data.__total_seq,
+	  c.__data.__wakeup_seq, c.__data.__woken_seq, c.__data.__mutex,
+	  c.__data.__nwaiters, c.__data.__broadcast_seq);
+
+  return status;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 184 - 0
test/nptl/tst-cond23.c

@@ -0,0 +1,184 @@
+/* Copyright (C) 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2008.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <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
+check (pthread_condattr_t *condattr, int pshared, clockid_t cl)
+{
+  clockid_t cl2;
+  if (pthread_condattr_getclock (condattr, &cl2) != 0)
+    {
+      puts ("condattr_getclock failed");
+      return 1;
+    }
+  if (cl != cl2)
+    {
+      printf ("condattr_getclock returned wrong value: %d, expected %d\n",
+	      (int) cl2, (int) cl);
+      return 1;
+    }
+
+  int p;
+  if (pthread_condattr_getpshared (condattr, &p) != 0)
+    {
+      puts ("condattr_getpshared failed");
+      return 1;
+    }
+  else if (p != pshared)
+    {
+      printf ("condattr_getpshared returned wrong value: %d, expected %d\n",
+	      p, pshared);
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+run_test (clockid_t cl)
+{
+  pthread_condattr_t condattr;
+
+  printf ("clock = %d\n", (int) cl);
+
+  if (pthread_condattr_init (&condattr) != 0)
+    {
+      puts ("condattr_init failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME))
+    return 1;
+
+  if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("1st condattr_setpshared failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME))
+    return 1;
+
+  if (pthread_condattr_setclock (&condattr, cl) != 0)
+    {
+      puts ("1st condattr_setclock failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_SHARED, cl))
+    return 1;
+
+  if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_PRIVATE) != 0)
+    {
+      puts ("2nd condattr_setpshared failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl))
+    return 1;
+
+  if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0)
+    {
+      puts ("2nd condattr_setclock failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME))
+    return 1;
+
+  if (pthread_condattr_setclock (&condattr, cl) != 0)
+    {
+      puts ("3rd condattr_setclock failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl))
+    return 1;
+
+  if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0)
+    {
+      puts ("3rd condattr_setpshared failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_SHARED, cl))
+    return 1;
+
+  if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0)
+    {
+      puts ("4th condattr_setclock failed");
+      return 1;
+    }
+
+  if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME))
+    return 1;
+
+  if (pthread_condattr_destroy (&condattr) != 0)
+    {
+      puts ("condattr_destroy failed");
+      return 1;
+    }
+
+  return 0;
+}
+#endif
+
+
+static int
+do_test (void)
+{
+#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1
+
+  puts ("_POSIX_CLOCK_SELECTION not supported, test skipped");
+  return 0;
+
+#else
+
+  int res = run_test (CLOCK_REALTIME);
+
+# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0
+#  if _POSIX_MONOTONIC_CLOCK == 0
+  int e = sysconf (_SC_MONOTONIC_CLOCK);
+  if (e < 0)
+    puts ("CLOCK_MONOTONIC not supported");
+  else if (e == 0)
+    {
+      puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0");
+      res = 1;
+    }
+  else
+#  endif
+    res |= run_test (CLOCK_MONOTONIC);
+# else
+  puts ("_POSIX_MONOTONIC_CLOCK not defined");
+# endif
+
+  return res;
+#endif
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 66 - 0
test/nptl/tst-dlsym1.c

@@ -0,0 +1,66 @@
+/* Test case by Hui Huang <hui.huang@sun.com>.  */
+#include <dlfcn.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+static void *
+start_routine (void *args)
+{
+  int i;
+  void **addrs = (void **) args;
+  for (i = 0; i < 10000; ++i)
+    addrs[i % 1024] = dlsym (NULL, "does_not_exist");
+
+  return addrs;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_t tid1, tid2, tid3;
+
+  void *addrs1[1024];
+  void *addrs2[1024];
+  void *addrs3[1024];
+
+  if (pthread_create (&tid1, NULL, start_routine, addrs1) != 0)
+    {
+      puts ("1st create failed");
+      exit (1);
+    }
+  if (pthread_create (&tid2, NULL, start_routine, addrs2) != 0)
+    {
+      puts ("2nd create failed");
+      exit (1);
+    }
+  if (pthread_create (&tid3, NULL, start_routine, addrs3) != 0)
+    {
+      puts ("3rd create failed");
+      exit (1);
+    }
+
+  if (pthread_join (tid1, NULL) != 0)
+    {
+      puts ("1st join failed");
+      exit (1);
+    }
+  if (pthread_join (tid2, NULL) != 0)
+    {
+      puts ("2nd join failed");
+      exit (1);
+    }
+  if (pthread_join (tid3, NULL) != 0)
+    {
+      puts ("2rd join failed");
+      exit (1);
+    }
+
+  return 0;
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 35 - 0
test/nptl/tst-fini1.c

@@ -0,0 +1,35 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <unistd.h>
+
+extern void m (void);
+
+int
+main (void)
+{
+  alarm (5);
+
+  m ();
+
+  /* The destructor is supposed to run now.  Make sure that if it is
+     not we will notice it by using 42 as the exit code.  In case the
+     destructor is run it will terminate with status zero.  */
+  return 42;
+}

+ 72 - 0
test/nptl/tst-fini1mod.c

@@ -0,0 +1,72 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <unistd.h>
+
+
+static void *
+tf (void *arg)
+{
+  int fds[2];
+  if (pipe (fds) != 0)
+    {
+      puts ("pipe failed");
+      exit (1);
+    }
+
+  char buf[10];
+  read (fds[0], buf, sizeof (buf));
+
+  puts ("read returned");
+  exit (1);
+}
+
+static pthread_t th;
+
+static void
+__attribute ((destructor))
+dest (void)
+{
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("cancel failed");
+      _exit (1);
+    }
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("join failed");
+      _exit (1);
+    }
+  /* Exit successfully.  */
+  _exit (0);
+}
+
+void
+m (void)
+{
+  if (pthread_create (&th, NULL, tf, NULL) != 0)
+    {
+      puts ("create failed");
+      _exit (1);
+    }
+}

+ 122 - 0
test/nptl/tst-getpid1.c

@@ -0,0 +1,122 @@
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <bits/stackinfo.h>
+
+#ifndef TEST_CLONE_FLAGS
+#define TEST_CLONE_FLAGS 0
+#endif
+
+static int sig;
+
+static int
+f (void *a)
+{
+  puts ("in f");
+  union sigval sival;
+  sival.sival_int = getpid ();
+  printf ("pid = %d\n", sival.sival_int);
+  if (sigqueue (getppid (), sig, sival) != 0)
+    return 1;
+  return 0;
+}
+
+
+static int
+do_test (void)
+{
+  int mypid = getpid ();
+
+  sig = SIGRTMIN;
+  sigset_t ss;
+  sigemptyset (&ss);
+  sigaddset (&ss, sig);
+  if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
+    {
+      printf ("sigprocmask failed: %m\n");
+      return 1;
+    }
+
+#ifdef __ia64__
+  extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
+		       size_t __child_stack_size, int __flags,
+		       void *__arg, ...);
+  char st[256 * 1024] __attribute__ ((aligned));
+  pid_t p = __clone2 (f, st, sizeof (st), TEST_CLONE_FLAGS, 0);
+#else
+  char st[128 * 1024] __attribute__ ((aligned));
+# if _STACK_GROWS_DOWN
+  pid_t p = clone (f, st + sizeof (st), TEST_CLONE_FLAGS, 0);
+# elif _STACK_GROWS_UP
+  pid_t p = clone (f, st, TEST_CLONE_FLAGS, 0);
+# else
+#  error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+# endif
+#endif
+  if (p == -1)
+    {
+      printf("clone failed: %m\n");
+      return 1;
+    }
+  printf ("new thread: %d\n", (int) p);
+
+  siginfo_t si;
+  do
+    if (sigwaitinfo (&ss, &si) < 0)
+      {
+	printf("sigwaitinfo failed: %m\n");
+	kill (p, SIGKILL);
+	return 1;
+      }
+  while  (si.si_signo != sig || si.si_code != SI_QUEUE);
+
+  int e;
+  if (waitpid (p, &e, __WCLONE) != p)
+    {
+      puts ("waitpid failed");
+      kill (p, SIGKILL);
+      return 1;
+    }
+  if (!WIFEXITED (e))
+    {
+      if (WIFSIGNALED (e))
+	printf ("died from signal %s\n", strsignal (WTERMSIG (e)));
+      else
+	puts ("did not terminate correctly");
+      return 1;
+    }
+  if (WEXITSTATUS (e) != 0)
+    {
+      printf ("exit code %d\n", WEXITSTATUS (e));
+      return 1;
+    }
+
+  if (si.si_int != (int) p)
+    {
+      printf ("expected PID %d, got si_int %d\n", (int) p, si.si_int);
+      kill (p, SIGKILL);
+      return 1;
+    }
+
+  if (si.si_pid != p)
+    {
+      printf ("expected PID %d, got si_pid %d\n", (int) p, (int) si.si_pid);
+      kill (p, SIGKILL);
+      return 1;
+    }
+
+  if (getpid () != mypid)
+    {
+      puts ("my PID changed");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 2 - 0
test/nptl/tst-getpid2.c

@@ -0,0 +1,2 @@
+#define TEST_CLONE_FLAGS CLONE_VM
+#include "tst-getpid1.c"

+ 114 - 0
test/nptl/tst-getpid3.c

@@ -0,0 +1,114 @@
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+
+static pid_t pid;
+
+static void *
+pid_thread (void *arg)
+{
+  if (pid != getpid ())
+    {
+      printf ("pid wrong in thread: should be %d, is %d\n",
+	      (int) pid, (int) getpid ());
+      return (void *) 1L;
+    }
+
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  pid = getpid ();
+
+  pthread_t thr;
+  int ret = pthread_create (&thr, NULL, pid_thread, NULL);
+  if (ret)
+    {
+      printf ("pthread_create failed: %d\n", ret);
+      return 1;
+    }
+
+  void *thr_ret;
+  ret = pthread_join (thr, &thr_ret);
+  if (ret)
+    {
+      printf ("pthread_create failed: %d\n", ret);
+      return 1;
+    }
+  else if (thr_ret)
+    {
+      printf ("thread getpid failed\n");
+      return 1;
+    }
+
+  pid_t child = fork ();
+  if (child == -1)
+    {
+      printf ("fork failed: %m\n");
+      return 1;
+    }
+  else if (child == 0)
+    {
+      if (pid == getpid ())
+	{
+	  puts ("pid did not change after fork");
+	  exit (1);
+	}
+
+      pid = getpid ();
+      ret = pthread_create (&thr, NULL, pid_thread, NULL);
+      if (ret)
+	{
+	  printf ("pthread_create failed: %d\n", ret);
+	  return 1;
+	}
+
+      ret = pthread_join (thr, &thr_ret);
+      if (ret)
+	{
+	  printf ("pthread_create failed: %d\n", ret);
+	  return 1;
+	}
+      else if (thr_ret)
+	{
+	  printf ("thread getpid failed\n");
+	  return 1;
+	}
+
+      return 0;
+    }
+
+  int status;
+  if (TEMP_FAILURE_RETRY (waitpid (child, &status, 0)) != child)
+    {
+      puts ("waitpid failed");
+      kill (child, SIGKILL);
+      return 1;
+    }
+
+  if (!WIFEXITED (status))
+    {
+      if (WIFSIGNALED (status))
+	printf ("died from signal %s\n", strsignal (WTERMSIG (status)));
+      else
+	puts ("did not terminate correctly");
+      return 1;
+    }
+  if (WEXITSTATUS (status) != 0)
+    {
+      printf ("exit code %d\n", WEXITSTATUS (status));
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 1 - 0
test/nptl/tst-initializers1-c89.c

@@ -0,0 +1 @@
+#include "tst-initializers1.c"

+ 1 - 0
test/nptl/tst-initializers1-c99.c

@@ -0,0 +1 @@
+#include "tst-initializers1.c"

+ 1 - 0
test/nptl/tst-initializers1-gnu89.c

@@ -0,0 +1 @@
+#include "tst-initializers1.c"

+ 1 - 0
test/nptl/tst-initializers1-gnu99.c

@@ -0,0 +1 @@
+#include "tst-initializers1.c"

+ 2 - 0
test/nptl/tst-join6.c

@@ -0,0 +1,2 @@
+#define WAIT_IN_CHILD 1
+#include "tst-join5.c"

+ 1 - 0
test/nptl/tst-oddstacklimit.c

@@ -0,0 +1 @@
+#include "tst-basic1.c"

+ 1 - 0
test/nptl/tst-oncex3.c

@@ -0,0 +1 @@
+#include "tst-once3.c"

+ 1 - 0
test/nptl/tst-oncex4.c

@@ -0,0 +1 @@
+#include "tst-once4.c"

+ 2 - 0
test/nptl/tst-rwlock2a.c

@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
+#include "tst-rwlock2.c"

+ 88 - 0
test/nptl/tst-sem10.c

@@ -0,0 +1,88 @@
+/* Copyright (C) 2007 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Jakub Jelinek <jakub@redhat.com>, 2007.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <pthread.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;
+  if (sem_init (&s, 0, 0) == -1)
+    {
+      puts ("sem_init failed");
+      return 1;
+    }
+
+  struct timeval tv;
+  if (gettimeofday (&tv, NULL) != 0)
+    {
+      puts ("gettimeofday failed");
+      return 1;
+    }
+
+  struct timespec ts;
+  TIMEVAL_TO_TIMESPEC (&tv, &ts);
+
+  /* Set ts to yesterday.  */
+  ts.tv_sec -= 86400;
+
+  int type_before;
+  if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_before) != 0)
+    {
+      puts ("first pthread_setcanceltype failed");
+      return 1;
+    }
+
+  errno = 0;
+  if (TEMP_FAILURE_RETRY (sem_timedwait (&s, &ts)) != -1)
+    {
+      puts ("sem_timedwait succeeded");
+      return 1;
+    }
+  if (errno != ETIMEDOUT)
+    {
+      printf ("sem_timedwait return errno = %d instead of ETIMEDOUT\n",
+	      errno);
+      return 1;
+    }
+
+  int type_after;
+  if (pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, &type_after) != 0)
+    {
+      puts ("second pthread_setcanceltype failed");
+      return 1;
+    }
+  if (type_after != PTHREAD_CANCEL_DEFERRED)
+    {
+      puts ("sem_timedwait changed cancellation type");
+      return 1;
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 76 - 0
test/nptl/tst-sem11.c

@@ -0,0 +1,76 @@
+#include <semaphore.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <internaltypes.h>
+
+#ifndef SEM_WAIT
+# define SEM_WAIT(s) sem_wait (s)
+#endif
+
+static void *
+tf (void *arg)
+{
+#ifdef PREPARE
+  PREPARE
+#endif
+  SEM_WAIT (arg);
+  return NULL;
+}
+
+int
+main (void)
+{
+  int tries = 5;
+  pthread_t th;
+  sem_t s;
+ again:
+  if (sem_init (&s, 0, 0) != 0)
+    {
+      puts ("sem_init failed");
+      return 1;
+    }
+
+  struct new_sem *is = (struct new_sem *) &s;
+
+  if (is->nwaiters != 0)
+    {
+      puts ("nwaiters not initialized");
+      return 1;
+    }
+
+  if (pthread_create (&th, NULL, tf, &s) != 0)
+    {
+      puts ("pthread_create failed");
+      return 1;
+    }
+
+  sleep (1);
+
+  if (pthread_cancel (th) != 0)
+    {
+      puts ("pthread_cancel failed");
+      return 1;
+    }
+
+  void *r;
+  if (pthread_join (th, &r) != 0)
+    {
+      puts ("pthread_join failed");
+      return 1;
+    }
+  if (r != PTHREAD_CANCELED && --tries > 0)
+    {
+      /* Maybe we get the scheduling right the next time.  */
+      sem_destroy (&s);
+      goto again;
+    }
+
+  if (is->nwaiters != 0)
+    {
+      puts ("nwaiters not reset");
+      return 1;
+    }
+
+  return 0;
+}

+ 14 - 0
test/nptl/tst-sem12.c

@@ -0,0 +1,14 @@
+#include <time.h>
+#include <sys/time.h>
+
+
+#define PREPARE \
+  struct timespec ts; \
+  struct timeval tv; \
+  gettimeofday (&tv, NULL); \
+  TIMEVAL_TO_TIMESPEC (&tv, &ts); \
+  ts.tv_sec += 60;
+
+#define SEM_WAIT(s) sem_timedwait (s, &ts)
+
+#include "tst-sem11.c"

+ 59 - 0
test/nptl/tst-signal7.c

@@ -0,0 +1,59 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@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 <errno.h>
+#include <pthreadP.h>
+#include <signal.h>
+#include <stdio.h>
+
+
+static int
+do_test (void)
+{
+  int result = 0;
+
+  errno = 0;
+  if (sigaction (SIGCANCEL, NULL, NULL) == 0)
+    {
+      puts ("sigaction(SIGCANCEL) did not fail");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      puts ("sigaction(SIGCANCEL) did not set errno to EINVAL");
+      result = 1;
+    }
+
+  errno = 0;
+  if (sigaction (SIGSETXID, NULL, NULL) == 0)
+    {
+      puts ("sigaction(SIGSETXID) did not fail");
+      result = 1;
+    }
+  else if (errno != EINVAL)
+    {
+      puts ("sigaction(SIGSETXID) did not set errno to EINVAL");
+      result = 1;
+    }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 89 - 0
test/nptl/tst-tsd6.c

@@ -0,0 +1,89 @@
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#define NKEYS 100
+static pthread_key_t keys[NKEYS];
+static pthread_barrier_t b;
+
+
+static void *
+tf (void *arg)
+{
+  void *res = NULL;
+  for (int i = 0; i < NKEYS; ++i)
+    {
+      void *p = pthread_getspecific (keys[i]);
+      pthread_setspecific (keys[i], (void *) 7);
+      if (p != NULL)
+	res = p;
+    }
+  if (arg != NULL)
+    {
+      pthread_barrier_wait (arg);
+      pthread_barrier_wait (arg);
+    }
+  return res;
+}
+
+
+static int
+do_test (void)
+{
+  pthread_barrier_init (&b, NULL, 2);
+
+  for (int i = 0; i < NKEYS; ++i)
+    if (pthread_key_create (&keys[i], NULL) != 0)
+      {
+	puts ("cannot create keys");
+	return 1;
+      }
+
+  pthread_t th;
+  if (pthread_create (&th, NULL, tf, &b) != 0)
+    {
+      puts ("cannot create thread in parent");
+      return 1;
+    }
+
+  pthread_barrier_wait (&b);
+
+  pid_t pid = fork ();
+  if (pid == 0)
+    {
+      if (pthread_create (&th, NULL, tf, NULL) != 0)
+	{
+	  puts ("cannot create thread in child");
+	  exit (1);
+	}
+
+      void *res;
+      pthread_join (th, &res);
+
+      exit (res != NULL);
+    }
+  else if (pid == -1)
+    {
+      puts ("cannot create child process");
+      return 1;
+    }
+
+  int s;
+  if (TEMP_FAILURE_RETRY (waitpid (pid, &s, 0)) != pid)
+    {
+      puts ("failing to wait for child process");
+      return 1;
+    }
+
+  pthread_barrier_wait (&b);
+  pthread_join (th, NULL);
+
+  return !WIFEXITED (s) ? 2 : WEXITSTATUS (s);
+}
+
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 96 - 0
test/nptl/tst-typesizes.c

@@ -0,0 +1,96 @@
+/* Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <drepper@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 <stdio.h>
+#include <pthreadP.h>
+#include <semaphore.h>
+
+static const struct
+{
+  const char *name;
+  size_t expected;
+  size_t is;
+} types[] =
+  {
+#define T(t, c) \
+    { #t, c, sizeof (t) }
+    T (pthread_attr_t, __SIZEOF_PTHREAD_ATTR_T),
+    T (pthread_mutex_t, __SIZEOF_PTHREAD_MUTEX_T),
+    T (pthread_mutexattr_t, __SIZEOF_PTHREAD_MUTEXATTR_T),
+    T (pthread_cond_t, __SIZEOF_PTHREAD_COND_T),
+    T (pthread_condattr_t, __SIZEOF_PTHREAD_CONDATTR_T),
+    T (pthread_rwlock_t, __SIZEOF_PTHREAD_RWLOCK_T),
+    T (pthread_rwlockattr_t, __SIZEOF_PTHREAD_RWLOCKATTR_T),
+    T (pthread_barrier_t, __SIZEOF_PTHREAD_BARRIER_T),
+    T (pthread_barrierattr_t, __SIZEOF_PTHREAD_BARRIERATTR_T)
+  };
+
+static int
+do_test (void)
+{
+  int result = 0;
+
+#define TEST_TYPE(name) \
+  printf ("%s: ", #name);						      \
+  if (sizeof (name) != sizeof (((name *) 0)->__size))			      \
+    {									      \
+      printf ("expected %zu, is %zu\n",					      \
+	      sizeof (((name *) 0)->__size), sizeof (name));		      \
+      result = 1;							      \
+    }									      \
+  else									      \
+    puts ("OK")
+
+  TEST_TYPE (pthread_mutex_t);
+  TEST_TYPE (pthread_cond_t);
+  TEST_TYPE (pthread_rwlock_t);
+
+#define TEST_TYPE2(name, internal)					      \
+  printf ("%s: ", #name);						      \
+  if (sizeof (((name *) 0)->__size) < sizeof (internal))		      \
+    {									      \
+      printf ("expected %zu, is %zu\n",					      \
+	      sizeof (((name *) 0)->__size), sizeof (internal));	      \
+      result = 1;							      \
+    }									      \
+  else									      \
+    puts ("OK")
+
+  TEST_TYPE2 (pthread_attr_t, struct pthread_attr);
+  TEST_TYPE2 (pthread_mutexattr_t, struct pthread_mutexattr);
+  TEST_TYPE2 (pthread_condattr_t, struct pthread_condattr);
+  TEST_TYPE2 (pthread_rwlockattr_t, struct pthread_rwlockattr);
+  TEST_TYPE2 (pthread_barrier_t, struct pthread_barrier);
+  TEST_TYPE2 (pthread_barrierattr_t, struct pthread_barrierattr);
+  TEST_TYPE2 (sem_t, struct new_sem);
+  TEST_TYPE2 (sem_t, struct old_sem);
+
+  for (size_t i = 0; i < sizeof (types) / sizeof (types[0]); ++i)
+    if (types[i].expected != types[i].is)
+      {
+	printf ("%s: expected %zu, is %zu\n",
+		types[i].name, types[i].expected, types[i].is);
+	result = 1;
+      }
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 47 - 0
test/nptl/tst-unload.c

@@ -0,0 +1,47 @@
+/* Tests for non-unloading of libpthread.
+   Copyright (C) 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <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 <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  void *p = dlopen ("libpthread.so.0", RTLD_LAZY);
+
+  if (p == NULL)
+    {
+      puts ("failed to load libpthread.so.0");
+      return 1;
+    }
+
+  if (dlclose (p) != 0)
+    {
+      puts ("dlclose (libpthread.so.0) failed");
+      return 1;
+    }
+
+  puts ("seems to work");
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 150 - 0
test/nptl/tst-vfork1.c

@@ -0,0 +1,150 @@
+/* Test for vfork functions.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* This test relies on non-POSIX functionality since the child
+   processes call write and getpid.  */
+static int
+do_test (void)
+{
+  int result = 0;
+  int fd[2];
+
+  if (pipe (fd) == -1)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  /* First vfork() without previous getpid().  */
+  pid_t p1;
+  if ((p1 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("1st vfork failed");
+      result = 1;
+    }
+
+  pid_t p2 = 0;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("1st read failed");
+      result = 1;
+    }
+  int r;
+  if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
+    {
+      puts ("1st waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 1st child failed");
+      result = 1;
+    }
+
+  /* Main process' ID.  */
+  pid_t p0 = getpid ();
+
+  /* vfork() again, but after a getpid() in the main process.  */
+  pid_t p3;
+  if ((p3 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("2nd vfork failed");
+      result = 1;
+    }
+
+  pid_t p4;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("2nd read failed");
+      result = 1;
+    }
+  if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
+    {
+      puts ("2nd waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 2nd child failed");
+      result = 1;
+    }
+
+  /* And getpid in the main process again.  */
+  pid_t p5 = getpid ();
+
+  /* Analysis of the results.  */
+  if (p0 != p5)
+    {
+      printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
+      result = 1;
+    }
+
+  if (p0 == p1)
+    {
+      printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
+      result = 1;
+    }
+
+  if (p1 != p2)
+    {
+      printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
+      result = 1;
+    }
+
+  if (p0 == p3)
+    {
+      printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
+      result = 1;
+    }
+
+  if (p3 != p4)
+    {
+      printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
+      result = 1;
+    }
+
+  close (fd[0]);
+  close (fd[1]);
+
+  if (result == 0)
+    puts ("All OK");
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 150 - 0
test/nptl/tst-vfork1x.c

@@ -0,0 +1,150 @@
+/* Test for vfork functions.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* This test relies on non-POSIX functionality since the child
+   processes call write and getpid.  */
+static int
+do_test (void)
+{
+  int result = 0;
+  int fd[2];
+
+  if (pipe (fd) == -1)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  /* First vfork() without previous getpid().  */
+  pid_t p1;
+  if ((p1 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("1st vfork failed");
+      result = 1;
+    }
+
+  pid_t p2 = 0;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("1st read failed");
+      result = 1;
+    }
+  int r;
+  if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
+    {
+      puts ("1st waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 1st child failed");
+      result = 1;
+    }
+
+  /* Main process' ID.  */
+  pid_t p0 = getpid ();
+
+  /* vfork() again, but after a getpid() in the main process.  */
+  pid_t p3;
+  if ((p3 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("2nd vfork failed");
+      result = 1;
+    }
+
+  pid_t p4;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("2nd read failed");
+      result = 1;
+    }
+  if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
+    {
+      puts ("2nd waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 2nd child failed");
+      result = 1;
+    }
+
+  /* And getpid in the main process again.  */
+  pid_t p5 = getpid ();
+
+  /* Analysis of the results.  */
+  if (p0 != p5)
+    {
+      printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
+      result = 1;
+    }
+
+  if (p0 == p1)
+    {
+      printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
+      result = 1;
+    }
+
+  if (p1 != p2)
+    {
+      printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
+      result = 1;
+    }
+
+  if (p0 == p3)
+    {
+      printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
+      result = 1;
+    }
+
+  if (p3 != p4)
+    {
+      printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
+      result = 1;
+    }
+
+  close (fd[0]);
+  close (fd[1]);
+
+  if (result == 0)
+    puts ("All OK");
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 199 - 0
test/nptl/tst-vfork2.c

@@ -0,0 +1,199 @@
+/* Test for vfork functions.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int raise_fail;
+
+static void
+alrm (int sig)
+{
+  if (raise (SIGUSR1) < 0)
+    raise_fail = 1;
+}
+
+/* This test relies on non-POSIX functionality since the child
+   processes call write, nanosleep and getpid.  */
+static int
+do_test (void)
+{
+  int result = 0;
+  int fd[2];
+
+  signal (SIGUSR1, SIG_IGN);
+
+  struct sigaction sa;
+  sa.sa_handler = alrm;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction (SIGALRM, &sa, NULL) < 0)
+    {
+      puts ("couldn't set up SIGALRM handler");
+      return 1;
+    }
+
+  if (pipe (fd) == -1)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  struct itimerval it;
+  it.it_value.tv_sec = 0;
+  it.it_value.tv_usec = 200 * 1000;
+  it.it_interval = it.it_value;
+  if (setitimer (ITIMER_REAL, &it, NULL) < 0)
+    {
+      puts ("couldn't set up timer");
+      return 1;
+    }
+
+  /* First vfork() without previous getpid().  */
+  pid_t p1;
+  if ((p1 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+
+      struct timespec ts;
+      ts.tv_sec = 1;
+      ts.tv_nsec = 0;
+      TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("1st vfork failed");
+      result = 1;
+    }
+
+  memset (&it, 0, sizeof (it));
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  pid_t p2 = 0;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("1st read failed");
+      result = 1;
+    }
+  int r;
+  if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
+    {
+      puts ("1st waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 1st child failed");
+      result = 1;
+    }
+
+  /* Main process' ID.  */
+  pid_t p0 = getpid ();
+
+  /* vfork() again, but after a getpid() in the main process.  */
+  pid_t p3;
+  if ((p3 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("2nd vfork failed");
+      result = 1;
+    }
+
+  pid_t p4;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("2nd read failed");
+      result = 1;
+    }
+  if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
+    {
+      puts ("2nd waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 2nd child failed");
+      result = 1;
+    }
+
+  /* And getpid in the main process again.  */
+  pid_t p5 = getpid ();
+
+  /* Analysis of the results.  */
+  if (p0 != p5)
+    {
+      printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
+      result = 1;
+    }
+
+  if (p0 == p1)
+    {
+      printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
+      result = 1;
+    }
+
+  if (p1 != p2)
+    {
+      printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
+      result = 1;
+    }
+
+  if (p0 == p3)
+    {
+      printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
+      result = 1;
+    }
+
+  if (p3 != p4)
+    {
+      printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
+      result = 1;
+    }
+
+  close (fd[0]);
+  close (fd[1]);
+
+  if (raise_fail)
+    {
+      puts ("raise failed");
+      result = 1;
+    }
+
+  if (result == 0)
+    puts ("All OK");
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"

+ 199 - 0
test/nptl/tst-vfork2x.c

@@ -0,0 +1,199 @@
+/* Test for vfork functions.
+   Copyright (C) 2004 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Ulrich Drepper <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 <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+int raise_fail;
+
+static void
+alrm (int sig)
+{
+  if (raise (SIGUSR1) < 0)
+    raise_fail = 1;
+}
+
+/* This test relies on non-POSIX functionality since the child
+   processes call write, nanosleep and getpid.  */
+static int
+do_test (void)
+{
+  int result = 0;
+  int fd[2];
+
+  signal (SIGUSR1, SIG_IGN);
+
+  struct sigaction sa;
+  sa.sa_handler = alrm;
+  sigemptyset (&sa.sa_mask);
+  sa.sa_flags = 0;
+  if (sigaction (SIGALRM, &sa, NULL) < 0)
+    {
+      puts ("couldn't set up SIGALRM handler");
+      return 1;
+    }
+
+  if (pipe (fd) == -1)
+    {
+      puts ("pipe failed");
+      return 1;
+    }
+
+  struct itimerval it;
+  it.it_value.tv_sec = 0;
+  it.it_value.tv_usec = 200 * 1000;
+  it.it_interval = it.it_value;
+  if (setitimer (ITIMER_REAL, &it, NULL) < 0)
+    {
+      puts ("couldn't set up timer");
+      return 1;
+    }
+
+  /* First vfork() without previous getpid().  */
+  pid_t p1;
+  if ((p1 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+
+      struct timespec ts;
+      ts.tv_sec = 1;
+      ts.tv_nsec = 0;
+      TEMP_FAILURE_RETRY (nanosleep (&ts, &ts));
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("1st vfork failed");
+      result = 1;
+    }
+
+  memset (&it, 0, sizeof (it));
+  setitimer (ITIMER_REAL, &it, NULL);
+
+  pid_t p2 = 0;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p2, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("1st read failed");
+      result = 1;
+    }
+  int r;
+  if (TEMP_FAILURE_RETRY (waitpid (p1, &r, 0)) != p1)
+    {
+      puts ("1st waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 1st child failed");
+      result = 1;
+    }
+
+  /* Main process' ID.  */
+  pid_t p0 = getpid ();
+
+  /* vfork() again, but after a getpid() in the main process.  */
+  pid_t p3;
+  if ((p3 = vfork ()) == 0)
+    {
+      pid_t p = getpid ();
+      _exit (TEMP_FAILURE_RETRY (write (fd[1], &p, sizeof (p))) != sizeof (p));
+    }
+  else if (p1 == -1)
+    {
+      puts ("2nd vfork failed");
+      result = 1;
+    }
+
+  pid_t p4;
+  if (TEMP_FAILURE_RETRY (read (fd[0], &p4, sizeof (pid_t))) != sizeof (pid_t))
+    {
+      puts ("2nd read failed");
+      result = 1;
+    }
+  if (TEMP_FAILURE_RETRY (waitpid (p3, &r, 0)) != p3)
+    {
+      puts ("2nd waitpid failed");
+      result = 1;
+    }
+  else if (r != 0)
+    {
+      puts ("write in 2nd child failed");
+      result = 1;
+    }
+
+  /* And getpid in the main process again.  */
+  pid_t p5 = getpid ();
+
+  /* Analysis of the results.  */
+  if (p0 != p5)
+    {
+      printf ("p0(%ld) != p5(%ld)\n", (long int) p0, (long int) p5);
+      result = 1;
+    }
+
+  if (p0 == p1)
+    {
+      printf ("p0(%ld) == p1(%ld)\n", (long int) p0, (long int) p1);
+      result = 1;
+    }
+
+  if (p1 != p2)
+    {
+      printf ("p1(%ld) != p2(%ld)\n", (long int) p1, (long int) p2);
+      result = 1;
+    }
+
+  if (p0 == p3)
+    {
+      printf ("p0(%ld) == p3(%ld)\n", (long int) p0, (long int) p3);
+      result = 1;
+    }
+
+  if (p3 != p4)
+    {
+      printf ("p3(%ld) != p4(%ld)\n", (long int) p3, (long int) p4);
+      result = 1;
+    }
+
+  close (fd[0]);
+  close (fd[1]);
+
+  if (raise_fail)
+    {
+      puts ("raise failed");
+      result = 1;
+    }
+
+  if (result == 0)
+    puts ("All OK");
+
+  return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"