#include <errno.h>
#include <stdlib.h>
#include <pthread.h>
#include "rthread.h"
int
pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr,
unsigned int count) {
int rc = 0;
pthread_barrier_t b = NULL;
if (barrier == NULL)
return (EINVAL);
if (count == 0)
return (EINVAL);
if (attr != NULL) {
if (*attr == NULL)
return (EINVAL);
if ((*attr)->pshared != PTHREAD_PROCESS_PRIVATE)
return (ENOTSUP);
}
b = calloc(1, sizeof *b);
if (b == NULL)
return (ENOMEM);
if ((rc = pthread_mutex_init(&b->mutex, NULL)))
goto err;
if ((rc = pthread_cond_init(&b->cond, NULL)))
goto err;
b->threshold = count;
*barrier = b;
return (0);
err:
if (b) {
if (b->mutex)
pthread_mutex_destroy(&b->mutex);
if (b->cond)
pthread_cond_destroy(&b->cond);
free(b);
}
return (rc);
}
int
pthread_barrier_destroy(pthread_barrier_t *barrier)
{
int rc;
pthread_barrier_t b;
if (barrier == NULL || *barrier == NULL)
return (EINVAL);
if ((rc = pthread_mutex_lock(&(*barrier)->mutex)))
return (rc);
b = *barrier;
if (b->out > 0 || b->in > 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);
return (0);
}
int
pthread_barrier_wait(pthread_barrier_t *barrier)
{
pthread_barrier_t b;
int rc, old_state, gen;
int done = 0;
if (barrier == NULL || *barrier == NULL)
return (EINVAL);
if ((rc = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state)))
return (rc);
b = *barrier;
if ((rc = pthread_mutex_lock(&b->mutex)))
goto cancel;
_rthread_debug(6, "in: %d, threshold: %d\n", b->in, b->threshold);
if (++b->in == b->threshold) {
b->out = b->in - 1;
b->in = 0;
b->generation++;
if ((rc = pthread_cond_signal(&b->cond)))
goto err;
done = 1;
_rthread_debug(6, "threshold reached\n");
} else {
gen = b->generation;
_rthread_debug(6, "waiting on condition\n");
do {
if ((rc = pthread_cond_wait(&b->cond, &b->mutex)))
goto err;
} while (gen == b->generation);
b->out--;
if ((rc = pthread_cond_signal(&b->cond)))
goto err;
}
err:
if ((rc = pthread_mutex_unlock(&b->mutex)))
return (rc);
cancel:
rc = pthread_setcancelstate(old_state, NULL);
if (rc == 0 && done)
rc = PTHREAD_BARRIER_SERIAL_THREAD;
return (rc);
}