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