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_); |
