diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-09 09:03:30 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-04-09 09:03:30 +0200 |
commit | 9b5c27af793a08fd17d1fde93e9512e76536f484 (patch) | |
tree | 15c063100e9ac122ed91cd746b5aaeffe8df89e8 /src | |
parent | 6efef88d0c7c155690dc2ac478d52e75da97d147 (diff) | |
download | lanes-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.cpp | 4 | ||||
-rw-r--r-- | src/threading.cpp | 300 | ||||
-rw-r--r-- | src/threading.h | 208 |
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) |
101 | static 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 | ||
160 | static int const gs_prio_remap[] = | 124 | static int const gs_prio_remap[] = |
@@ -170,12 +134,12 @@ static int const gs_prio_remap[] = | |||
170 | 134 | ||
171 | // ############################################################################################### | 135 | // ############################################################################################### |
172 | 136 | ||
173 | void THREAD_SET_PRIORITY( int prio) | 137 | void 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 | ||
195 | void THREAD_SET_AFFINITY(unsigned int aff) | 159 | void 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 | 173 | typedef 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) | 183 | void 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 | ||
224 | static 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 ) { | 235 | static 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 |
279 | static int const gs_prio_remap[] = | 251 | static 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 | ||
407 | void THREAD_SET_PRIORITY( int prio) | 371 | void 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) | |||
422 | void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_) | 386 | void 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 | ||
437 | void THREAD_SET_AFFINITY( unsigned int aff) | 401 | void 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 | 434 | void 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 ===--- | 19 | static 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 | 44 | static constexpr int THREAD_PRIO_MIN{ -3 }; |
43 | // | 45 | static 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) \ | 70 | extern 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 | } | 74 | static 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 | 78 | static constexpr int THREAD_PRIO_MIN{ -3 }; | |
106 | using THREAD_RETURN_T = void *; | 79 | static 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 | /* | 86 | void THREAD_SETNAME(char const* _name); |
169 | * Win32 and PTHREAD_TIMEDJOIN allow waiting for a thread with a timeout. | 87 | void THREAD_SET_PRIORITY(int prio); |
170 | * Posix without PTHREAD_TIMEDJOIN needs to use a condition variable approach. | 88 | void 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 | |||
182 | void THREAD_SETNAME( char const* _name); | ||
183 | void THREAD_SET_PRIORITY( int prio); | ||
184 | void THREAD_SET_AFFINITY( unsigned int aff); | ||
185 | 89 | ||
186 | void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_); | 90 | void JTHREAD_SET_PRIORITY(std::jthread& thread_, int prio_); |