aboutsummaryrefslogtreecommitdiff
path: root/src/threading.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/threading.cpp')
-rw-r--r--src/threading.cpp300
1 files changed, 135 insertions, 165 deletions
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// #################################################################################################