1 #ifdef DEPRECATED
2 #define thread__ thread_local
3 #endif
4 
5 #ifdef flagPROFILEMT
6 class Mutex;
7 class StaticMutex;
8 
9 struct MtInspector {
10 	const char *name;
11 	int   number;
12 	int   locked;
13 	int   blocked;
14 
15 	static MtInspector *Dumi();
16 
17 	MtInspector(const char *s, int n = -1) { name = s; number = n; locked = blocked = 0; }
18 	~MtInspector();
19 };
20 
21 #define PROFILEMT(mutex) \
22 	{ static MtInspector MK__s(__FILE__, __LINE__); mutex.Set(MK__s); }
23 
24 #define PROFILEMT_(mutex, id) \
25 	{ static MtInspector MK__s(id); mutex.Set(MK__s); }
26 
27 #else
28 
29 #define PROFILEMT(mutex)
30 #define PROFILEMT_(mutex, id)
31 
32 #endif
33 
34 template<typename Res, typename... ArgTypes>
35 class Function<Res(ArgTypes...)>;
36 
37 class Thread : NoCopy {
38 #ifdef PLATFORM_WIN32
39 	HANDLE     handle;
40 	DWORD	   thread_id;
41 #endif
42 #ifdef PLATFORM_POSIX
43 	pthread_t  handle;
44 #endif
45 public:
46 	bool       Run(Function<void ()> cb, bool noshutdown = false);
47 	bool       RunNice(Function<void ()> cb, bool noshutdown = false);
48 	bool       RunCritical(Function<void ()> cb, bool noshutdown = false);
49 
50 	void       Detach();
51 	int        Wait();
52 
IsOpen()53 	bool       IsOpen() const     { return handle; }
54 
55 #ifdef PLATFORM_WIN32
56 	typedef HANDLE Handle;
57 	typedef DWORD  Id;
58 
GetId()59 	Id          GetId() const                  { return thread_id; }
60 #endif
61 #ifdef PLATFORM_POSIX
62 	typedef pthread_t Handle;
63 	typedef pthread_t Id;
64 
GetId()65 	Id          GetId() const                  { return handle; }
66 #endif
67 
GetHandle()68 	Handle      GetHandle() const              { return handle; }
69 
70 	bool        Priority(int percent); // 0 = lowest, 100 = normal
71 
Nice()72 	void        Nice()                         { Priority(25); }
Critical()73 	void        Critical()                     { Priority(150); }
74 
75 	static void Start(Function<void ()> cb, bool noshutdown = false);
76 	static void StartNice(Function<void ()> cb, bool noshutdown = false);
77 	static void StartCritical(Function<void ()> cb, bool noshutdown = false);
78 
79 	static void Sleep(int ms);
80 
81 	static bool IsST();
82 	static bool IsMain();
83 	static int  GetCount();
84 	static void BeginShutdownThreads();
85 	static void EndShutdownThreads();
86 	static void ShutdownThreads();
87 	static bool IsShutdownThreads();
88 	static void (*AtExit(void (*exitfn)()))();
89 
90 	static void Exit();
91 
92 #ifdef PLATFORM_WIN32
GetCurrentHandle()93 	static Handle GetCurrentHandle()          { return GetCurrentThread(); }
GetCurrentId()94 	static inline Id GetCurrentId()           { return ::GetCurrentThreadId(); };
95 #endif
96 #ifdef PLATFORM_POSIX
GetCurrentHandle()97 	static Handle GetCurrentHandle()          { return pthread_self(); }
GetCurrentId()98 	static inline Id GetCurrentId()           { return pthread_self(); };
99 #endif
100 
101 	Thread();
102 	~Thread();
103 
104 private:
105 	void operator=(const Thread&);
106 	Thread(const Thread&);
107 };
108 
109 #ifdef _DEBUG
AssertST()110 inline void AssertST() { ASSERT(Thread::IsST()); }
111 #else
AssertST()112 inline void AssertST() {}
113 #endif
114 
115 
116 class Semaphore : NoCopy {
117 #ifdef PLATFORM_WIN32
118 	HANDLE     handle;
119 #elif PLATFORM_OSX
120 	dispatch_semaphore_t    sem;
121 #else
122 	sem_t      sem;
123 #endif
124 
125 public:
126 	bool       Wait(int timeout_ms = -1);
127 	void       Release();
128 #ifdef PLATFORM_WIN32
129 	void       Release(int n);
130 #endif
131 
132 	Semaphore();
133 	~Semaphore();
134 };
135 
136 struct MtInspector;
137 
138 #ifdef PLATFORM_WIN32
139 
140 class Mutex : NoCopy {
141 protected:
142 	CRITICAL_SECTION section;
143 	MtInspector        *mti;
144 
Mutex(int)145 	Mutex(int)         {}
146 
147 	friend class ConditionVariable;
148 
149 public:
150 	bool  TryEnter();
Leave()151 	void  Leave()                { LeaveCriticalSection(&section); }
152 
153 #ifdef flagPROFILEMT
Enter()154 	void  Enter()                { if(!TryEnter()) { mti->blocked++; EnterCriticalSection(&section); }; mti->locked++; }
Set(MtInspector & m)155 	void  Set(MtInspector& m)    { mti = &m; }
156 
Mutex()157 	Mutex()                      { mti = MtInspector::Dumi(); InitializeCriticalSection(&section); }
158 #else
Enter()159 	void  Enter()                { EnterCriticalSection(&section); }
160 
Mutex()161 	Mutex()                      { InitializeCriticalSection(&section); }
162 #endif
163 
~Mutex()164 	~Mutex()                     { DeleteCriticalSection(&section); }
165 
166 	class Lock;
167 };
168 
169 /* Win32 RWMutex implementation by Chris Thomasson, cristom@comcast.net */
170 
171 class RWMutex : NoCopy {
172     LONG   m_count, m_rdwake;
173     HANDLE m_wrwset, m_rdwset;
174     CRITICAL_SECTION m_wrlock;
175 
176 public:
177 	void EnterWrite();
178 	void LeaveWrite();
179 
180 	void EnterRead();
181 	void LeaveRead();
182 
183 	RWMutex();
184 	~RWMutex();
185 
186 	class ReadLock;
187 	class WriteLock;
188 };
189 
190 class ConditionVariable {
191 	static VOID (WINAPI *InitializeConditionVariable)(PCONDITION_VARIABLE ConditionVariable);
192 	static VOID (WINAPI *WakeConditionVariable)(PCONDITION_VARIABLE ConditionVariable);
193 	static VOID (WINAPI *WakeAllConditionVariable)(PCONDITION_VARIABLE ConditionVariable);
194 	static BOOL (WINAPI *SleepConditionVariableCS)(PCONDITION_VARIABLE ConditionVariable, PCRITICAL_SECTION CriticalSection, DWORD dwMilliseconds);
195 
196 	CONDITION_VARIABLE cv[1];
197 
198 	struct WaitingThread { // Windows XP does not provide ConditionVariable, implement using Semaphores
199 		Semaphore      sem;
200 		WaitingThread *next;
201 	};
202 	Mutex          mutex;
203 	WaitingThread *head, *tail;
204 
205 public:
206 	bool Wait(Mutex& m, int timeout_ms = -1);
207 	void Signal();
208 	void Broadcast();
209 
210 	ConditionVariable();
211 	~ConditionVariable();
212 };
213 
214 #endif
215 
216 #ifdef PLATFORM_POSIX
217 
218 class Mutex : NoCopy {
219 	pthread_mutex_t  mutex[1];
220 #ifdef flagPROFILEMT
221 	MtInspector     *mti;
222 #endif
223 	friend class ConditionVariable;
224 
225 public:
226 #ifdef flagPROFILEMT
TryEnter()227 	bool  TryEnter()          { bool b = pthread_mutex_trylock(mutex) == 0; mti->locked += b; return b; }
Enter()228 	void  Enter()             { if(pthread_mutex_trylock(mutex) != 0) { mti->blocked++; pthread_mutex_lock(mutex); } mti->locked++; }
Set(MtInspector & m)229 	void  Set(MtInspector& m) { mti = &m; }
230 #else
231 	bool  TryEnter()          { return pthread_mutex_trylock(mutex) == 0; }
232 	void  Enter()             { pthread_mutex_lock(mutex); }
233 #endif
Leave()234 	void  Leave()             { pthread_mutex_unlock(mutex); }
235 
236 	class Lock;
237 
238 	Mutex();
~Mutex()239 	~Mutex()           { pthread_mutex_destroy(mutex); }
240 };
241 
242 class RWMutex : NoCopy {
243 	pthread_rwlock_t rwlock[1];
244 
245 public:
EnterWrite()246 	void EnterWrite()  { pthread_rwlock_wrlock(rwlock); }
LeaveWrite()247 	void LeaveWrite()  { pthread_rwlock_unlock(rwlock); }
EnterRead()248 	void EnterRead()   { pthread_rwlock_rdlock(rwlock); }
LeaveRead()249 	void LeaveRead()   { pthread_rwlock_unlock(rwlock); }
250 
251 	RWMutex();
252 	~RWMutex();
253 
254 	class ReadLock;
255 	class WriteLock;
256 };
257 
258 class ConditionVariable {
259 	pthread_cond_t cv[1];
260 
261 public:
262 	bool Wait(Mutex& m, int timeout_ms = -1);
263 
Signal()264 	void Signal()        { pthread_cond_signal(cv); }
Broadcast()265 	void Broadcast()     { pthread_cond_broadcast(cv); }
266 
ConditionVariable()267 	ConditionVariable()  { pthread_cond_init(cv, NULL); }
~ConditionVariable()268 	~ConditionVariable() { pthread_cond_destroy(cv); }
269 };
270 
271 #endif
272 
273 typedef std::atomic<bool> OnceFlag;
274 
275 #define ONCELOCK_(o_b_) \
276 for(static ::Upp::Mutex o_ss_; !o_b_.load(std::memory_order_acquire);) \
277 	for(::Upp::Mutex::Lock o_ss_lock__(o_ss_); !o_b_.load(std::memory_order_acquire); o_b_.store(true, std::memory_order_release))
278 
279 #define ONCELOCK \
280 for(static ::Upp::OnceFlag o_b_; !o_b_.load(std::memory_order_acquire);) ONCELOCK_(o_b_)
281 
282 
283 class Mutex::Lock : NoCopy {
284 	Mutex& s;
285 
286 public:
Lock(Mutex & s)287 	Lock(Mutex& s) : s(s) { s.Enter(); }
~Lock()288 	~Lock()               { s.Leave(); }
289 };
290 
291 class RWMutex::ReadLock : NoCopy {
292 	RWMutex& s;
293 
294 public:
ReadLock(RWMutex & s)295 	ReadLock(RWMutex& s) : s(s) { s.EnterRead(); }
~ReadLock()296 	~ReadLock()                 { s.LeaveRead(); }
297 };
298 
299 class RWMutex::WriteLock : NoCopy {
300 	RWMutex& s;
301 
302 public:
WriteLock(RWMutex & s)303 	WriteLock(RWMutex& s) : s(s) { s.EnterWrite(); }
~WriteLock()304 	~WriteLock()                 { s.LeaveWrite(); }
305 };
306 
307 template <class Primitive>
308 class StaticPrimitive_ : NoCopy {
309 	Primitive *primitive;
310 	byte       buffer[sizeof(Primitive)];
311 	OnceFlag   once;
312 
Initialize()313 	void Initialize() { primitive = new(buffer) Primitive; }
314 
315 public:
Get()316 	Primitive& Get()  { ONCELOCK_(once) Initialize(); return *primitive; }
317 };
318 
319 class StaticMutex : StaticPrimitive_<Mutex> {
320 public:
321 	operator Mutex&()          { return Get(); }
TryEnter()322 	bool TryEnter()            { return Get().TryEnter();}
Enter()323 	void Enter()               { Get().Enter();}
Leave()324 	void Leave()               { Get().Leave(); }
325 #ifdef flagPROFILEMT
Set(MtInspector & mti)326 	void Set(MtInspector& mti) { Get().Set(mti); }
327 #endif
328 };
329 
330 class StaticSemaphore : StaticPrimitive_<Semaphore> {
331 public:
332 	operator Semaphore&()        { return Get(); }
Wait()333 	void Wait()                  { Get().Wait(); }
Release()334 	void Release()               { Get().Release(); }
335 };
336 
337 class StaticRWMutex : StaticPrimitive_<RWMutex> {
338 public:
339 	operator RWMutex&()  { return Get(); }
EnterRead()340 	void EnterRead()     { Get().EnterRead();}
LeaveRead()341 	void LeaveRead()     { Get().LeaveRead(); }
EnterWrite()342 	void EnterWrite()    { Get().EnterWrite();}
LeaveWrite()343 	void LeaveWrite()    { Get().LeaveWrite(); }
344 };
345 
346 class StaticConditionVariable : StaticPrimitive_<ConditionVariable> {
347 public:
348 	operator ConditionVariable&() { return Get(); }
Wait(Mutex & m)349 	void Wait(Mutex& m)  { Get().Wait(m); }
Signal()350 	void Signal()        { Get().Signal(); }
Broadcast()351 	void Broadcast()     { Get().Broadcast(); }
352 };
353 
354 class LazyUpdate {
355 	mutable Mutex              mutex;
356 	mutable std::atomic<bool>  dirty;
357 
358 public:
359 	void Invalidate();
360 	bool BeginUpdate() const;
361 	void EndUpdate() const;
362 
363 	LazyUpdate();
364 };
365 
IsMainThread()366 inline bool IsMainThread() { return Thread::IsMain(); }
367 
368 struct SpinLock : Moveable<SpinLock> {
369 #ifdef COMPILER_MSC
370 	volatile LONG locked;
371 
TryEnterSpinLock372 	bool TryEnter() { return InterlockedCompareExchange(&locked, 1, 0) == 0; }
LeaveSpinLock373 	void Leave()    { _ReadWriteBarrier(); locked = 0; }
374 #else
375 	volatile int locked;
376 
377 	bool TryEnter() { return  __sync_bool_compare_and_swap (&locked, 0, 1); }
378 	void Leave()    { __sync_lock_release(&locked); }
379 #endif
380 
EnterSpinLock381 	void Enter()    { while(!TryEnter()) Wait(); }
382 
383 	void Wait();
384 
385 	class Lock;
386 
SpinLockSpinLock387 	SpinLock()         { locked = 0; }
388 };
389 
390 class SpinLock::Lock : NoCopy {
391 	SpinLock& s;
392 
393 public:
Lock(SpinLock & s)394 	Lock(SpinLock& s) : s(s) { s.Enter(); }
~Lock()395 	~Lock()                  { s.Leave(); }
396 };
397 
398 #define INTERLOCKED \
399 for(bool i_b_ = true; i_b_;) \
400 	for(static UPP::Mutex i_ss_; i_b_;) \
401 		for(UPP::Mutex::Lock i_ss_lock__(i_ss_); i_b_; i_b_ = false)
402 
403 struct H_l_ : Mutex::Lock {
404 	bool b;
H_l_H_l_405 	H_l_(Mutex& cs) : Mutex::Lock(cs) { b = true; }
406 };
407 
408 #define INTERLOCKED_(cs) \
409 for(UPP::H_l_ i_ss_lock__(cs); i_ss_lock__.b; i_ss_lock__.b = false)
410 
411 #ifdef DEPRECATED
412 typedef Mutex CriticalSection;
413 typedef StaticMutex StaticCriticalSection;
414 #endif
415 
416 // Auxiliary multithreading - this is not using/cannot use U++ heap, so does not need cleanup.
417 // Used to resolve some host platform issues.
418 
419 #ifdef PLATFORM_WIN32
420 #define auxthread_t DWORD
421 #define auxthread__ WINAPI
422 #else
423 #define auxthread_t void *
424 #define auxthread__
425 #endif
426 
427 bool StartAuxThread(auxthread_t (auxthread__ *fn)(void *ptr), void *ptr);
428