Mark Wielaard ebed60
From 3a30870111f1ce95d5715e66387d60548927c703 Mon Sep 17 00:00:00 2001
Mark Wielaard ebed60
From: Mark Wielaard <mjw@redhat.com>
Mark Wielaard ebed60
Date: Tue, 19 Jan 2016 15:13:47 +0100
Mark Wielaard ebed60
Subject: [PATCH] pthread_barrier vs newer glibc implementation
Mark Wielaard ebed60
Mark Wielaard ebed60
glibc 2.23 will have a new pthread_barrier implementation.
Mark Wielaard ebed60
This implementation reacts differently on bad usage of barriers.
Mark Wielaard ebed60
Because of this the bar_bad testcase will hang indefinitely.
Mark Wielaard ebed60
In particular pthread_barrier_destroy will hang when there are
Mark Wielaard ebed60
still other threads waiting on a barrier. To solve this we add
Mark Wielaard ebed60
extra threads to will "unblock" the hanging destroy by sleeping
Mark Wielaard ebed60
for a while and then also waiting on the barrier, which will unblock
Mark Wielaard ebed60
the destroy operation. Or if this is the last test, just exit
Mark Wielaard ebed60
the whole program since we are done anyway. Also newer glibc is
Mark Wielaard ebed60
more picky about destroying uninitialized barriers, we would crash
Mark Wielaard ebed60
when zero filling, so we now one fill. Which doesn't crash, but
Mark Wielaard ebed60
depending on glibc version might return an error or hang. Since
Mark Wielaard ebed60
depending on version we now get slightly different error reports
Mark Wielaard ebed60
there are now alternative exp files.
Mark Wielaard ebed60
Mark Wielaard ebed60
Tested against glibc 2.17, glibc 2.22 and glibc 2.23-prerelease.
Mark Wielaard ebed60
---
Mark Wielaard ebed60
 helgrind/tests/Makefile.am                         |  1 +
Mark Wielaard ebed60
 helgrind/tests/bar_bad.c                           | 51 ++++++++++++++--------
Mark Wielaard ebed60
 helgrind/tests/bar_bad.stderr.exp                  | 16 +++----
Mark Wielaard ebed60
 ....stderr.exp => bar_bad.stderr.exp-destroy-hang} | 30 ++++++++-----
Mark Wielaard ebed60
 4 files changed, 62 insertions(+), 36 deletions(-)
Mark Wielaard ebed60
 copy helgrind/tests/{bar_bad.stderr.exp => bar_bad.stderr.exp-destroy-hang} (72%)
Mark Wielaard ebed60
Mark Wielaard ebed60
diff --git a/helgrind/tests/Makefile.am b/helgrind/tests/Makefile.am
Mark Wielaard ebed60
index 8a0d6e6..df82169 100644
Mark Wielaard ebed60
--- a/helgrind/tests/Makefile.am
Mark Wielaard ebed60
+++ b/helgrind/tests/Makefile.am
Mark Wielaard ebed60
@@ -19,6 +19,7 @@ EXTRA_DIST = \
Mark Wielaard ebed60
 	cond_timedwait_test.vgtest cond_timedwait_test.stdout.exp \
Mark Wielaard ebed60
 		cond_timedwait_test.stderr.exp \
Mark Wielaard ebed60
 	bar_bad.vgtest bar_bad.stdout.exp bar_bad.stderr.exp \
Mark Wielaard ebed60
+		bar_bad.stderr.exp-destroy-hang \
Mark Wielaard ebed60
 	bar_trivial.vgtest bar_trivial.stdout.exp bar_trivial.stderr.exp \
Mark Wielaard ebed60
 	free_is_write.vgtest free_is_write.stdout.exp \
Mark Wielaard ebed60
 		free_is_write.stderr.exp \
Mark Wielaard ebed60
diff --git a/helgrind/tests/bar_bad.c b/helgrind/tests/bar_bad.c
Mark Wielaard ebed60
index dd6079c..424ae2f 100644
Mark Wielaard ebed60
--- a/helgrind/tests/bar_bad.c
Mark Wielaard ebed60
+++ b/helgrind/tests/bar_bad.c
Mark Wielaard ebed60
@@ -15,23 +15,27 @@ void* child1 ( void* arg )
Mark Wielaard ebed60
    return NULL;
Mark Wielaard ebed60
 }
Mark Wielaard ebed60
 
Mark Wielaard ebed60
+void *sleep1 ( void* arg )
Mark Wielaard ebed60
+{
Mark Wielaard ebed60
+   /* Long sleep, we hope to never trigger. */
Mark Wielaard ebed60
+   sleep (6);
Mark Wielaard ebed60
+   pthread_barrier_wait ( (pthread_barrier_t*)arg );
Mark Wielaard ebed60
+   return NULL;
Mark Wielaard ebed60
+}
Mark Wielaard ebed60
+
Mark Wielaard ebed60
+void *exit1 ( void* arg )
Mark Wielaard ebed60
+{
Mark Wielaard ebed60
+   /* Sleep a bit, then exit, we are done. */
Mark Wielaard ebed60
+   sleep (1);
Mark Wielaard ebed60
+   exit (0);
Mark Wielaard ebed60
+   return NULL;
Mark Wielaard ebed60
+}
Mark Wielaard ebed60
+
Mark Wielaard ebed60
 int main ( void )
Mark Wielaard ebed60
 {
Mark Wielaard ebed60
   pthread_barrier_t *bar1, *bar2, *bar3, *bar4, *bar5;
Mark Wielaard ebed60
-  pthread_t thr1, thr2;
Mark Wielaard ebed60
   int r;
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-  /* possibly set up a watchdog timer thread here. */
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
-
Mark Wielaard ebed60
+  pthread_t thr1, thr2, slp1, slp2, ext1;
Mark Wielaard ebed60
 
Mark Wielaard ebed60
   /* initialise a barrier with a zero count */
Mark Wielaard ebed60
   fprintf(stderr, "\ninitialise a barrier with zero count\n");
Mark Wielaard ebed60
@@ -49,6 +53,9 @@ int main ( void )
Mark Wielaard ebed60
   fprintf(stderr, "\ninitialise a barrier which has threads waiting on it\n");
Mark Wielaard ebed60
   bar3 = malloc(sizeof(pthread_barrier_t));
Mark Wielaard ebed60
   pthread_barrier_init(bar3, NULL, 2);
Mark Wielaard ebed60
+  /* create a thread, whose purpose is to "unblock" the barrier after
Mark Wielaard ebed60
+     some sleeping in case it keeps being blocked.  */
Mark Wielaard ebed60
+  pthread_create(&slp1, NULL, sleep1, (void*)bar3);
Mark Wielaard ebed60
   /* create a thread, whose only purpose is to block on the barrier */
Mark Wielaard ebed60
   pthread_create(&thr1, NULL, child1, (void*)bar3);
Mark Wielaard ebed60
   /* guarantee that it gets there first */
Mark Wielaard ebed60
@@ -61,6 +68,12 @@ int main ( void )
Mark Wielaard ebed60
   /* once again, create a thread, whose only purpose is to block. */
Mark Wielaard ebed60
   bar4 = malloc(sizeof(pthread_barrier_t));
Mark Wielaard ebed60
   pthread_barrier_init(bar4, NULL, 2);
Mark Wielaard ebed60
+  /* create a thread, whose purpose is to "unblock" the barrier after
Mark Wielaard ebed60
+     some sleeping in case it keeps being blocked. We hope it isn't
Mark Wielaard ebed60
+     needed, but if it is, because pthread_barier_destroy hangs
Mark Wielaard ebed60
+     and we will get an extra warning about the barrier being already
Mark Wielaard ebed60
+     destroyed. */
Mark Wielaard ebed60
+  pthread_create(&slp2, NULL, sleep1, (void*)bar4);
Mark Wielaard ebed60
   /* create a thread, whose only purpose is to block on the barrier */
Mark Wielaard ebed60
   pthread_create(&thr2, NULL, child1, (void*)bar4);
Mark Wielaard ebed60
   /* guarantee that it gets there first */
Mark Wielaard ebed60
@@ -70,13 +83,16 @@ int main ( void )
Mark Wielaard ebed60
 
Mark Wielaard ebed60
   /* destroy a barrier that was never initialised.  This is a bit
Mark Wielaard ebed60
      tricky, in that we have to fill the barrier with bytes which
Mark Wielaard ebed60
-     ensure that the pthread_barrier_destroy call doesn't hang for
Mark Wielaard ebed60
-     some reason.  Zero-fill seems to work ok on amd64-linux (glibc
Mark Wielaard ebed60
+     ensure that the pthread_barrier_destroy call doesn't crash for
Mark Wielaard ebed60
+     some reason.  One-fill seems to work ok on amd64-linux (glibc
Mark Wielaard ebed60
      2.8). */
Mark Wielaard ebed60
   fprintf(stderr, "\ndestroy a barrier that was never initialised\n");
Mark Wielaard ebed60
+  /* Create a thread that just exits the process after some sleep.
Mark Wielaard ebed60
+     We are really done at this point, even if we hang. */
Mark Wielaard ebed60
+  pthread_create(&ext1, NULL, exit1, NULL);
Mark Wielaard ebed60
   bar5 = malloc(sizeof(pthread_barrier_t));
Mark Wielaard ebed60
   assert(bar5);
Mark Wielaard ebed60
-  memset(bar5, 0, sizeof(*bar5));
Mark Wielaard ebed60
+  memset(bar5, 1, sizeof(*bar5));
Mark Wielaard ebed60
   pthread_barrier_destroy(bar5);
Mark Wielaard ebed60
 
Mark Wielaard ebed60
   /* now we need to clean up the mess .. */
Mark Wielaard ebed60
@@ -85,5 +101,6 @@ int main ( void )
Mark Wielaard ebed60
 
Mark Wielaard ebed60
   free(bar1); free(bar2); free(bar3); free(bar4); free(bar5);
Mark Wielaard ebed60
 
Mark Wielaard ebed60
-  return 0;
Mark Wielaard ebed60
+  /* Use exit, we want to kill any "sleeper threads". */
Mark Wielaard ebed60
+  exit (0);
Mark Wielaard ebed60
 }
Mark Wielaard ebed60
diff --git a/helgrind/tests/bar_bad.stderr.exp b/helgrind/tests/bar_bad.stderr.exp
Mark Wielaard ebed60
index 74af4fa..d0901b2 100644
Mark Wielaard ebed60
--- a/helgrind/tests/bar_bad.stderr.exp
Mark Wielaard ebed60
+++ b/helgrind/tests/bar_bad.stderr.exp
Mark Wielaard ebed60
@@ -8,14 +8,14 @@ Thread #x is the program's root thread
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: 'count' argument is zero
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:39)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:43)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 ----------------------------------------------------------------
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x's call to pthread_barrier_init failed
Mark Wielaard ebed60
    with error code 22 (EINVAL: Invalid argument)
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:39)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:43)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 initialise a barrier twice
Mark Wielaard ebed60
@@ -23,7 +23,7 @@ initialise a barrier twice
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: barrier is already initialised
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:45)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:49)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 initialise a barrier which has threads waiting on it
Mark Wielaard ebed60
@@ -31,13 +31,13 @@ initialise a barrier which has threads waiting on it
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: barrier is already initialised
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:57)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:64)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 ----------------------------------------------------------------
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: threads are waiting at barrier
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:57)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:64)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 destroy a barrier that has waiting threads
Mark Wielaard ebed60
@@ -45,14 +45,14 @@ destroy a barrier that has waiting threads
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_destroy: threads are waiting at barrier
Mark Wielaard ebed60
    at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:69)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:82)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 ----------------------------------------------------------------
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x's call to pthread_barrier_destroy failed
Mark Wielaard ebed60
    with error code 16 (EBUSY: Device or resource busy)
Mark Wielaard ebed60
    at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:69)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:82)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 destroy a barrier that was never initialised
Mark Wielaard ebed60
@@ -60,5 +60,5 @@ destroy a barrier that was never initialised
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_destroy: barrier was never initialised
Mark Wielaard ebed60
    at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:80)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:96)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
diff --git a/helgrind/tests/bar_bad.stderr.exp b/helgrind/tests/bar_bad.stderr.exp-destroy-hang
Mark Wielaard ebed60
similarity index 72%
Mark Wielaard ebed60
copy from helgrind/tests/bar_bad.stderr.exp
Mark Wielaard ebed60
copy to helgrind/tests/bar_bad.stderr.exp-destroy-hang
Mark Wielaard ebed60
index 74af4fa..ddf5624 100644
Mark Wielaard ebed60
--- a/helgrind/tests/bar_bad.stderr.exp
Mark Wielaard ebed60
+++ b/helgrind/tests/bar_bad.stderr.exp-destroy-hang
Mark Wielaard ebed60
@@ -8,14 +8,14 @@ Thread #x is the program's root thread
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: 'count' argument is zero
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:39)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:43)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 ----------------------------------------------------------------
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x's call to pthread_barrier_init failed
Mark Wielaard ebed60
    with error code 22 (EINVAL: Invalid argument)
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:39)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:43)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 initialise a barrier twice
Mark Wielaard ebed60
@@ -23,7 +23,7 @@ initialise a barrier twice
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: barrier is already initialised
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:45)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:49)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 initialise a barrier which has threads waiting on it
Mark Wielaard ebed60
@@ -31,13 +31,13 @@ initialise a barrier which has threads waiting on it
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: barrier is already initialised
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:57)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:64)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 ----------------------------------------------------------------
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_init: threads are waiting at barrier
Mark Wielaard ebed60
    at 0x........: pthread_barrier_init (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:57)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:64)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 destroy a barrier that has waiting threads
Mark Wielaard ebed60
@@ -45,14 +45,22 @@ destroy a barrier that has waiting threads
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_destroy: threads are waiting at barrier
Mark Wielaard ebed60
    at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:69)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:82)
Mark Wielaard ebed60
+
Mark Wielaard ebed60
+---Thread-Announcement------------------------------------------
Mark Wielaard ebed60
+
Mark Wielaard ebed60
+Thread #x was created
Mark Wielaard ebed60
+   ...
Mark Wielaard ebed60
+   by 0x........: pthread_create@* (hg_intercepts.c:...)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:76)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 ----------------------------------------------------------------
Mark Wielaard ebed60
 
Mark Wielaard ebed60
-Thread #x's call to pthread_barrier_destroy failed
Mark Wielaard ebed60
-   with error code 16 (EBUSY: Device or resource busy)
Mark Wielaard ebed60
-   at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:69)
Mark Wielaard ebed60
+Thread #x: pthread_barrier_wait: barrier is uninitialised
Mark Wielaard ebed60
+   at 0x........: pthread_barrier_wait (hg_intercepts.c:...)
Mark Wielaard ebed60
+   by 0x........: sleep1 (bar_bad.c:22)
Mark Wielaard ebed60
+   by 0x........: mythread_wrapper (hg_intercepts.c:...)
Mark Wielaard ebed60
+   ...
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 destroy a barrier that was never initialised
Mark Wielaard ebed60
@@ -60,5 +68,5 @@ destroy a barrier that was never initialised
Mark Wielaard ebed60
 
Mark Wielaard ebed60
 Thread #x: pthread_barrier_destroy: barrier was never initialised
Mark Wielaard ebed60
    at 0x........: pthread_barrier_destroy (hg_intercepts.c:...)
Mark Wielaard ebed60
-   by 0x........: main (bar_bad.c:80)
Mark Wielaard ebed60
+   by 0x........: main (bar_bad.c:96)
Mark Wielaard ebed60
 
Mark Wielaard ebed60
-- 
Mark Wielaard ebed60
1.8.3.1
Mark Wielaard ebed60