aboutsummaryrefslogtreecommitdiff
path: root/src/threading.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/threading.h')
-rw-r--r--src/threading.h262
1 files changed, 43 insertions, 219 deletions
diff --git a/src/threading.h b/src/threading.h
index 38a021f..fc35730 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -1,25 +1,13 @@
1#pragma once 1#pragma once
2 2
3/*
4 * win32-pthread:
5 * define HAVE_WIN32_PTHREAD and PTW32_INCLUDE_WINDOWS_H in your project configuration when building for win32-pthread.
6 * link against pthreadVC2.lib, and of course have pthreadVC2.dll somewhere in your path.
7 */
8#include "platform.h" 3#include "platform.h"
9 4
10#include <time.h> 5#include <thread>
11
12/* Note: ERROR is a defined entity on Win32
13 PENDING: The Lua VM hasn't done anything yet.
14 RUNNING, WAITING: Thread is inside the Lua VM. If the thread is forcefully stopped, we can't lua_close() the Lua State.
15 DONE, ERROR_ST, CANCELLED: Thread execution is outside the Lua VM. It can be lua_close()d.
16*/
17enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
18 6
19#define THREADAPI_WINDOWS 1 7#define THREADAPI_WINDOWS 1
20#define THREADAPI_PTHREAD 2 8#define THREADAPI_PTHREAD 2
21 9
22#if( defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)) && !defined( HAVE_WIN32_PTHREAD) 10#if( defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC))
23//#pragma message ( "THREADAPI_WINDOWS" ) 11//#pragma message ( "THREADAPI_WINDOWS" )
24#define THREADAPI THREADAPI_WINDOWS 12#define THREADAPI THREADAPI_WINDOWS
25#else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 13#else // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
@@ -27,22 +15,24 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
27#define THREADAPI THREADAPI_PTHREAD 15#define THREADAPI THREADAPI_PTHREAD
28#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 16#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
29 17
30/*---=== Locks & Signals ===--- 18static constexpr int THREAD_PRIO_DEFAULT{ -999 };
31*/
32 19
20// ##################################################################################################
21// ##################################################################################################
33#if THREADAPI == THREADAPI_WINDOWS 22#if THREADAPI == THREADAPI_WINDOWS
34 #if defined( PLATFORM_XBOX) 23
35 #include <xtl.h> 24#if defined(PLATFORM_XBOX)
36 #else // !PLATFORM_XBOX 25#include <xtl.h>
37 #define WIN32_LEAN_AND_MEAN 26#else // !PLATFORM_XBOX
38 // CONDITION_VARIABLE needs version 0x0600+ 27#define WIN32_LEAN_AND_MEAN
39 // _WIN32_WINNT value is already defined by MinGW, but not by MSVC 28// CONDITION_VARIABLE needs version 0x0600+
40 #ifndef _WIN32_WINNT 29// _WIN32_WINNT value is already defined by MinGW, but not by MSVC
41 #define _WIN32_WINNT 0x0600 30#ifndef _WIN32_WINNT
42 #endif // _WIN32_WINNT 31#define _WIN32_WINNT 0x0600
43 #include <windows.h> 32#endif // _WIN32_WINNT
44 #endif // !PLATFORM_XBOX 33#include <windows.h>
45 #include <process.h> 34#endif // !PLATFORM_XBOX
35#include <process.h>
46 36
47/* 37/*
48#define XSTR(x) STR(x) 38#define XSTR(x) STR(x)
@@ -50,202 +40,36 @@ enum e_status { PENDING, RUNNING, WAITING, DONE, ERROR_ST, CANCELLED };
50#pragma message( "The value of _WIN32_WINNT: " XSTR(_WIN32_WINNT)) 40#pragma message( "The value of _WIN32_WINNT: " XSTR(_WIN32_WINNT))
51*/ 41*/
52 42
53 // MSDN: http://msdn2.microsoft.com/en-us/library/ms684254.aspx 43static constexpr int THREAD_PRIO_MIN{ -3 };
54 // 44static constexpr int THREAD_PRIO_MAX{ +3 };
55 // CRITICAL_SECTION can be used for simple code protection. Mutexes are
56 // needed for use with the SIGNAL system.
57 //
58
59 #if _WIN32_WINNT < 0x0600 // CONDITION_VARIABLE aren't available, use a signal
60
61 struct SIGNAL_T
62 {
63 CRITICAL_SECTION signalCS;
64 CRITICAL_SECTION countCS;
65 HANDLE waitEvent;
66 HANDLE waitDoneEvent;
67 LONG waitersCount;
68 };
69
70
71 #define MUTEX_T HANDLE
72 void MUTEX_INIT( MUTEX_T* ref);
73 void MUTEX_FREE( MUTEX_T* ref);
74 void MUTEX_LOCK( MUTEX_T* ref);
75 void MUTEX_UNLOCK( MUTEX_T* ref);
76
77 #else // CONDITION_VARIABLE are available, use them
78
79 #define SIGNAL_T CONDITION_VARIABLE
80 #define MUTEX_T CRITICAL_SECTION
81 #define MUTEX_INIT( ref) InitializeCriticalSection( ref)
82 #define MUTEX_FREE( ref) DeleteCriticalSection( ref)
83 #define MUTEX_LOCK( ref) EnterCriticalSection( ref)
84 #define MUTEX_UNLOCK( ref) LeaveCriticalSection( ref)
85
86 #endif // CONDITION_VARIABLE are available
87
88 #define MUTEX_RECURSIVE_INIT(ref) MUTEX_INIT(ref) /* always recursive in Win32 */
89
90 using THREAD_RETURN_T = unsigned int;
91 45
92 #define YIELD() Sleep(0) 46// ##################################################################################################
93 #define THREAD_CALLCONV __stdcall 47// ##################################################################################################
94#else // THREADAPI == THREADAPI_PTHREAD 48#else // THREADAPI == THREADAPI_PTHREAD
95 // PThread (Linux, OS X, ...) 49// ##################################################################################################
96 50// ##################################################################################################
97 // looks like some MinGW installations don't support PTW32_INCLUDE_WINDOWS_H, so let's include it ourselves, just in case
98 #if defined(PLATFORM_WIN32)
99 #include <windows.h>
100 #endif // PLATFORM_WIN32
101 #include <pthread.h>
102
103 #ifdef PLATFORM_LINUX
104 #if defined(__GLIBC__)
105 # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
106 #else
107 # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE
108 #endif
109 #else
110 /* OS X, ... */
111 # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE
112 #endif
113
114 #define MUTEX_T pthread_mutex_t
115 #define MUTEX_INIT(ref) pthread_mutex_init(ref, nullptr)
116 #define MUTEX_RECURSIVE_INIT(ref) \
117 { pthread_mutexattr_t a; pthread_mutexattr_init( &a ); \
118 pthread_mutexattr_settype( &a, _MUTEX_RECURSIVE ); \
119 pthread_mutex_init(ref,&a); pthread_mutexattr_destroy( &a ); \
120 }
121 #define MUTEX_FREE(ref) pthread_mutex_destroy(ref)
122 #define MUTEX_LOCK(ref) pthread_mutex_lock(ref)
123 #define MUTEX_UNLOCK(ref) pthread_mutex_unlock(ref)
124
125 using THREAD_RETURN_T = void *;
126
127 using SIGNAL_T = pthread_cond_t;
128
129 void SIGNAL_ONE( SIGNAL_T *ref );
130
131 // Yield is non-portable:
132 //
133 // OS X 10.4.8/9 has pthread_yield_np()
134 // Linux 2.4 has pthread_yield() if _GNU_SOURCE is #defined
135 // FreeBSD 6.2 has pthread_yield()
136 // ...
137 //
138 #if defined( PLATFORM_OSX)
139 #define YIELD() pthread_yield_np()
140 #else
141 #define YIELD() sched_yield()
142 #endif
143 #define THREAD_CALLCONV
144#endif //THREADAPI == THREADAPI_PTHREAD
145
146void SIGNAL_INIT( SIGNAL_T *ref );
147void SIGNAL_FREE( SIGNAL_T *ref );
148void SIGNAL_ALL( SIGNAL_T *ref );
149 51
150/* 52// PThread (Linux, OS X, ...)
151* 'time_d': <0.0 for no timeout
152* 0.0 for instant check
153* >0.0 absolute timeout in secs + ms
154*/
155using time_d = double;
156time_d now_secs(void);
157
158time_d SIGNAL_TIMEOUT_PREPARE( double rel_secs );
159
160bool SIGNAL_WAIT( SIGNAL_T *ref, MUTEX_T *mu, time_d timeout );
161
162
163/*---=== Threading ===---
164*/
165 53
166#define THREAD_PRIO_DEFAULT (-999) 54// looks like some MinGW installations don't support PTW32_INCLUDE_WINDOWS_H, so let's include it ourselves, just in case
55#if defined(PLATFORM_WIN32)
56#include <windows.h>
57#endif // PLATFORM_WIN32
58#include <pthread.h>
167 59
168#if THREADAPI == THREADAPI_WINDOWS 60#if defined(PLATFORM_LINUX) && !defined(LINUX_SCHED_RR)
169 61static constexpr int THREAD_PRIO_MIN{ 0 };
170 using THREAD_T = HANDLE; 62#else
171# define THREAD_ISNULL( _h) (_h == 0) 63static constexpr int THREAD_PRIO_MIN{ -3 };
172 void THREAD_CREATE( THREAD_T* ref, THREAD_RETURN_T (__stdcall *func)( void*), void* data, int prio /* -3..+3 */); 64#endif
65static constexpr int THREAD_PRIO_MAX{ +3 };
173 66
174# define THREAD_PRIO_MIN (-3) 67#endif // THREADAPI == THREADAPI_PTHREAD
175# define THREAD_PRIO_MAX (+3) 68// ##################################################################################################
69// ##################################################################################################
176 70
177# define THREAD_CLEANUP_PUSH( cb_, val_) 71void THREAD_SETNAME(char const* _name);
178# define THREAD_CLEANUP_POP( execute_) 72void THREAD_SET_PRIORITY(int prio_, bool sudo_);
179 73void THREAD_SET_AFFINITY(unsigned int aff);
180#else // THREADAPI == THREADAPI_PTHREAD
181 74
182 /* Platforms that have a timed 'pthread_join()' can get away with a simpler 75void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_, bool sudo_);
183 * implementation. Others will use a condition variable.
184 */
185# if defined __WINPTHREADS_VERSION
186//# define USE_PTHREAD_TIMEDJOIN
187# endif // __WINPTHREADS_VERSION
188
189# ifdef USE_PTHREAD_TIMEDJOIN
190# ifdef PLATFORM_OSX
191# error "No 'pthread_timedjoin()' on this system"
192# else
193 /* Linux, ... */
194# define PTHREAD_TIMEDJOIN pthread_timedjoin_np
195# endif
196# endif
197
198 using THREAD_T = pthread_t;
199# define THREAD_ISNULL( _h) 0 // pthread_t may be a structure: never 'null' by itself
200
201 void THREAD_CREATE( THREAD_T* ref, THREAD_RETURN_T (*func)( void*), void* data, int prio /* -3..+3 */);
202
203# if defined(PLATFORM_LINUX)
204 extern volatile bool sudo;
205# ifdef LINUX_SCHED_RR
206# define THREAD_PRIO_MIN (sudo ? -3 : 0)
207# else
208# define THREAD_PRIO_MIN (0)
209# endif
210# define THREAD_PRIO_MAX (sudo ? +3 : 0)
211# else
212# define THREAD_PRIO_MIN (-3)
213# define THREAD_PRIO_MAX (+3)
214# endif
215
216# if THREADWAIT_METHOD == THREADWAIT_CONDVAR
217# define THREAD_CLEANUP_PUSH( cb_, val_) pthread_cleanup_push( cb_, val_)
218# define THREAD_CLEANUP_POP( execute_) pthread_cleanup_pop( execute_)
219# else
220# define THREAD_CLEANUP_PUSH( cb_, val_) {
221# define THREAD_CLEANUP_POP( execute_) }
222# endif // THREADWAIT_METHOD == THREADWAIT_CONDVAR
223#endif // THREADAPI == THREADAPI_WINDOWS
224
225/*
226* Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout.
227* Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach.
228*/
229#define THREADWAIT_TIMEOUT 1
230#define THREADWAIT_CONDVAR 2
231
232#if THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
233#define THREADWAIT_METHOD THREADWAIT_TIMEOUT
234#else // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
235#define THREADWAIT_METHOD THREADWAIT_CONDVAR
236#endif // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
237
238
239#if THREADWAIT_METHOD == THREADWAIT_TIMEOUT
240bool THREAD_WAIT_IMPL( THREAD_T *ref, double secs);
241#define THREAD_WAIT( a, b, c, d, e) THREAD_WAIT_IMPL( a, b)
242#else // THREADWAIT_METHOD == THREADWAIT_CONDVAR
243bool THREAD_WAIT_IMPL( THREAD_T *ref, double secs, SIGNAL_T *signal_ref, MUTEX_T *mu_ref, volatile enum e_status *st_ref);
244#define THREAD_WAIT THREAD_WAIT_IMPL
245#endif // // THREADWAIT_METHOD == THREADWAIT_CONDVAR
246
247void THREAD_KILL( THREAD_T* ref);
248void THREAD_SETNAME( char const* _name);
249void THREAD_MAKE_ASYNCH_CANCELLABLE();
250void THREAD_SET_PRIORITY( int prio);
251void THREAD_SET_AFFINITY( unsigned int aff);