On Tue, Mar 15, 2016 at 12:51:45AM +0100, Tobias Ulmer wrote:
> On Thu, Mar 10, 2016 at 10:23:17PM +0000, Kári Tristan Helgason wrote:
> > I think I may have come across a race in the implementation of
> > `pthread_barrier_wait` in librthread.
I'm pretty tired but I think I know what you're talking about. Can you
try this diff?
We set 'sofar' to 0 first thing when the condition is met, allowing
threads to destroy a barrier that's still in use.
Index: rthread_barrier.c
===================================================================
RCS file: /home/vcs/cvs/openbsd/src/lib/librthread/rthread_barrier.c,v
retrieving revision 1.2
diff -u -p -r1.2 rthread_barrier.c
--- rthread_barrier.c 23 Apr 2012 08:30:33 -0000 1.2
+++ rthread_barrier.c 15 Mar 2016 01:10:25 -0000
@@ -70,16 +70,23 @@ int
pthread_barrier_destroy(pthread_barrier_t *barrier)
{
pthread_barrier_t b;
+ int rc;
if (barrier == NULL || *barrier == NULL)
return (EINVAL);
b = *barrier;
- if (b->sofar > 0)
+ if ((rc = pthread_mutex_trylock(&b->mutex)))
+ return rc;
+
+ if (b->sofar > 0) {
+ pthread_mutex_unlock(&b->mutex);
return (EBUSY);
+ }
*barrier = NULL;
+ pthread_mutex_unlock(&b->mutex);
pthread_mutex_destroy(&b->mutex);
pthread_cond_destroy(&b->cond);
free(b);
--8<--
/* modified test program */
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
pthread_barrier_t barrier;
void *threadfn(void *arg) {
int num = (int)arg;
fprintf(stderr, "Thread %d started\n", num);
srandom(num);
sleep(random() % 5 + 1);
pthread_barrier_wait(&barrier);
fprintf(stderr, "Thread %d ended\n", num);
}
int main(int argc, char *argv[]) {
int numThreads = 4;
int i, rc;
pthread_barrier_init(&barrier, NULL, numThreads+1);
pthread_t *thread = malloc(sizeof(pthread_t) * numThreads);
for(i = 0; i < numThreads; i++) {
pthread_create(&thread[i], NULL, threadfn, (void*)i);
}
fprintf(stderr, "Main thread done spawning threads\n");
pthread_barrier_wait(&barrier);
fprintf(stderr, "Main thread done waiting\n");
do {
rc = pthread_barrier_destroy(&barrier);
fprintf(stderr, "pthread_barrier_destroy returned %d\n", rc);
} while (rc != 0);
return 0;
}
--8<--