aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-04-09 09:03:30 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-04-09 09:03:30 +0200
commit9b5c27af793a08fd17d1fde93e9512e76536f484 (patch)
tree15c063100e9ac122ed91cd746b5aaeffe8df89e8 /src
parent6efef88d0c7c155690dc2ac478d52e75da97d147 (diff)
downloadlanes-9b5c27af793a08fd17d1fde93e9512e76536f484.tar.gz
lanes-9b5c27af793a08fd17d1fde93e9512e76536f484.tar.bz2
lanes-9b5c27af793a08fd17d1fde93e9512e76536f484.zip
C++ migration: YIELD() → std::this_thread::yield. plus more threading code cleanup
Diffstat (limited to 'src')
-rw-r--r--src/lanes.cpp4
-rw-r--r--src/threading.cpp300
-rw-r--r--src/threading.h208
3 files changed, 193 insertions, 319 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 12cd7ef..f5d5130 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -502,7 +502,7 @@ static int universe_gc( lua_State* L)
502 while (U->selfdestruct_first != SELFDESTRUCT_END) 502 while (U->selfdestruct_first != SELFDESTRUCT_END)
503 { 503 {
504 // give threads time to act on their cancel 504 // give threads time to act on their cancel
505 YIELD(); 505 std::this_thread::yield();
506 // count the number of cancelled thread that didn't have the time to act yet 506 // count the number of cancelled thread that didn't have the time to act yet
507 int n{ 0 }; 507 int n{ 0 };
508 { 508 {
@@ -529,7 +529,7 @@ static int universe_gc( lua_State* L)
529 // They are no longer listed in the selfdestruct chain, but they still have to lua_close(). 529 // They are no longer listed in the selfdestruct chain, but they still have to lua_close().
530 while (U->selfdestructing_count.load(std::memory_order_acquire) > 0) 530 while (U->selfdestructing_count.load(std::memory_order_acquire) > 0)
531 { 531 {
532 YIELD(); 532 std::this_thread::yield();
533 } 533 }
534 } 534 }
535 535
diff --git a/src/threading.cpp b/src/threading.cpp
index bc1852f..aab2fa7 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -97,64 +97,28 @@ THE SOFTWARE.
97* FAIL is for unexpected API return values - essentially programming 97* FAIL is for unexpected API return values - essentially programming
98* error in _this_ code. 98* error in _this_ code.
99*/ 99*/
100#if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) 100#if defined(PLATFORM_XBOX) || defined(PLATFORM_WIN32) || defined(PLATFORM_POCKETPC)
101static void FAIL( char const* funcname, int rc) 101 static void FAIL(char const* funcname, int rc)
102{ 102 {
103#if defined( PLATFORM_XBOX) 103#if defined(PLATFORM_XBOX)
104 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); 104 fprintf(stderr, "%s() failed! (%d)\n", funcname, rc);
105#else // PLATFORM_XBOX 105#else // PLATFORM_XBOX
106 char buf[256]; 106 char buf[256];
107 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, nullptr); 107 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, nullptr);
108 fprintf( stderr, "%s() failed! [GetLastError() -> %d] '%s'", funcname, rc, buf); 108 fprintf(stderr, "%s() failed! [GetLastError() -> %d] '%s'", funcname, rc, buf);
109#endif // PLATFORM_XBOX 109#endif // PLATFORM_XBOX
110#ifdef _MSC_VER 110#ifdef _MSC_VER
111 __debugbreak(); // give a chance to the debugger! 111 __debugbreak(); // give a chance to the debugger!
112#endif // _MSC_VER 112#endif // _MSC_VER
113 abort(); 113 abort();
114} 114 }
115#endif // win32 build 115#endif // win32 build
116 116
117 117
118/*---=== Threading ===---*/ 118/*---=== Threading ===---*/
119 119
120//--- 120// ##################################################################################################
121// It may be meaningful to explicitly limit the new threads' C stack size. 121// ##################################################################################################
122// We should know how much Lua needs in the C stack, all Lua side allocations
123// are done in heap so they don't count.
124//
125// Consequence of _not_ limiting the stack is running out of virtual memory
126// with 1000-5000 threads on 32-bit systems.
127//
128// Note: using external C modules may be affected by the stack size check.
129// if having problems, set back to '0' (default stack size of the system).
130//
131// Win32: 64K (?)
132// Win64: xxx
133//
134// Linux x86: 2MB Ubuntu 7.04 via 'pthread_getstacksize()'
135// Linux x64: xxx
136// Linux ARM: xxx
137//
138// OS X 10.4.9: 512K <http://developer.apple.com/qa/qa2005/qa1419.html>
139// valid values N * 4KB
140//
141#ifndef _THREAD_STACK_SIZE
142# if defined( PLATFORM_XBOX) || defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC) || defined( PLATFORM_CYGWIN)
143# define _THREAD_STACK_SIZE 0
144 // Win32: does it work with less?
145# elif (defined PLATFORM_OSX)
146# define _THREAD_STACK_SIZE (524288/2) // 262144
147 // OS X: "make test" works on 65536 and even below
148 // "make perftest" works on >= 4*65536 == 262144 (not 3*65536)
149# elif (defined PLATFORM_LINUX) && (defined __i386)
150# define _THREAD_STACK_SIZE (2097152/16) // 131072
151 // Linux x86 (Ubuntu 7.04): "make perftest" works on /16 (not on /32)
152# elif (defined PLATFORM_BSD) && (defined __i386)
153# define _THREAD_STACK_SIZE (1048576/8) // 131072
154 // FreeBSD 6.2 SMP i386: ("gmake perftest" works on /8 (not on /16)
155# endif
156#endif
157
158#if THREADAPI == THREADAPI_WINDOWS 122#if THREADAPI == THREADAPI_WINDOWS
159 123
160static int const gs_prio_remap[] = 124static int const gs_prio_remap[] =
@@ -170,12 +134,12 @@ static int const gs_prio_remap[] =
170 134
171// ############################################################################################### 135// ###############################################################################################
172 136
173void THREAD_SET_PRIORITY( int prio) 137void THREAD_SET_PRIORITY(int prio)
174{ 138{
175 // prio range [-3,+3] was checked by the caller 139 // prio range [-3,+3] was checked by the caller
176 if (!SetThreadPriority( GetCurrentThread(), gs_prio_remap[prio + 3])) 140 if (!SetThreadPriority(GetCurrentThread(), gs_prio_remap[prio + 3]))
177 { 141 {
178 FAIL( "THREAD_SET_PRIORITY", GetLastError()); 142 FAIL("THREAD_SET_PRIORITY", GetLastError());
179 } 143 }
180} 144}
181 145
@@ -194,86 +158,94 @@ void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_)
194 158
195void THREAD_SET_AFFINITY(unsigned int aff) 159void THREAD_SET_AFFINITY(unsigned int aff)
196{ 160{
197 if( !SetThreadAffinityMask( GetCurrentThread(), aff)) 161 if (!SetThreadAffinityMask(GetCurrentThread(), aff))
198 { 162 {
199 FAIL( "THREAD_SET_AFFINITY", GetLastError()); 163 FAIL("THREAD_SET_AFFINITY", GetLastError());
200 } 164 }
201} 165}
202 166
167// ###############################################################################################
168
203#if !defined __GNUC__ 169#if !defined __GNUC__
204 //see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx 170//see http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
205 #define MS_VC_EXCEPTION 0x406D1388 171#define MS_VC_EXCEPTION 0x406D1388
206 #pragma pack(push,8) 172#pragma pack(push,8)
207 typedef struct tagTHREADNAME_INFO 173typedef struct tagTHREADNAME_INFO
208 { 174{
209 DWORD dwType; // Must be 0x1000. 175 DWORD dwType; // Must be 0x1000.
210 LPCSTR szName; // Pointer to name (in user addr space). 176 LPCSTR szName; // Pointer to name (in user addr space).
211 DWORD dwThreadID; // Thread ID (-1=caller thread). 177 DWORD dwThreadID; // Thread ID (-1=caller thread).
212 DWORD dwFlags; // Reserved for future use, must be zero. 178 DWORD dwFlags; // Reserved for future use, must be zero.
213 } THREADNAME_INFO; 179} THREADNAME_INFO;
214 #pragma pack(pop) 180#pragma pack(pop)
215#endif // !__GNUC__ 181#endif // !__GNUC__
216 182
217 void THREAD_SETNAME( char const* _name) 183void THREAD_SETNAME(char const* _name)
218 { 184{
219#if !defined __GNUC__ 185#if !defined __GNUC__
220 THREADNAME_INFO info; 186 THREADNAME_INFO info;
221 info.dwType = 0x1000; 187 info.dwType = 0x1000;
222 info.szName = _name; 188 info.szName = _name;
223 info.dwThreadID = GetCurrentThreadId(); 189 info.dwThreadID = GetCurrentThreadId();
224 info.dwFlags = 0; 190 info.dwFlags = 0;
225 191
226 __try 192 __try
227 { 193 {
228 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); 194 RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
229 }
230 __except(EXCEPTION_EXECUTE_HANDLER)
231 {
232 }
233#endif // !__GNUC__
234 } 195 }
196 __except(EXCEPTION_EXECUTE_HANDLER)
197 {
198 }
199#endif // !__GNUC__
200}
235 201
202// ##################################################################################################
203// ##################################################################################################
236#else // THREADAPI == THREADAPI_PTHREAD 204#else // THREADAPI == THREADAPI_PTHREAD
237 // PThread (Linux, OS X, ...) 205// ##################################################################################################
238 // 206// ##################################################################################################
239 // On OS X, user processes seem to be able to change priorities. 207
240 // On Linux, SCHED_RR and su privileges are required.. !-( 208// PThread (Linux, OS X, ...)
241 // 209//
242 #include <errno.h> 210// On OS X, user processes seem to be able to change priorities.
243 #include <sched.h> 211// On Linux, SCHED_RR and su privileges are required.. !-(
244 212//
245# if (defined(__MINGW32__) || defined(__MINGW64__)) && defined pthread_attr_setschedpolicy 213#include <errno.h>
246# if pthread_attr_setschedpolicy( A, S) == ENOTSUP 214#include <sched.h>
247 // from the mingw-w64 team: 215
248 // Well, we support pthread_setschedparam by which you can specify 216#if (defined(__MINGW32__) || defined(__MINGW64__)) && defined pthread_attr_setschedpolicy
249 // threading-policy. Nevertheless, yes we lack this function. In 217#if pthread_attr_setschedpolicy(A, S) == ENOTSUP
250 // general its implementation is pretty much trivial, as on Win32 target 218// from the mingw-w64 team:
251 // just SCHED_OTHER can be supported. 219// Well, we support pthread_setschedparam by which you can specify
252 #undef pthread_attr_setschedpolicy 220// threading-policy. Nevertheless, yes we lack this function. In
253 static int pthread_attr_setschedpolicy( pthread_attr_t* attr, int policy) 221// general its implementation is pretty much trivial, as on Win32 target
222// just SCHED_OTHER can be supported.
223#undef pthread_attr_setschedpolicy
224static int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy)
225{
226 if (policy != SCHED_OTHER)
254 { 227 {
255 if( policy != SCHED_OTHER) 228 return ENOTSUP;
256 {
257 return ENOTSUP;
258 }
259 return 0;
260 } 229 }
261# endif // pthread_attr_setschedpolicy() 230 return 0;
262# endif // defined(__MINGW32__) || defined(__MINGW64__) 231}
232#endif // pthread_attr_setschedpolicy()
233#endif // defined(__MINGW32__) || defined(__MINGW64__)
263 234
264 static void _PT_FAIL( int rc, const char *name, const char *file, int line ) { 235static void _PT_FAIL( int rc, const char *name, const char *file, int line )
236{
265 const char *why= (rc==EINVAL) ? "EINVAL" : 237 const char *why= (rc==EINVAL) ? "EINVAL" :
266 (rc==EBUSY) ? "EBUSY" : 238 (rc==EBUSY) ? "EBUSY" :
267 (rc==EPERM) ? "EPERM" : 239 (rc==EPERM) ? "EPERM" :
268 (rc==ENOMEM) ? "ENOMEM" : 240 (rc==ENOMEM) ? "ENOMEM" :
269 (rc==ESRCH) ? "ESRCH" : 241 (rc==ESRCH) ? "ESRCH" :
270 (rc==ENOTSUP) ? "ENOTSUP": 242 (rc==ENOTSUP) ? "ENOTSUP":
271 //... 243 //...
272 "<UNKNOWN>"; 244 "<UNKNOWN>";
273 fprintf( stderr, "%s %d: %s failed, %d %s\n", file, line, name, rc, why ); 245 fprintf( stderr, "%s %d: %s failed, %d %s\n", file, line, name, rc, why );
274 abort(); 246 abort();
275 } 247}
276 #define PT_CALL( call ) { int rc= call; if (rc!=0) _PT_FAIL( rc, #call, __FILE__, __LINE__ ); } 248#define PT_CALL( call ) { int rc= call; if (rc!=0) _PT_FAIL( rc, #call, __FILE__, __LINE__ ); }
277 249
278// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range 250// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range
279static int const gs_prio_remap[] = 251static int const gs_prio_remap[] =
@@ -376,14 +348,6 @@ static int const gs_prio_remap[] =
376 // 348 //
377 // TBD: Find right values for Cygwin 349 // TBD: Find right values for Cygwin
378 // 350 //
379# elif defined( PLATFORM_WIN32) || defined( PLATFORM_POCKETPC)
380 // any other value not supported by win32-pthread as of version 2.9.1
381# define _PRIO_MODE SCHED_OTHER
382
383 // PTHREAD_SCOPE_PROCESS not supported by win32-pthread as of version 2.9.1
384 //#define _PRIO_SCOPE PTHREAD_SCOPE_SYSTEM // but do we need this at all to start with?
385 THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL
386
387# else 351# else
388# error "Unknown OS: not implemented!" 352# error "Unknown OS: not implemented!"
389# endif 353# endif
@@ -404,17 +368,17 @@ static int select_prio(int prio /* -3..+3 */)
404 return gs_prio_remap[prio + 3]; 368 return gs_prio_remap[prio + 3];
405} 369}
406 370
407void THREAD_SET_PRIORITY( int prio) 371void THREAD_SET_PRIORITY(int prio)
408{ 372{
409#ifdef PLATFORM_LINUX 373#ifdef PLATFORM_LINUX
410 if( sudo) // only root-privileged process can change priorities 374 if (!sudo) // only root-privileged process can change priorities
375 return;
411#endif // PLATFORM_LINUX 376#endif // PLATFORM_LINUX
412 { 377
413 struct sched_param sp; 378 struct sched_param sp;
414 // prio range [-3,+3] was checked by the caller 379 // prio range [-3,+3] was checked by the caller
415 sp.sched_priority = gs_prio_remap[ prio + 3]; 380 sp.sched_priority = gs_prio_remap[prio + 3];
416 PT_CALL( pthread_setschedparam( pthread_self(), _PRIO_MODE, &sp)); 381 PT_CALL(pthread_setschedparam(pthread_self(), _PRIO_MODE, &sp));
417 }
418} 382}
419 383
420// ################################################################################################# 384// #################################################################################################
@@ -422,69 +386,75 @@ void THREAD_SET_PRIORITY( int prio)
422void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_) 386void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_)
423{ 387{
424#ifdef PLATFORM_LINUX 388#ifdef PLATFORM_LINUX
425 if (sudo) // only root-privileged process can change priorities 389 if (!sudo) // only root-privileged process can change priorities
390 return;
426#endif // PLATFORM_LINUX 391#endif // PLATFORM_LINUX
427 { 392
428 struct sched_param sp; 393 struct sched_param sp;
429 // prio range [-3,+3] was checked by the caller 394 // prio range [-3,+3] was checked by the caller
430 sp.sched_priority = gs_prio_remap[prio_ + 3]; 395 sp.sched_priority = gs_prio_remap[prio_ + 3];
431 PT_CALL(pthread_setschedparam(static_cast<pthread_t>(thread_.native_handle()), _PRIO_MODE, &sp)); 396 PT_CALL(pthread_setschedparam(static_cast<pthread_t>(thread_.native_handle()), _PRIO_MODE, &sp));
432 }
433} 397}
434 398
435// ################################################################################################# 399// #################################################################################################
436 400
437void THREAD_SET_AFFINITY( unsigned int aff) 401void THREAD_SET_AFFINITY(unsigned int aff)
438{ 402{
439 int bit = 0; 403 int bit = 0;
440#ifdef __NetBSD__ 404#ifdef __NetBSD__
441 cpuset_t *cpuset = cpuset_create(); 405 cpuset_t* cpuset = cpuset_create();
442 if (cpuset == nullptr) 406 if (cpuset == nullptr)
443 _PT_FAIL( errno, "cpuset_create", __FILE__, __LINE__-2 ); 407 _PT_FAIL(errno, "cpuset_create", __FILE__, __LINE__ - 2);
444#define CPU_SET(b, s) cpuset_set(b, *(s)) 408#define CPU_SET(b, s) cpuset_set(b, *(s))
445#else 409#else
446 cpu_set_t cpuset; 410 cpu_set_t cpuset;
447 CPU_ZERO( &cpuset); 411 CPU_ZERO(&cpuset);
448#endif 412#endif
449 while( aff != 0) 413 while (aff != 0)
450 { 414 {
451 if( aff & 1) 415 if (aff & 1)
452 { 416 {
453 CPU_SET( bit, &cpuset); 417 CPU_SET(bit, &cpuset);
454 } 418 }
455 ++ bit; 419 ++bit;
456 aff >>= 1; 420 aff >>= 1;
457 } 421 }
458#ifdef __ANDROID__ 422#ifdef __ANDROID__
459 PT_CALL( sched_setaffinity( pthread_self(), sizeof(cpu_set_t), &cpuset)); 423 PT_CALL(sched_setaffinity(pthread_self(), sizeof(cpu_set_t), &cpuset));
460#elif defined(__NetBSD__) 424#elif defined(__NetBSD__)
461 PT_CALL( pthread_setaffinity_np( pthread_self(), cpuset_size(cpuset), cpuset)); 425 PT_CALL(pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset), cpuset));
462 cpuset_destroy( cpuset); 426 cpuset_destroy(cpuset);
463#else 427#else
464 PT_CALL( pthread_setaffinity_np( pthread_self(), sizeof(cpu_set_t), &cpuset)); 428 PT_CALL(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset));
465#endif 429#endif
466} 430}
467 431
468 void THREAD_SETNAME( char const* _name) 432// #################################################################################################
469 { 433
470 // exact API to set the thread name is platform-dependant 434void THREAD_SETNAME(char const* _name)
471 // if you need to fix the build, or if you know how to fill a hole, tell me (bnt.germain@gmail.com) so that I can submit the fix in github. 435{
436 // exact API to set the thread name is platform-dependant
437 // if you need to fix the build, or if you know how to fill a hole, tell me (bnt.germain@gmail.com) so that I can submit the fix in github.
472#if defined PLATFORM_BSD && !defined __NetBSD__ 438#if defined PLATFORM_BSD && !defined __NetBSD__
473 pthread_set_name_np( pthread_self(), _name); 439 pthread_set_name_np(pthread_self(), _name);
474#elif defined PLATFORM_BSD && defined __NetBSD__ 440#elif defined PLATFORM_BSD && defined __NetBSD__
475 pthread_setname_np( pthread_self(), "%s", (void *)_name); 441 pthread_setname_np(pthread_self(), "%s", (void*) _name);
476#elif defined PLATFORM_LINUX 442#elif defined PLATFORM_LINUX
477 #if LINUX_USE_PTHREAD_SETNAME_NP 443#if LINUX_USE_PTHREAD_SETNAME_NP
478 pthread_setname_np( pthread_self(), _name); 444 pthread_setname_np(pthread_self(), _name);
479 #else // LINUX_USE_PTHREAD_SETNAME_NP 445#else // LINUX_USE_PTHREAD_SETNAME_NP
480 prctl(PR_SET_NAME, _name, 0, 0, 0); 446 prctl(PR_SET_NAME, _name, 0, 0, 0);
481 #endif // LINUX_USE_PTHREAD_SETNAME_NP 447#endif // LINUX_USE_PTHREAD_SETNAME_NP
482#elif defined PLATFORM_QNX || defined PLATFORM_CYGWIN 448#elif defined PLATFORM_QNX || defined PLATFORM_CYGWIN
483 pthread_setname_np( pthread_self(), _name); 449 pthread_setname_np(pthread_self(), _name);
484#elif defined PLATFORM_OSX 450#elif defined PLATFORM_OSX
485 pthread_setname_np(_name); 451 pthread_setname_np(_name);
486#elif defined PLATFORM_WIN32 || defined PLATFORM_POCKETPC 452#else
487 PT_CALL( pthread_setname_np( pthread_self(), _name)); 453 fprintf(stderr, "THREAD_SETNAME: unsupported platform\n");
454 abort();
488#endif 455#endif
489 } 456}
457
490#endif // THREADAPI == THREADAPI_PTHREAD 458#endif // THREADAPI == THREADAPI_PTHREAD
459// #################################################################################################
460// #################################################################################################
diff --git a/src/threading.h b/src/threading.h
index 82c8f52..c443c82 100644
--- a/src/threading.h
+++ b/src/threading.h
@@ -16,22 +16,24 @@
16#define THREADAPI THREADAPI_PTHREAD 16#define THREADAPI THREADAPI_PTHREAD
17#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 17#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
18 18
19/*---=== Locks & Signals ===--- 19static constexpr int THREAD_PRIO_DEFAULT{ -999 };
20*/
21 20
21// ##################################################################################################
22// ##################################################################################################
22#if THREADAPI == THREADAPI_WINDOWS 23#if THREADAPI == THREADAPI_WINDOWS
23 #if defined( PLATFORM_XBOX) 24
24 #include <xtl.h> 25#if defined(PLATFORM_XBOX)
25 #else // !PLATFORM_XBOX 26#include <xtl.h>
26 #define WIN32_LEAN_AND_MEAN 27#else // !PLATFORM_XBOX
27 // CONDITION_VARIABLE needs version 0x0600+ 28#define WIN32_LEAN_AND_MEAN
28 // _WIN32_WINNT value is already defined by MinGW, but not by MSVC 29// CONDITION_VARIABLE needs version 0x0600+
29 #ifndef _WIN32_WINNT 30// _WIN32_WINNT value is already defined by MinGW, but not by MSVC
30 #define _WIN32_WINNT 0x0600 31#ifndef _WIN32_WINNT
31 #endif // _WIN32_WINNT 32#define _WIN32_WINNT 0x0600
32 #include <windows.h> 33#endif // _WIN32_WINNT
33 #endif // !PLATFORM_XBOX 34#include <windows.h>
34 #include <process.h> 35#endif // !PLATFORM_XBOX
36#include <process.h>
35 37
36/* 38/*
37#define XSTR(x) STR(x) 39#define XSTR(x) STR(x)
@@ -39,148 +41,50 @@
39#pragma message( "The value of _WIN32_WINNT: " XSTR(_WIN32_WINNT)) 41#pragma message( "The value of _WIN32_WINNT: " XSTR(_WIN32_WINNT))
40*/ 42*/
41 43
42 // MSDN: http://msdn2.microsoft.com/en-us/library/ms684254.aspx 44static constexpr int THREAD_PRIO_MIN{ -3 };
43 // 45static constexpr int THREAD_PRIO_MAX{ +3 };
44 // CRITICAL_SECTION can be used for simple code protection. Mutexes are
45 // needed for use with the SIGNAL system.
46 //
47
48 #if _WIN32_WINNT < 0x0600 // CONDITION_VARIABLE aren't available, use a signal
49
50 struct SIGNAL_T
51 {
52 CRITICAL_SECTION signalCS;
53 CRITICAL_SECTION countCS;
54 HANDLE waitEvent;
55 HANDLE waitDoneEvent;
56 LONG waitersCount;
57 };
58
59
60 #else // CONDITION_VARIABLE are available, use them
61 46
62 #define SIGNAL_T CONDITION_VARIABLE 47// ##################################################################################################
63 #define MUTEX_INIT( ref) InitializeCriticalSection( ref) 48// ##################################################################################################
64 #define MUTEX_FREE( ref) DeleteCriticalSection( ref)
65 #define MUTEX_LOCK( ref) EnterCriticalSection( ref)
66 #define MUTEX_UNLOCK( ref) LeaveCriticalSection( ref)
67
68 #endif // CONDITION_VARIABLE are available
69
70 #define MUTEX_RECURSIVE_INIT(ref) MUTEX_INIT(ref) /* always recursive in Win32 */
71
72 using THREAD_RETURN_T = unsigned int;
73
74 #define YIELD() Sleep(0)
75 #define THREAD_CALLCONV __stdcall
76#else // THREADAPI == THREADAPI_PTHREAD 49#else // THREADAPI == THREADAPI_PTHREAD
77 // PThread (Linux, OS X, ...) 50// ##################################################################################################
78 51// ##################################################################################################
79 // looks like some MinGW installations don't support PTW32_INCLUDE_WINDOWS_H, so let's include it ourselves, just in case 52
80 #if defined(PLATFORM_WIN32) 53// PThread (Linux, OS X, ...)
81 #include <windows.h> 54
82 #endif // PLATFORM_WIN32 55// looks like some MinGW installations don't support PTW32_INCLUDE_WINDOWS_H, so let's include it ourselves, just in case
83 #include <pthread.h> 56#if defined(PLATFORM_WIN32)
84 57#include <windows.h>
85 #ifdef PLATFORM_LINUX 58#endif // PLATFORM_WIN32
86 #if defined(__GLIBC__) 59#include <pthread.h>
87 # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP 60
88 #else 61// Yield is non-portable:
89 # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE 62//
90 #endif 63// OS X 10.4.8/9 has pthread_yield_np()
91 #else 64// Linux 2.4 has pthread_yield() if _GNU_SOURCE is #defined
92 /* OS X, ... */ 65// FreeBSD 6.2 has pthread_yield()
93 # define _MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE 66// ...
94 #endif 67//
95 68
96 #define MUTEX_INIT(ref) pthread_mutex_init(ref, nullptr) 69#if defined(PLATFORM_LINUX)
97 #define MUTEX_RECURSIVE_INIT(ref) \ 70extern volatile bool sudo;
98 { pthread_mutexattr_t a; pthread_mutexattr_init( &a ); \ 71# ifdef LINUX_SCHED_RR
99 pthread_mutexattr_settype( &a, _MUTEX_RECURSIVE ); \ 72# define THREAD_PRIO_MIN (sudo ? -3 : 0)
100 pthread_mutex_init(ref,&a); pthread_mutexattr_destroy( &a ); \ 73# else
101 } 74static constexpr int THREAD_PRIO_MIN{ 0 };
102 #define MUTEX_FREE(ref) pthread_mutex_destroy(ref) 75#endif
103 #define MUTEX_LOCK(ref) pthread_mutex_lock(ref) 76# define THREAD_PRIO_MAX (sudo ? +3 : 0)
104 #define MUTEX_UNLOCK(ref) pthread_mutex_unlock(ref) 77#else
105 78static constexpr int THREAD_PRIO_MIN{ -3 };
106 using THREAD_RETURN_T = void *; 79static constexpr int THREAD_PRIO_MAX{ +3 };
107 80#endif
108 using SIGNAL_T = pthread_cond_t;
109
110 // Yield is non-portable:
111 //
112 // OS X 10.4.8/9 has pthread_yield_np()
113 // Linux 2.4 has pthread_yield() if _GNU_SOURCE is #defined
114 // FreeBSD 6.2 has pthread_yield()
115 // ...
116 //
117 #if defined( PLATFORM_OSX)
118 #define YIELD() pthread_yield_np()
119 #else
120 #define YIELD() sched_yield()
121 #endif
122 #define THREAD_CALLCONV
123#endif //THREADAPI == THREADAPI_PTHREAD
124
125/*---=== Threading ===---
126*/
127
128#define THREAD_PRIO_DEFAULT (-999)
129
130#if THREADAPI == THREADAPI_WINDOWS
131
132# define THREAD_PRIO_MIN (-3)
133# define THREAD_PRIO_MAX (+3)
134
135#else // THREADAPI == THREADAPI_PTHREAD
136
137 /* Platforms that have a timed 'pthread_join()' can get away with a simpler
138 * implementation. Others will use a condition variable.
139 */
140# if defined __WINPTHREADS_VERSION
141//# define USE_PTHREAD_TIMEDJOIN
142# endif // __WINPTHREADS_VERSION
143
144# ifdef USE_PTHREAD_TIMEDJOIN
145# ifdef PLATFORM_OSX
146# error "No 'pthread_timedjoin()' on this system"
147# else
148 /* Linux, ... */
149# define PTHREAD_TIMEDJOIN pthread_timedjoin_np
150# endif
151# endif
152
153# if defined(PLATFORM_LINUX)
154 extern volatile bool sudo;
155# ifdef LINUX_SCHED_RR
156# define THREAD_PRIO_MIN (sudo ? -3 : 0)
157# else
158# define THREAD_PRIO_MIN (0)
159# endif
160# define THREAD_PRIO_MAX (sudo ? +3 : 0)
161# else
162# define THREAD_PRIO_MIN (-3)
163# define THREAD_PRIO_MAX (+3)
164# endif
165 81
166#endif // THREADAPI == THREADAPI_WINDOWS 82#endif // THREADAPI == THREADAPI_WINDOWS
83// ##################################################################################################
84// ##################################################################################################
167 85
168/* 86void THREAD_SETNAME(char const* _name);
169* Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout. 87void THREAD_SET_PRIORITY(int prio);
170* Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach. 88void THREAD_SET_AFFINITY(unsigned int aff);
171*/
172#define THREADWAIT_TIMEOUT 1
173#define THREADWAIT_CONDVAR 2
174
175#if THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
176#define THREADWAIT_METHOD THREADWAIT_TIMEOUT
177#else // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
178#define THREADWAIT_METHOD THREADWAIT_CONDVAR
179#endif // THREADAPI == THREADAPI_WINDOWS || (defined PTHREAD_TIMEDJOIN)
180
181
182void THREAD_SETNAME( char const* _name);
183void THREAD_SET_PRIORITY( int prio);
184void THREAD_SET_AFFINITY( unsigned int aff);
185 89
186void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_); 90void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_);