blob: e7e58fce04cad3fd70f4b69893380742215d6454 [file] [log] [blame]
// (C) Copyright Christian Bienia 2007
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0.
//
// file : Barrier.cpp
// author : Christian Bienia - cbienia@cs.princeton.edu
// description : A barrier
#if defined(HAVE_CONFIG_H)
# include "config.h"
#endif
#if defined(HAVE_LIBPTHREAD)
# include <pthread.h>
# include <errno.h>
#else
# include "Mutex.h"
# include "Condition.h"
#endif //HAVE_LIBPTHREAD
#include <exception>
#include "Barrier.h"
namespace threads {
Barrier::Barrier(int _n) {
#if defined(HAVE_LIBPTHREAD)
int rv;
n = _n;
rv = pthread_barrier_init(&b, NULL, n);
switch(rv) {
case 0:
break;
case EINVAL:
case EBUSY:
{
BarrierInitException e;
throw e;
break;
}
case EAGAIN:
case ENOMEM:
{
BarrierResourceException e;
throw e;
break;
}
default:
{
BarrierUnknownException e;
throw e;
break;
}
}
#else
n = _n;
countSleep = 0;
countReset = 0;
M = new Mutex;
CSleep = new Condition(*M);
CReset = new Condition(*M);
#endif //HAVE_LIBPTHREAD
}
Barrier::~Barrier() {
#if defined(HAVE_LIBPTHREAD)
int rv;
rv = pthread_barrier_destroy(&b);
switch(rv) {
case 0:
break;
case EINVAL:
case EBUSY:
{
BarrierDestroyException e;
throw e;
break;
}
default:
{
BarrierUnknownException e;
throw e;
break;
}
}
#else
delete CReset;
delete CSleep;
delete M;
#endif //HAVE_LIBPTHREAD
}
//Wait at a barrier
bool Barrier::Wait() {
#if defined(HAVE_LIBPTHREAD)
int rv;
rv = pthread_barrier_wait(&b);
switch(rv) {
case 0:
break;
case PTHREAD_BARRIER_SERIAL_THREAD:
return true;
break;
case EINVAL:
{
BarrierException e;
throw e;
break;
}
default:
{
BarrierUnknownException e;
throw e;
break;
}
}
return false;
#else
bool master;
M->Lock();
//Make sure no more than n threads have entered the barrier yet, otherwise wait for reset
while(countSleep >= n) CReset->Wait();
//Enter barrier, pick a thread as master
master = (countSleep == 0);
countSleep++;
//Sleep until designated number of threads have entered barrier
if(countSleep < n) {
//Wait() must be free of spurious wakeups
CSleep->Wait();
} else {
countReset = 0; //prepare for synchronized reset
CSleep->NotifyAll();
}
//Leave barrier
countReset++;
//Wait until all threads have left barrier, then execute reset
if(countReset < n) {
//Wait() must be free of spurious wakeups
CReset->Wait();
} else {
countSleep = 0;
CReset->NotifyAll();
}
M->Unlock();
return master;
#endif //HAVE_LIBPTHREAD
}
const int Barrier::nThreads() const {
return n;
}
};