#ifndef _H_THREADING
#define _H_THREADING
#include <security_utilities/utilities.h>
#include <security_utilities/errors.h>
#include <security_utilities/debugging.h>
# include <pthread.h>
#include <security_utilities/threading_internal.h>
namespace Security {
#if defined(NDEBUG) || defined(THREAD_CLEAN_NDEBUG)
# if !defined(THREAD_NDEBUG)
# define THREAD_NDEBUG
# endif
#endif
class ThreadStoreSlot {
public:
typedef void Destructor(void *);
ThreadStoreSlot(Destructor *destructor = NULL);
~ThreadStoreSlot();
void *get() const { return pthread_getspecific(mKey); }
operator void * () const { return get(); }
void operator = (void *value) const
{
if (int err = pthread_setspecific(mKey, value))
UnixError::throwMe(err);
}
private:
pthread_key_t mKey;
};
template <class T>
class PerThreadPointer : public ThreadStoreSlot {
public:
PerThreadPointer(bool cleanup = true) : ThreadStoreSlot(cleanup ? destructor : NULL) { }
operator bool() const { return get() != NULL; }
operator T * () const { return reinterpret_cast<T *>(get()); }
T *operator -> () const { return static_cast<T *>(*this); }
T &operator * () const { return *static_cast<T *>(get()); }
void operator = (T *t) { ThreadStoreSlot::operator = (t); }
private:
static void destructor(void *element)
{ delete reinterpret_cast<T *>(element); }
};
class LockingPrimitive {
protected:
LockingPrimitive() { }
void check(int err) { if (err) UnixError::throwMe(err); }
};
class Mutex : public LockingPrimitive {
NOCOPY(Mutex)
friend class Condition;
public:
enum Type {
normal,
recursive
};
Mutex(); Mutex(Type type); ~Mutex(); void lock(); bool tryLock(); void unlock();
private:
pthread_mutex_t me;
};
class RecursiveMutex : public Mutex
{
public:
RecursiveMutex() : Mutex(recursive) {}
~RecursiveMutex() {}
};
class NormalMutex : public Mutex
{
public:
NormalMutex() : Mutex(normal) {}
~NormalMutex() {}
};
class Condition : public LockingPrimitive {
NOCOPY(Condition)
public:
Condition(Mutex &mutex); ~Condition();
void wait(); void signal(); void broadcast();
Mutex &mutex;
private:
pthread_cond_t me;
};
class CountingMutex : public Mutex {
public:
CountingMutex() : mCount(0) { }
~CountingMutex() { assert(mCount == 0); }
void enter(); bool tryEnter(); void exit();
unsigned int count() const { return mCount; }
bool isIdle() const { return mCount == 0; }
void finishEnter(); void finishExit();
private:
unsigned int mCount; };
class ReadWriteLock : public Mutex {
public:
ReadWriteLock();
~ReadWriteLock() { check(pthread_rwlock_destroy(&mLock)); }
bool lock();
bool tryLock();
void unlock();
bool writeLock();
bool tryWriteLock();
private:
pthread_rwlock_t mLock;
};
template <class Lock,
void (Lock::*_lock)() = &Lock::lock,
void (Lock::*_unlock)() = &Lock::unlock>
class StLock {
public:
StLock(Lock &lck) : me(lck) { (me.*_lock)(); mActive = true; }
StLock(Lock &lck, bool option) : me(lck), mActive(option) { }
~StLock() { if (mActive) (me.*_unlock)(); }
bool isActive() const { return mActive; }
void lock() { if(!mActive) { (me.*_lock)(); mActive = true; }}
void unlock() { if(mActive) { (me.*_unlock)(); mActive = false; }}
void release() { assert(mActive); mActive = false; }
operator const Lock &() const { return me; }
protected:
Lock &me;
bool mActive;
};
template <class Lock,
void (Lock::*_lock)() = &Lock::lock,
void (Lock::*_unlock)() = &Lock::unlock>
class StMaybeLock {
public:
StMaybeLock(Lock *lck) : me(lck), mActive(false)
{ if(me) { (me->*_lock)(); mActive = true; } }
StMaybeLock(Lock *lck, bool option) : me(lck), mActive(option) { }
~StMaybeLock() { if (me) { if(mActive) (me->*_unlock)(); } else {mActive = false;} }
bool isActive() const { return mActive; }
void lock() { if(me) { if(!mActive) { (me->*_lock)(); mActive = true; }}}
void unlock() { if(me) { if(mActive) { (me->*_unlock)(); mActive = false; }}}
void release() { if(me) { assert(mActive); mActive = false; } }
operator const Lock &() const { return me; }
protected:
Lock *me;
bool mActive;
};
class StReadWriteLock {
public:
enum Type {
Read,
TryRead,
Write,
TryWrite
};
StReadWriteLock(ReadWriteLock &lck, Type type) : mType(type), mIsLocked(false), mRWLock(lck)
{ lock(); }
~StReadWriteLock() { if(mIsLocked) unlock(); }
bool lock();
void unlock();
bool isLocked();
protected:
Type mType;
bool mIsLocked;
ReadWriteLock& mRWLock;
};
template <class TakeLock, class ReleaseLock,
void (TakeLock::*_lock)() = &TakeLock::lock,
void (TakeLock::*_unlock)() = &TakeLock::unlock,
void (ReleaseLock::*_rlock)() = &ReleaseLock::lock,
void (ReleaseLock::*_runlock)() = &ReleaseLock::unlock>
class StSyncLock {
public:
StSyncLock(TakeLock &tlck, ReleaseLock &rlck) : taken(tlck), released(rlck) {
(released.*_unlock)();
(taken.*_lock)();
mActive = true;
}
StSyncLock(TakeLock &tlck, ReleaseLock &rlck, bool option) : taken(tlck), released(rlck), mActive(option) { }
~StSyncLock() { if (mActive) { (taken.*_unlock)(); (released.*_rlock)(); }}
bool isActive() const { return mActive; }
void lock() { if(!mActive) { (released.*_runlock)(); (taken.*_lock)(); mActive = true; }}
void unlock() { if(mActive) { (taken.*_unlock)(); (released.*_rlock)(); mActive = false; }}
void release() { assert(mActive); mActive = false; }
protected:
TakeLock &taken;
ReleaseLock &released;
bool mActive;
};
template <class Integer = uint32_t>
class StaticAtomicCounter {
protected:
Integer mValue;
public:
operator Integer() const { return mValue; }
Integer operator ++ () { return Atomic<Integer>::increment(mValue); }
Integer operator -- () { return Atomic<Integer>::decrement(mValue); }
Integer operator ++ (int) { return Atomic<Integer>::increment(mValue) - 1; }
Integer operator -- (int) { return Atomic<Integer>::decrement(mValue) + 1; }
Integer operator += (int delta) { return Atomic<Integer>::add(delta, mValue); }
};
template <class Integer = int>
class AtomicCounter : public StaticAtomicCounter<Integer> {
public:
AtomicCounter(Integer init = 0) { StaticAtomicCounter<Integer>::mValue = init; }
};
class Thread {
NOCOPY(Thread)
public:
Thread() { } virtual ~Thread(); void run();
public:
static void yield();
protected:
virtual void action() = 0;
private:
static void *runner(void *); };
class ThreadRunner : public Thread {
typedef void Action();
public:
ThreadRunner(Action *todo);
private:
void action();
Action *mAction;
};
}
#endif //_H_THREADING