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<--

Reply via email to