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