commit 47847907fd2dae3201bf87096886c44d7801768b
Author: Stefan Liebler <stli@linux.ibm.com>
Date:   Wed Sep 11 09:43:08 2019 +0200

    Speedup various nptl/tst-cancel20 and nptl/tst-cancel21 tests.
    
    Each of thease tests - tst-cancel20, tst-cancelx20, tst-cancel21,
    tst-cancelx21 and tst-cancel21-static - runs for 8s.
    
    do_one_test is called 4 times. Either in do_one_test (tst-cancel20.c)
    or in tf (tst-cancel21.c) "sleep (1)" is called 2 times.
    
    This patch removes the sleep which leads to a short runtime of one
    tst-cancel... invocation and as the nptl tests run in sequence,
    this patch saves roughly 39s of runtime for "make check".
    
    Just removing the sleeps leads to fails in tst-cancelx20 / x21
    as one cleanup-handler won't be called as pthread_barrier_wait is
    marked with attribute ((__nothrow__)).  Therefore the pthread_barrier_wait
    calls are replaced by writing to and reading from a pipe in order
    to synchronize the threads.
    
    ChangeLog:
    
            * nptl/tst-cancel20.c (b): Remove.
            (fd): Enhance to 6 elements.
            (tf_body): Use xwrite instead of pthread_barrier_wait.
            (do_one_test): Remove sleep and use read instead of
            pthread_barrier_wait.
            * nptl/tst-cancel21.c (b): Remove.
            (fd): Enhance to 6 elements.
            (tf_body): Use xwrite instead of pthread_barrier_wait.
            (tf): Remove sleep and use read instead of
            pthread_barrier_wait.

diff --git a/nptl/tst-cancel20.c b/nptl/tst-cancel20.c
index 96dfb71fa9..f82f899a83 100644
--- a/nptl/tst-cancel20.c
+++ b/nptl/tst-cancel20.c
@@ -21,11 +21,10 @@
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
+#include <support/xunistd.h>
 
 
-static int fd[4];
-static pthread_barrier_t b;
+static int fd[6];
 volatile int in_sh_body;
 unsigned long cleanups;
 
@@ -68,17 +67,21 @@ sh (int sig)
 static void __attribute__((noinline))
 tf_body (void)
 {
-  char c;
+  char c = 0;
 
   pthread_cleanup_push (cl, (void *) 3L);
 
-  int r = pthread_barrier_wait (&b);
-  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
-    {
-      puts ("child thread: barrier_wait failed");
-      exit (1);
-    }
-
+  /* Write to the pipe in order to inform do_one_test that we are now within
+     pthread_cleanup_push / pop and do_one_test can send us SIGHUP and cancel
+     this thread.
+     We do not use pthread_barrier_wait here as it is marked with
+     attribute ((__nothrow__)) and the region in .gcc_except_table section
+     which is responsible for calling the cleanup-handler would start just
+     before the next call to read in case of nptl/tst-cancelx20.c where we
+     build with "gcc -fexceptions -fasynchronous-unwind-tables".  */
+  xwrite (fd[5], &c, 1);
+
+  /* Blocks until either SIGHUP is received or the thread is canceled.  */
   if (read (fd[0], &c, 1) == 1)
     {
       puts ("read succeeded");
@@ -106,7 +109,7 @@ do_one_test (void)
 {
   in_sh_body = 0;
   cleanups = 0;
-  if (pipe (fd) != 0 || pipe (fd + 2) != 0)
+  if (pipe (fd) != 0 || pipe (fd + 2) != 0 || pipe (fd + 4) != 0)
     {
       puts ("pipe failed");
       return 1;
@@ -119,16 +122,17 @@ do_one_test (void)
       return 1;
     }
 
-  int r = pthread_barrier_wait (&b);
-  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+  /* Block until the thread is within pthread_cleanup_push / pop
+     in tf_body which is called by tf.  */
+  char c;
+  if (read (fd[4], &c, 1) != 1)
     {
-      puts ("parent thread: barrier_wait failed");
+      printf ("parent thread: Reading from pipe failed %m\n");
       return 1;
     }
 
-  sleep (1);
-
-  r = pthread_kill (th, SIGHUP);
+  /* Send signal SIGHUP where in_sh_body will be set to 1 in sh_body.  */
+  int r = pthread_kill (th, SIGHUP);
   if (r)
     {
       errno = r;
@@ -137,8 +141,9 @@ do_one_test (void)
     }
 
   while (in_sh_body == 0)
-    sleep (1);
+    ;
 
+  /* Cancel the thread while the signal handler blocks in read in sh_body.  */
   if (pthread_cancel (th) != 0)
     {
       puts ("cancel failed");
@@ -172,6 +177,8 @@ do_one_test (void)
   close (fd[1]);
   close (fd[2]);
   close (fd[3]);
+  close (fd[4]);
+  close (fd[5]);
 
   return 0;
 }
@@ -195,12 +202,6 @@ do_test (void)
       return 1;
     }
 
-  if (pthread_barrier_init (&b, NULL, 2) != 0)
-    {
-      puts ("barrier_init failed");
-      return 1;
-    }
-
   struct sigaction sa;
   sa.sa_handler = sh;
   sigemptyset (&sa.sa_mask);
diff --git a/nptl/tst-cancel21.c b/nptl/tst-cancel21.c
index 361510b027..30e396dee2 100644
--- a/nptl/tst-cancel21.c
+++ b/nptl/tst-cancel21.c
@@ -22,11 +22,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/wait.h>
-#include <unistd.h>
+#include <support/xunistd.h>
 
 
-static int fd[4];
-static pthread_barrier_t b;
+static int fd[6];
 volatile int in_sh_body;
 unsigned long cleanups;
 
@@ -69,17 +68,21 @@ sh (int sig)
 static void __attribute__((noinline))
 tf_body (void)
 {
-  char c;
+  char c = 0;
 
   pthread_cleanup_push (cl, (void *) 3L);
 
-  int r = pthread_barrier_wait (&b);
-  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
-    {
-      puts ("child thread: barrier_wait failed");
-      exit (1);
-    }
-
+  /* Write to the pipe in order to inform tf that we are now within
+     pthread_cleanup_push / pop and tf can send us SIGHUP and cancel
+     this thread.
+     We do not use pthread_barrier_wait here as it is marked with
+     attribute ((__nothrow__)) and the region in .gcc_except_table section
+     which is responsible for calling the cleanup-handler would start just
+     before the next call to read in case of nptl/tst-cancelx21.c where we
+     build with "gcc -fexceptions -fasynchronous-unwind-tables".  */
+  xwrite (fd[5], &c, 1);
+
+  /* Blocks until either SIGHUP is received or the thread is canceled.  */
   if (read (fd[0], &c, 1) == 1)
     {
       puts ("read succeeded");
@@ -97,16 +100,17 @@ tf (void *arg)
 {
   pthread_t th = (pthread_t) arg;
 
-  int r = pthread_barrier_wait (&b);
-  if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
+  /* Block until the main thread is within pthread_cleanup_push / pop
+     in tf_body which is called by do_one_test.  */
+  char c;
+  if (read (fd[4], &c, 1) != 1)
     {
-      puts ("parent thread: barrier_wait failed");
+      printf ("Reading from pipe failed %m\n");
       exit (1);
     }
 
-  sleep (1);
-
-  r = pthread_kill (th, SIGHUP);
+  /* Send signal SIGHUP where in_sh_body will be set to 1 in sh_body.  */
+  int r = pthread_kill (th, SIGHUP);
   if (r)
     {
       errno = r;
@@ -115,8 +119,10 @@ tf (void *arg)
     }
 
   while (in_sh_body == 0)
-    sleep (1);
+    ;
 
+  /* Cancel the parent thread while the signal handler blocks in read
+     in sh_body.  */
   if (pthread_cancel (th) != 0)
     {
       puts ("cancel failed");
@@ -142,11 +148,6 @@ tf (void *arg)
       exit (1);
     }
 
-  if (pthread_barrier_destroy (&b))
-    {
-      puts ("barrier destroy failed");
-      exit (1);
-    }
 
   /* The pipe closing must be issued after the cancellation handling to avoid
      a race condition where the cancellation runs after both pipe ends are
@@ -156,6 +157,8 @@ tf (void *arg)
   close (fd[1]);
   close (fd[2]);
   close (fd[3]);
+  close (fd[4]);
+  close (fd[5]);
 
   exit (0);
 }
@@ -186,14 +189,8 @@ do_one_test (void)
       return !WIFEXITED (status) || WEXITSTATUS (status);
     }
 
-  if (pthread_barrier_init (&b, NULL, 2) != 0)
-    {
-      puts ("barrier_init failed");
-      exit (1);
-    }
-
   cleanups = 0;
-  if (pipe (fd) != 0 || pipe (fd + 2) != 0)
+  if (pipe (fd) != 0 || pipe (fd + 2) != 0 || pipe (fd + 4) != 0)
     {
       puts ("pipe failed");
       exit (1);
