Browse Source

- fix a race condition between starpu_pthread_barrier_wait and starpu_pthread_barrier_destroy in the fall-back implementation

A thread A may call starpu_pthread_barrier_destroy while a thread B did not yet get a chance to run and exit the critical section after having been woken up. In that case, thread A may destroy the barrier's mutex and condition objects while they are still in use by B.
Olivier Aumage 10 years ago
parent
commit
4e714efbb7
2 changed files with 15 additions and 0 deletions
  1. 2 0
      include/starpu_thread.h
  2. 13 0
      src/common/thread.c

+ 2 - 0
include/starpu_thread.h

@@ -212,8 +212,10 @@ typedef int starpu_pthread_barrierattr_t;
 typedef struct {
 	starpu_pthread_mutex_t mutex;
 	starpu_pthread_cond_t cond;
+	starpu_pthread_cond_t cond_destroy;
 	unsigned count;
 	unsigned done;
+	unsigned busy;
 } starpu_pthread_barrier_t;
 typedef int starpu_pthread_barrierattr_t;
 #define STARPU_PTHREAD_BARRIER_SERIAL_THREAD -1

+ 13 - 0
src/common/thread.c

@@ -345,16 +345,26 @@ int starpu_pthread_barrier_init(starpu_pthread_barrier_t *restrict barrier, cons
 	int ret = starpu_pthread_mutex_init(&barrier->mutex, NULL);
 	if (!ret)
 		ret = starpu_pthread_cond_init(&barrier->cond, NULL);
+	if (!ret)
+		ret = starpu_pthread_cond_init(&barrier->cond_destroy, NULL);
 	barrier->count = count;
 	barrier->done = 0;
+	barrier->busy = 0;
 	return ret;
 }
 
 int starpu_pthread_barrier_destroy(starpu_pthread_barrier_t *barrier)
 {
+	starpu_pthread_mutex_lock(&barrier->mutex);
+	while (barrier->busy) {
+		starpu_pthread_cond_wait(&barrier->cond_destroy, &barrier->mutex);
+	}
+	starpu_pthread_mutex_unlock(&barrier->mutex);
 	int ret = starpu_pthread_mutex_destroy(&barrier->mutex);
 	if (!ret)
 		ret = starpu_pthread_cond_destroy(&barrier->cond);
+	if (!ret)
+		ret = starpu_pthread_cond_destroy(&barrier->cond_destroy);
 	return ret;
 }
 
@@ -373,7 +383,10 @@ int starpu_pthread_barrier_wait(starpu_pthread_barrier_t *barrier)
 	}
 	else
 	{
+		barrier->busy++;
 		starpu_pthread_cond_wait(&barrier->cond, &barrier->mutex);
+		barrier->busy--;
+		starpu_pthread_cond_broadcast(&barrier->cond_destroy);
 	}
 
 	starpu_pthread_mutex_unlock(&barrier->mutex);