/* This file is part of Jellyfish.
Jellyfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jellyfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jellyfish. If not, see .
*/
#ifndef __JELLYFISH_LOCKS_PTHREAD_HPP__
#define __JELLYFISH_LOCKS_PTHREAD_HPP__
#include
#include
#include
#ifdef HAVE_CONFIG_H
#include
#endif
namespace jellyfish { namespace locks{ namespace pthread {
class cond
{
pthread_mutex_t _mutex;
pthread_cond_t _cond;
public:
cond() {
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_cond, NULL);
}
~cond() {
pthread_cond_destroy(&_cond);
pthread_mutex_destroy(&_mutex);
}
inline void lock() { pthread_mutex_lock(&_mutex); }
inline void unlock() { pthread_mutex_unlock(&_mutex); }
inline void wait() { pthread_cond_wait(&_cond, &_mutex); }
inline void signal() { pthread_cond_signal(&_cond); }
inline void broadcast() { pthread_cond_broadcast(&_cond); }
inline int timedwait(struct timespec *abstime) {
return pthread_cond_timedwait(&_cond, &_mutex, abstime);
}
inline int timedwait(time_t seconds) {
struct timespec curtime;
#ifdef HAVE_CLOCK_GETTIME
clock_gettime(CLOCK_REALTIME, &curtime);
#else
struct timeval timeofday;
gettimeofday(&timeofday, 0);
curtime.tv_sec = timeofday.tv_sec;
curtime.tv_nsec = timeofday.tv_usec * 1000;
#endif
curtime.tv_sec += seconds;
return timedwait(&curtime);
}
};
class mutex {
pthread_mutex_t _mutex;
public:
mutex(int type = PTHREAD_MUTEX_DEFAULT) {
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, type);
pthread_mutex_init(&_mutex, &attr);
}
~mutex() {
pthread_mutex_destroy(&_mutex);
}
inline void lock() { pthread_mutex_lock(&_mutex); }
inline void unlock() { pthread_mutex_unlock(&_mutex); }
inline bool try_lock() { return !pthread_mutex_trylock(&_mutex); }
};
class mutex_recursive : public mutex {
public:
mutex_recursive() : mutex(PTHREAD_MUTEX_RECURSIVE) { }
};
class mutex_lock {
mutex& m_;
public:
explicit mutex_lock(mutex& m) : m_(m) { m_.lock(); }
~mutex_lock() { m_.unlock(); }
};
class Semaphore {
int _value, _wakeups;
cond _cv;
public:
explicit Semaphore(int value) :
_value(value),
_wakeups(0)
{
// nothing to do
}
~Semaphore() {}
inline void wait() {
_cv.lock();
_value--;
if (_value < 0) {
do {
_cv.wait();
} while(_wakeups < 1);
_wakeups--;
}
_cv.unlock();
}
inline void signal() {
_cv.lock();
_value++;
if(_value <= 0) {
_wakeups++;
_cv.signal();
}
_cv.unlock();
}
};
#if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS - 20012L) >= 0
class barrier
{
pthread_barrier_t _barrier;
public:
explicit barrier(unsigned count) {
pthread_barrier_init(&_barrier, NULL, count);
}
~barrier() {
pthread_barrier_destroy(&_barrier);
}
/// Return true if serial thread.
inline bool wait() {
return pthread_barrier_wait(&_barrier) == PTHREAD_BARRIER_SERIAL_THREAD;
}
};
#else
// # ifndef PTHREAD_BARRIER_SERIAL_THREAD
// # define PTHREAD_BARRIER_SERIAL_THREAD 1
// # endif
class barrier
{
int count; // required # of threads
int current; // current # of threads that have passed thru
mutex barlock; // protect current
Semaphore barrier1; // implement the barrier
Semaphore barrier2;
public:
explicit barrier(unsigned cnt)
: count(cnt), current(0), barrier1(0), barrier2(0) {
}
~barrier() {}
inline bool wait() {
bool ret = false;
barlock.lock();
current += 1;
if(current == count) {
ret = true;
for(int i=0; i