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