1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
|
/*
* Licensed under CLIFE license. See LICENCE.TXT
*
* Produced by: Jeff Lait
*
* CLIFE Development
*
* NAME: thread.h ( CLIFE, C++ )
*
* COMMENTS:
* Attempt at a threading class.
*/
#ifndef __thread_h__
#define __thread_h__
typedef void *(*THREADmainFunc)(void *);
class THREAD
{
public:
// We use this generator to return the system specific implementation.
static THREAD *alloc();
static int numProcessors();
// (Re)starts this, invoking the given function as the main
// thread program.
virtual void start(THREADmainFunc func, void *data) = 0;
// Blocks until this is done
virtual void join() = 0;
// Is this thread still processing?
bool isActive() const { return myActive; }
// Terminates this thread.
virtual void kill() = 0;
protected:
THREAD() { myActive = false; }
virtual ~THREAD() {}
void setActive(bool val) { myActive = val; }
// Blocks until the thread is ready to process.
virtual void waittillimready() = 0;
virtual void iamdonenow() = 0;
// Canonical main func for threads.
static void *wrapper(void *data);
// No public copying.
THREAD(const THREAD &) { }
THREAD &operator=(const THREAD &) { return *this; }
bool myActive;
THREADmainFunc myCB;
void *myCBData;
};
typedef int s32;
#ifdef LINUX
#include <pthread.h>
#ifdef iPOWDER
#include <libkern/OSAtomic.h>
inline s32
testandset(s32 *addr, s32 val)
{
// Not natively supported, sadly.
// Too lazy to build a lock. Yes this will bite me someday.
int result = *addr;
*addr = val;
return result;
}
inline s32
testandadd(s32 *addr, s32 val)
{
// This does not return the original value, but that is
// what our code expects.
return OSAtomicAdd32(val, addr) - val;
}
#else
// Requires GCC 4.1 ++
// Consider this punishment for 4.3's behaviour with enums.
inline s32
testandset(s32 *addr, s32 val)
{
return __sync_lock_test_and_set(addr, val);
}
inline s32
testandadd(s32 *addr, s32 val)
{
return __sync_fetch_and_add(addr, val);
}
#endif
#else
#define _THREAD_SAFE
#define _WIN32_WINNT 0x0400
#include <windows.h>
#include <intrin.h>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
#pragma intrinsic (_InterlockedExchange)
#pragma intrinsic (_InterlockedExchangeAdd)
inline s32
testandset(s32 *addr, s32 val)
{
return (s32)_InterlockedExchange((long *)addr, (long)val);
}
inline s32
testandadd(s32 *addr, s32 val)
{
return (s32)_InterlockedExchangeAdd((long *)addr, (long)val);
}
#endif
class ATOMIC_INT32
{
public:
explicit ATOMIC_INT32(s32 value = 0) : myValue(value) {}
// Swap this and val
inline s32 exchange(s32 val)
{
return testandset(&myValue, val);
}
// Add val to this, return the old value.
inline s32 exchangeAdd(s32 val)
{
return testandadd(&myValue, val);
}
// Add val to this, return new value.
inline s32 add(s32 val)
{
return testandadd(&myValue, val) + val;
}
// Set self to maximum of self and val
inline s32 maximum(s32 val)
{
s32 peek = exchange(val);
while (peek > val)
{
val = peek;
peek = exchange(val);
}
return peek;
}
void set(s32 val) { myValue = val; }
operator s32() const { return myValue; }
private:
s32 myValue;
ATOMIC_INT32(const ATOMIC_INT32 &) {}
ATOMIC_INT32 &operator=(const ATOMIC_INT32 &) { return *this; }
};
class LOCK
{
public:
LOCK();
~LOCK();
// Non blocking attempt at the lock, returns true if now locked.
bool tryToLock();
void lock();
void unlock();
bool isLocked();
protected:
LOCK(const LOCK &) {}
LOCK &operator=(const LOCK &) { return *this; }
#ifdef LINUX
pthread_mutex_t myLock;
pthread_mutexattr_t myLockAttr;
#else
CRITICAL_SECTION *myLock;
#endif
friend class CONDITION;
};
class AUTOLOCK
{
public:
AUTOLOCK(LOCK &lock) : myLock(lock) { myLock.lock(); }
~AUTOLOCK() { myLock.unlock(); }
protected:
LOCK &myLock;
};
class CONDITION
{
public:
CONDITION();
~CONDITION();
// Lock is currently set. We will unlock it, block, then
// when condition is triggered relock it and return.
void wait(LOCK &lock);
// Trigger, allowing one thread through.
// Caller should currently have the wait lock.
void trigger();
private:
CONDITION(const CONDITION &) {}
CONDITION &operator=(const CONDITION &) { return *this; }
#ifdef LINUX
pthread_cond_t myCond;
#else
ATOMIC_INT32 myNumWaiting;
HANDLE myEvent;
#endif
};
#endif
|