aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lane.cpp4
-rw-r--r--src/lane.hpp2
-rw-r--r--src/lanes.cpp62
-rw-r--r--src/lanes.lua42
-rw-r--r--src/threading.cpp146
-rw-r--r--src/threading.hpp14
-rw-r--r--src/universe.hpp5
7 files changed, 175 insertions, 100 deletions
diff --git a/src/lane.cpp b/src/lane.cpp
index 26ddebd..65a776e 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -1169,11 +1169,11 @@ void Lane::securizeDebugName(lua_State* const L_)
1169 1169
1170// ################################################################################################# 1170// #################################################################################################
1171 1171
1172void Lane::startThread(int const priority_) 1172void Lane::startThread(lua_State* const L_, int const priority_, NativePrioFlag native_)
1173{ 1173{
1174 thread = std::thread([this]() { lane_main(this); }); 1174 thread = std::thread([this]() { lane_main(this); });
1175 if (priority_ != kThreadPrioDefault) { 1175 if (priority_ != kThreadPrioDefault) {
1176 THREAD_SET_PRIORITY(thread, priority_, U->sudo); 1176 THREAD_SET_PRIORITY(L_, thread, priority_, native_, U->sudo);
1177 } 1177 }
1178} 1178}
1179 1179
diff --git a/src/lane.hpp b/src/lane.hpp
index 5fe36b6..917606f 100644
--- a/src/lane.hpp
+++ b/src/lane.hpp
@@ -204,7 +204,7 @@ class Lane final
204 [[nodiscard]] 204 [[nodiscard]]
205 bool selfdestructRemove(); 205 bool selfdestructRemove();
206 void securizeDebugName(lua_State* L_); 206 void securizeDebugName(lua_State* L_);
207 void startThread(int priority_); 207 void startThread(lua_State* L_, int priority_, NativePrioFlag native_);
208 void storeDebugName( std::string_view const& name_); 208 void storeDebugName( std::string_view const& name_);
209 [[nodiscard]] 209 [[nodiscard]]
210 int storeResults(lua_State* L_); 210 int storeResults(lua_State* L_);
diff --git a/src/lanes.cpp b/src/lanes.cpp
index d1a353b..0eaeb3e 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -137,13 +137,15 @@ LUAG_FUNC(set_singlethreaded)
137LUAG_FUNC(set_thread_priority) 137LUAG_FUNC(set_thread_priority)
138{ 138{
139 lua_Integer const _prio{ luaL_checkinteger(L_, 1) }; 139 lua_Integer const _prio{ luaL_checkinteger(L_, 1) };
140 NativePrioFlag const _native{ std::string_view{ "native" } == luaL_optstring(L_, 2, "mapped") };
140 // public Lanes API accepts a generic range -3/+3 141 // public Lanes API accepts a generic range -3/+3
141 // that will be remapped into the platform-specific scheduler priority scheme 142 // that will be remapped into the platform-specific scheduler priority scheme
142 // On some platforms, -3 is equivalent to -2 and +3 to +2 143 // On some platforms, -3 is equivalent to -2 and +3 to +2
143 if (_prio < kThreadPrioMin || _prio > kThreadPrioMax) { 144 if (!_native && (_prio < kThreadPrioMin || _prio > kThreadPrioMax)) {
144 raise_luaL_error(L_, "priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _prio); 145 raise_luaL_error(L_, "priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _prio);
145 } 146 }
146 THREAD_SET_PRIORITY(static_cast<int>(_prio), Universe::Get(L_)->sudo); 147
148 THREAD_SET_PRIORITY(L_, static_cast<int>(_prio), _native, Universe::Get(L_)->sudo);
147 return 0; 149 return 0;
148} 150}
149 151
@@ -155,7 +157,8 @@ LUAG_FUNC(set_thread_affinity)
155 if (_affinity <= 0) { 157 if (_affinity <= 0) {
156 raise_luaL_error(L_, "invalid affinity (%d)", _affinity); 158 raise_luaL_error(L_, "invalid affinity (%d)", _affinity);
157 } 159 }
158 THREAD_SET_AFFINITY(static_cast<unsigned int>(_affinity)); 160
161 THREAD_SET_AFFINITY(L_, static_cast<unsigned int>(_affinity));
159 return 0; 162 return 0;
160} 163}
161 164
@@ -236,9 +239,26 @@ int lanes_register(lua_State* const L_)
236 239
237// ################################################################################################# 240// #################################################################################################
238 241
242LUAG_FUNC(thread_priority_range)
243{
244 NativePrioFlag const _native{ std::string_view{ "native" } == luaL_optstring(L_, 1, "mapped") };
245 if (_native) {
246 auto const [_prio_min, _prio_max] = THREAD_NATIVE_PRIOS();
247 lua_pushinteger(L_, _prio_min);
248 lua_pushinteger(L_, _prio_max);
249 } else {
250 lua_pushinteger(L_, kThreadPrioMin);
251 lua_pushinteger(L_, kThreadPrioMax);
252 }
253 return 2;
254}
255
256// #################################################################################################
257
239//--- [] means can be nil 258//--- [] means can be nil
240// lane_ud = lane_new( function 259// lane_ud = lane_new( function
241// , [libs_str] 260// , [libs_str]
261// , [prio_is_native_bool]
242// , [priority_int] 262// , [priority_int]
243// , [globals_tbl] 263// , [globals_tbl]
244// , [package_tbl] 264// , [package_tbl]
@@ -255,15 +275,16 @@ LUAG_FUNC(lane_new)
255{ 275{
256 static constexpr StackIndex kFuncIdx{ 1 }; 276 static constexpr StackIndex kFuncIdx{ 1 };
257 static constexpr StackIndex kLibsIdx{ 2 }; 277 static constexpr StackIndex kLibsIdx{ 2 };
258 static constexpr StackIndex kPrioIdx{ 3 }; 278 static constexpr StackIndex kPrinIdx{ 3 };
259 static constexpr StackIndex kGlobIdx{ 4 }; 279 static constexpr StackIndex kPrioIdx{ 4 };
260 static constexpr StackIndex kPackIdx{ 5 }; 280 static constexpr StackIndex kGlobIdx{ 5 };
261 static constexpr StackIndex kRequIdx{ 6 }; 281 static constexpr StackIndex kPackIdx{ 6 };
262 static constexpr StackIndex kGcCbIdx{ 7 }; 282 static constexpr StackIndex kRequIdx{ 7 };
263 static constexpr StackIndex kNameIdx{ 8 }; 283 static constexpr StackIndex kGcCbIdx{ 8 };
264 static constexpr StackIndex kErTlIdx{ 9 }; 284 static constexpr StackIndex kNameIdx{ 9 };
265 static constexpr StackIndex kAsCoro{ 10 }; 285 static constexpr StackIndex kErTlIdx{ 10 };
266 static constexpr StackIndex kFixedArgsIdx{ 10 }; 286 static constexpr StackIndex kAsCoro{ 11 };
287 static constexpr StackIndex kFixedArgsIdx{ 11 };
267 288
268 int const _nargs{ lua_gettop(L_) - kFixedArgsIdx }; 289 int const _nargs{ lua_gettop(L_) - kFixedArgsIdx };
269 LUA_ASSERT(L_, _nargs >= 0); 290 LUA_ASSERT(L_, _nargs >= 0);
@@ -400,21 +421,22 @@ LUAG_FUNC(lane_new)
400 // public Lanes API accepts a generic range -3/+3 421 // public Lanes API accepts a generic range -3/+3
401 // that will be remapped into the platform-specific scheduler priority scheme 422 // that will be remapped into the platform-specific scheduler priority scheme
402 // On some platforms, -3 is equivalent to -2 and +3 to +2 423 // On some platforms, -3 is equivalent to -2 and +3 to +2
403 int const _priority{ 424 auto const [_priority, _native] {
404 std::invoke([L = L_]() { 425 std::invoke([L = L_]() {
426 NativePrioFlag const _native{ static_cast<bool>(lua_toboolean(L, kPrinIdx)) };
405 StackIndex const _prio_idx{ lua_isnoneornil(L, kPrioIdx) ? kIdxNone : kPrioIdx }; 427 StackIndex const _prio_idx{ lua_isnoneornil(L, kPrioIdx) ? kIdxNone : kPrioIdx };
406 if (_prio_idx == 0) { 428 if (_prio_idx == kIdxNone) {
407 return kThreadPrioDefault; 429 return std::make_pair(kThreadPrioDefault, _native);
408 } 430 }
409 int const _priority{ static_cast<int>(lua_tointeger(L, _prio_idx)) }; 431 int const _priority{ static_cast<int>(lua_tointeger(L, _prio_idx)) };
410 if ((_priority < kThreadPrioMin || _priority > kThreadPrioMax)) { 432 if (!_native && (_priority < kThreadPrioMin || _priority > kThreadPrioMax)) {
411 raise_luaL_error(L, "Priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _priority); 433 raise_luaL_error(L, "Priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _priority);
412 } 434 }
413 return _priority; 435 return std::make_pair(_priority, _native);
414 }) 436 })
415 }; 437 };
416 438
417 _lane->startThread(_priority); 439 _lane->startThread(L_, _priority, _native);
418 440
419 STACK_GROW(_L2, _nargs + 3); 441 STACK_GROW(_L2, _nargs + 3);
420 STACK_GROW(L_, 3); 442 STACK_GROW(L_, 3);
@@ -658,6 +680,7 @@ namespace {
658 { Universe::kFinally, Universe::InitializeFinalizer }, 680 { Universe::kFinally, Universe::InitializeFinalizer },
659 { "linda", LG_linda }, 681 { "linda", LG_linda },
660 { "nameof", LG_nameof }, 682 { "nameof", LG_nameof },
683 { "thread_priority_range", LG_thread_priority_range },
661 { "now_secs", LG_now_secs }, 684 { "now_secs", LG_now_secs },
662 { "register", lanes_register }, 685 { "register", lanes_register },
663 { "set_singlethreaded", LG_set_singlethreaded }, 686 { "set_singlethreaded", LG_set_singlethreaded },
@@ -753,9 +776,6 @@ LUAG_FUNC(configure)
753 ); // L_: settings M VERSION 776 ); // L_: settings M VERSION
754 lua_setfield(L_, -2, "version"); // L_: settings M 777 lua_setfield(L_, -2, "version"); // L_: settings M
755 778
756 lua_pushinteger(L_, kThreadPrioMax); // L_: settings M kThreadPrioMax
757 lua_setfield(L_, -2, "max_prio"); // L_: settings M
758
759 kCancelError.pushKey(L_); // L_: settings M kCancelError 779 kCancelError.pushKey(L_); // L_: settings M kCancelError
760 lua_setfield(L_, -2, "cancel_error"); // L_: settings M 780 lua_setfield(L_, -2, "cancel_error"); // L_: settings M
761 781
diff --git a/src/lanes.lua b/src/lanes.lua
index 3ee959c..c5b3315 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -280,6 +280,10 @@ local opt_validators =
280 local tv = type(v_) 280 local tv = type(v_)
281 return (tv == "string") and v_ or raise_option_error("name", tv, v_) 281 return (tv == "string") and v_ or raise_option_error("name", tv, v_)
282 end, 282 end,
283 native_priority = function(v_)
284 local tv = type(v_)
285 return (tv == "number") and v_ or raise_option_error("native_priority", tv, v_)
286 end,
283 package = function(v_) 287 package = function(v_)
284 local tv = type(v_) 288 local tv = type(v_)
285 return (tv == "table") and v_ or raise_option_error("package", tv, v_) 289 return (tv == "table") and v_ or raise_option_error("package", tv, v_)
@@ -295,7 +299,7 @@ local opt_validators =
295} 299}
296 300
297-- ############################################################################################# 301-- #############################################################################################
298-- ##################################### lanes.gen() ########################################### 302-- ################################### lanes.gen/coro() ########################################
299-- ############################################################################################# 303-- #############################################################################################
300 304
301local process_gen_opt = function(...) 305local process_gen_opt = function(...)
@@ -367,9 +371,16 @@ local process_gen_opt = function(...)
367 opt[k] = validator(v) 371 opt[k] = validator(v)
368 end 372 end
369 end 373 end
374
375 -- special case: can't have priority and native_priority at the same time
376 if opt.priority and opt.native_priority then
377 error "priority and native_priority cannot be specified together"
378 end
370 return func, libs, opt 379 return func, libs, opt
371end -- process_gen_opt 380end -- process_gen_opt
372 381
382-- #################################################################################################
383
373-- lane_h[1..n]: lane results, same as via 'lane_h:join()' 384-- lane_h[1..n]: lane results, same as via 'lane_h:join()'
374-- lane_h[0]: can be read to make sure a thread has finished (gives the number of available results) 385-- lane_h[0]: can be read to make sure a thread has finished (gives the number of available results)
375-- lane_h[negative]: error message, without propagating the error 386-- lane_h[negative]: error message, without propagating the error
@@ -408,25 +419,28 @@ end -- process_gen_opt
408-- Calling with a function argument ('lane_func') ends the string/table 419-- Calling with a function argument ('lane_func') ends the string/table
409-- modifiers, and prepares a lane generator. 420-- modifiers, and prepares a lane generator.
410 421
411-- receives a sequence of strings and tables, plus a function 422local make_generator = function(is_coro_, ...)
412local gen = function(...)
413 local func, libs, opt = process_gen_opt(...) 423 local func, libs, opt = process_gen_opt(...)
414 local core_lane_new = assert(core.lane_new) 424 local core_lane_new = assert(core.lane_new)
415 local priority, globals, package, required, gc_cb, name, error_trace_level = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name, error_trace_levels[opt.error_trace_level] 425 local prio_is_native = opt.native_priority and true or false
426 local priority, globals, package, required, gc_cb, name, error_trace_level = opt.priority or opt.native_priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name, error_trace_levels[opt.error_trace_level]
416 return function(...) 427 return function(...)
417 -- must pass functions args last else they will be truncated to the first one 428 -- must pass functions args last else they will be truncated to the first one
418 return core_lane_new(func, libs, priority, globals, package, required, gc_cb, name, error_trace_level, false, ...) 429 return core_lane_new(func, libs, prio_is_native, priority, globals, package, required, gc_cb, name, error_trace_level, is_coro_, ...)
419 end 430 end
431end -- make_generator
432
433-- #################################################################################################
434
435-- receives a sequence of strings and tables, plus a function
436local gen = function(...)
437 return make_generator(false, ...)
420end -- gen() 438end -- gen()
421 439
440-- #################################################################################################
441
422local coro = function(...) 442local coro = function(...)
423 local func, libs, opt = process_gen_opt(...) 443 return make_generator(true, ...)
424 local core_lane_new = assert(core.lane_new)
425 local priority, globals, package, required, gc_cb, name, error_trace_level = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name, error_trace_levels[opt.error_trace_level]
426 return function(...)
427 -- must pass functions args last else they will be truncated to the first one
428 return core_lane_new(func, libs, priority, globals, package, required, gc_cb, name, error_trace_level, true, ...)
429 end
430end -- coro() 444end -- coro()
431 445
432-- ################################################################################################# 446-- #################################################################################################
@@ -656,7 +670,8 @@ local configure_timers = function()
656 end 670 end
657 end 671 end
658 end -- timer_body() 672 end -- timer_body()
659 timer_lane = gen("lanes_core,table", { name = "LanesTimer", package = {}, priority = core.max_prio }, timer_body)() 673 local min_prio, max_prio = core.thread_priority_range()
674 timer_lane = gen("lanes_core,table", { name = "LanesTimer", package = {}, priority = max_prio }, timer_body)()
660 end -- first_time 675 end -- first_time
661 676
662 ----- 677 -----
@@ -876,6 +891,7 @@ local configure = function(settings_)
876 lanes.set_thread_affinity = core.set_thread_affinity 891 lanes.set_thread_affinity = core.set_thread_affinity
877 lanes.set_thread_priority = core.set_thread_priority 892 lanes.set_thread_priority = core.set_thread_priority
878 lanes.sleep = core.sleep 893 lanes.sleep = core.sleep
894 lanes.thread_priority_range = core.thread_priority_range
879 lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false 895 lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false
880 896
881 lanes.gen = gen 897 lanes.gen = gen
diff --git a/src/threading.cpp b/src/threading.cpp
index 483a228..efca7eb 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -49,6 +49,7 @@ THE SOFTWARE.
49 49
50#endif // __linux__ 50#endif // __linux__
51 51
52#include "compat.hpp"
52#include "threading.hpp" 53#include "threading.hpp"
53 54
54#if !defined(PLATFORM_XBOX) && !defined(PLATFORM_WIN32) && !defined(PLATFORM_POCKETPC) 55#if !defined(PLATFORM_XBOX) && !defined(PLATFORM_WIN32) && !defined(PLATFORM_POCKETPC)
@@ -82,25 +83,42 @@ THE SOFTWARE.
82#pragma warning(disable : 4054) 83#pragma warning(disable : 4054)
83#endif 84#endif
84 85
86static constexpr std::string_view StripFuncName(std::string_view const& where_)
87{
88 std::string_view funcname_{ where_ };
89
90 auto _args_pos{ funcname_.find_first_of('(') };
91 funcname_ = funcname_.substr(0, _args_pos);
92 auto _name_pos{ funcname_.find_last_of(' ') };
93 funcname_.remove_prefix(_name_pos + 1);
94 return funcname_;
95}
96
85/* 97/*
86 * FAIL is for unexpected API return values - essentially programming 98 * FAIL is for unexpected API return values - essentially programming
87 * error in _this_ code. 99 * error in _this_ code.
88 */ 100 */
89#if HAVE_WIN32 101#if HAVE_WIN32
90static void FAIL(char const* funcname_, DWORD const rc_) 102
103template <typename F, typename... ARGS>
104void Win32Invoke(lua_State* const L_, std::string_view const& where_, F& f_, ARGS... args_)
91{ 105{
106 auto const _ret{ std::invoke(f_, std::forward<ARGS>(args_)...) };
107 if (!_ret) {
108 auto const _rc{ GetLastError() };
109 std::string_view const _funcname{ StripFuncName(where_) };
110
92#if defined(PLATFORM_XBOX) 111#if defined(PLATFORM_XBOX)
93 fprintf(stderr, "%s() failed! (%d)\n", funcname_, rc_); 112 luaG_pushstring(L_, "%s() failed with code %d", _funcname.data(), _rc);
94#else // PLATFORM_XBOX 113#else // PLATFORM_XBOX
95 char buf[256]; 114 char _buf[256];
96 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, rc_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, nullptr); 115 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, _rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), _buf, 256, nullptr);
97 fprintf(stderr, "%s() failed! [GetLastError() -> %lu] '%s'", funcname_, rc_, buf); 116 luaG_pushstring(L_, "%s() failed with code %d '%s'", _funcname.data(), _rc, _buf);
98#endif // PLATFORM_XBOX 117#endif // PLATFORM_XBOX
99#ifdef _MSC_VER 118 raise_lua_error(L_);
100 __debugbreak(); // give a chance to the debugger! 119 }
101#endif // _MSC_VER
102 abort();
103} 120}
121
104#endif // HAVE_WIN32 122#endif // HAVE_WIN32
105 123
106/*---=== Threading ===---*/ 124/*---=== Threading ===---*/
@@ -121,33 +139,35 @@ static int const gs_prio_remap[] = {
121 139
122// ################################################################################################# 140// #################################################################################################
123 141
124void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) 142std::pair<int, int> THREAD_NATIVE_PRIOS()
125{ 143{
126 // prio range [-3,+3] was checked by the caller 144 return std::make_pair(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);
127 if (!SetThreadPriority(GetCurrentThread(), gs_prio_remap[prio_ + 3])) {
128 FAIL("THREAD_SET_PRIORITY", GetLastError());
129 }
130} 145}
131 146
132// ################################################################################################# 147// #################################################################################################
133 148
134void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool sudo_) 149[[nodiscard]]
150void THREAD_SET_PRIORITY(lua_State* const L_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
135{ 151{
136 // prio range [-3,+3] was checked by the caller 152 // mapped prio range [-3,+3] was checked by the caller
137 // for some reason when building for mingw, native_handle() is an unsigned long long, but HANDLE is a void* 153 return Win32Invoke(L_, std::source_location::current().function_name(), SetThreadPriority, GetCurrentThread(), native_ ? prio_ : gs_prio_remap[prio_ + 3]);
138 // -> need a strong cast to make g++ happy
139 if (!SetThreadPriority(thread_.native_handle(), gs_prio_remap[prio_ + 3])) {
140 FAIL("THREAD_SET_PRIORITY", GetLastError());
141 }
142} 154}
143 155
144// ################################################################################################# 156// #################################################################################################
145 157
146void THREAD_SET_AFFINITY(unsigned int aff_) 158[[nodiscard]]
159void THREAD_SET_PRIORITY(lua_State* const L_, std::thread& thread_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
147{ 160{
148 if (!SetThreadAffinityMask(GetCurrentThread(), aff_)) { 161 // mapped prio range [-3,+3] was checked by the caller
149 FAIL("THREAD_SET_AFFINITY", GetLastError()); 162 return Win32Invoke(L_, std::source_location::current().function_name(), SetThreadPriority, thread_.native_handle(), native_ ? prio_ : gs_prio_remap[prio_ + 3]);
150 } 163}
164
165// #################################################################################################
166
167[[nodiscard]]
168void THREAD_SET_AFFINITY(lua_State* const L_, unsigned int aff_)
169{
170 return Win32Invoke(L_, std::source_location::current().function_name(), SetThreadAffinityMask, GetCurrentThread(), aff_);
151} 171}
152 172
153// ################################################################################################# 173// #################################################################################################
@@ -215,24 +235,24 @@ static int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy)
215#endif // pthread_attr_setschedpolicy() 235#endif // pthread_attr_setschedpolicy()
216#endif // defined(__MINGW32__) || defined(__MINGW64__) 236#endif // defined(__MINGW32__) || defined(__MINGW64__)
217 237
218static void _PT_FAIL(int rc, const char* name, const char* file, int line) 238template <typename F, typename... ARGS>
239void PthreadInvoke(lua_State* const L_, std::string_view const& where_, F& f_, ARGS... args_)
219{ 240{
220 const char* why = (rc == EINVAL) ? "EINVAL" 241 auto const _rc{ std::invoke(f_, std::forward<ARGS>(args_)...) };
221 : (rc == EBUSY) ? "EBUSY" 242 if (_rc) {
222 : (rc == EPERM) ? "EPERM" 243 std::string_view const _funcname{ StripFuncName(where_) };
223 : (rc == ENOMEM) ? "ENOMEM" 244
224 : (rc == ESRCH) ? "ESRCH" 245 char const* _why = (_rc == EINVAL) ? "EINVAL"
225 : (rc == ENOTSUP) ? "ENOTSUP" 246 : (_rc == EBUSY) ? "EBUSY"
226 : "<UNKNOWN>"; 247 : (_rc == EPERM) ? "EPERM"
227 fprintf(stderr, "%s %d: %s failed, %d %s\n", file, line, name, rc, why); 248 : (_rc == ENOMEM) ? "ENOMEM"
228 abort(); 249 : (_rc == ESRCH) ? "ESRCH"
229} 250 : (_rc == ENOTSUP) ? "ENOTSUP"
230#define PT_CALL(call) \ 251 : "<UNKNOWN>";
231 { \ 252
232 int rc = call; \ 253 raise_luaL_error(L_, "%s() failed with code %s", _funcname.data(), _why);
233 if (rc != 0) \
234 _PT_FAIL(rc, #call, __FILE__, __LINE__); \
235 } 254 }
255}
236 256
237// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range 257// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range
238static int const gs_prio_remap[] = { 258static int const gs_prio_remap[] = {
@@ -357,7 +377,18 @@ static int const gs_prio_remap[] = {
357#endif // _PRIO_0 377#endif // _PRIO_0
358}; 378};
359 379
360void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) 380// #################################################################################################
381
382std::pair<int, int> THREAD_NATIVE_PRIOS()
383{
384 int const _prio_min{ sched_get_priority_min(_PRIO_MODE) };
385 int const _prio_max{ sched_get_priority_max(_PRIO_MODE) };
386 return std::make_pair(_prio_min, _prio_max);
387}
388
389// #################################################################################################
390
391void THREAD_SET_PRIORITY(lua_State* const L_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
361{ 392{
362#ifdef PLATFORM_LINUX 393#ifdef PLATFORM_LINUX
363 if (!sudo_) // only root-privileged process can change priorities 394 if (!sudo_) // only root-privileged process can change priorities
@@ -366,13 +397,13 @@ void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_)
366 397
367 struct sched_param sp; 398 struct sched_param sp;
368 // prio range [-3,+3] was checked by the caller 399 // prio range [-3,+3] was checked by the caller
369 sp.sched_priority = gs_prio_remap[prio_ + 3]; 400 sp.sched_priority = native_ ? prio_ : gs_prio_remap[prio_ + 3];
370 PT_CALL(pthread_setschedparam(pthread_self(), _PRIO_MODE, &sp)); 401 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setschedparam, pthread_self(), _PRIO_MODE, &sp);
371} 402}
372 403
373// ################################################################################################# 404// #################################################################################################
374 405
375void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool sudo_) 406void THREAD_SET_PRIORITY(lua_State* const L_, std::thread& thread_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
376{ 407{
377#ifdef PLATFORM_LINUX 408#ifdef PLATFORM_LINUX
378 if (!sudo_) // only root-privileged process can change priorities 409 if (!sudo_) // only root-privileged process can change priorities
@@ -381,28 +412,26 @@ void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool
381 412
382 struct sched_param sp; 413 struct sched_param sp;
383 // prio range [-3,+3] was checked by the caller 414 // prio range [-3,+3] was checked by the caller
384 sp.sched_priority = gs_prio_remap[prio_ + 3]; 415 sp.sched_priority = native_ ? prio_ : gs_prio_remap[prio_ + 3];
385 PT_CALL(pthread_setschedparam(thread_.native_handle(), _PRIO_MODE, &sp)); 416 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setschedparam, thread_.native_handle(), _PRIO_MODE, &sp);
386} 417}
387 418
388// ################################################################################################# 419// #################################################################################################
389 420
390#ifdef __PROSPERO__ 421#ifdef __PROSPERO__
391 422
392void THREAD_SET_AFFINITY(unsigned int aff_) 423void THREAD_SET_AFFINITY(lua_State* const L_, unsigned int aff_)
393{ 424{
394 scePthreadSetaffinity(scePthreadSelf(), aff_); 425 PthreadInvoke(L_, std::source_location::current().function_name(), scePthreadSetaffinity, scePthreadSelf(), aff_);
395} 426}
396 427
397#else // __PROSPERO__ 428#else // __PROSPERO__
398 429
399void THREAD_SET_AFFINITY(unsigned int aff_) 430void THREAD_SET_AFFINITY(lua_State* const L_, unsigned int aff_)
400{ 431{
401#if HAVE_WIN32 // "hybrid": Win32 API is available, and pthread too 432#if HAVE_WIN32 // "hybrid": Win32 API is available, and pthread too
402 // since pthread_setaffinity_np can be missing (for example mingw), use win32 api instead 433 // since pthread_setaffinity_np can be missing (for example mingw), use win32 api instead
403 if (!SetThreadAffinityMask(GetCurrentThread(), aff_)) { 434 Win32Invoke(L_, std::source_location::current().function_name(), SetThreadAffinityMask, GetCurrentThread(), aff_);
404 FAIL("THREAD_SET_AFFINITY", GetLastError());
405 }
406#else // pure pthread 435#else // pure pthread
407 int bit = 0; 436 int bit = 0;
408#ifdef __NetBSD__ 437#ifdef __NetBSD__
@@ -422,12 +451,13 @@ void THREAD_SET_AFFINITY(unsigned int aff_)
422 aff_ >>= 1; 451 aff_ >>= 1;
423 } 452 }
424#ifdef __ANDROID__ 453#ifdef __ANDROID__
425 PT_CALL(sched_setaffinity(pthread_self(), sizeof(cpu_set_t), &cpuset)); 454
455 PthreadInvoke(L_, std::source_location::current().function_name(), sched_setaffinity, pthread_self(), sizeof(cpu_set_t), &cpuset);
426#elif defined(__NetBSD__) 456#elif defined(__NetBSD__)
427 PT_CALL(pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset), cpuset)); 457 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setaffinity_np, pthread_self(), cpuset_size(cpuset), cpuset);
428 cpuset_destroy(cpuset); 458 cpuset_destroy(cpuset);
429#else 459#else
430 PT_CALL(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset)); 460 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setaffinity_np, pthread_self(), sizeof(cpu_set_t), &cpuset);
431#endif 461#endif
432#endif // PLATFORM_MINGW 462#endif // PLATFORM_MINGW
433} 463}
@@ -447,7 +477,7 @@ void THREAD_SETNAME(std::string_view const& name_)
447 477
448void THREAD_SETNAME(std::string_view const& name_) 478void THREAD_SETNAME(std::string_view const& name_)
449{ 479{
450 // exact API to set the thread name is platform-dependant 480 // exact API to set the thread name is platform-dependent
451 // 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. 481 // 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.
452#if defined PLATFORM_MINGW 482#if defined PLATFORM_MINGW
453 pthread_setname_np(pthread_self(), name_.data()); 483 pthread_setname_np(pthread_self(), name_.data());
diff --git a/src/threading.hpp b/src/threading.hpp
index 912c28f..07c1ab3 100644
--- a/src/threading.hpp
+++ b/src/threading.hpp
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "platform.h" 3#include "platform.h"
4#include "unique.hpp"
4 5
5#define THREADAPI_WINDOWS 1 6#define THREADAPI_WINDOWS 1
6#define THREADAPI_PTHREAD 2 7#define THREADAPI_PTHREAD 2
@@ -73,8 +74,15 @@ static constexpr int kThreadPrioMax{ +3 };
73// ################################################################################################# 74// #################################################################################################
74// ################################################################################################# 75// #################################################################################################
75 76
77DECLARE_UNIQUE_TYPE(SudoFlag, bool);
78DECLARE_UNIQUE_TYPE(NativePrioFlag, bool);
79
80std::pair<int, int> THREAD_NATIVE_PRIOS();
81
76void THREAD_SETNAME(std::string_view const& name_); 82void THREAD_SETNAME(std::string_view const& name_);
77void THREAD_SET_PRIORITY(int prio_, bool sudo_);
78void THREAD_SET_AFFINITY(unsigned int aff_);
79 83
80void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, bool sudo_); 84void THREAD_SET_PRIORITY(lua_State* L_, int prio_, NativePrioFlag native_, SudoFlag sudo_);
85
86void THREAD_SET_AFFINITY(lua_State* L_, unsigned int aff_);
87
88void THREAD_SET_PRIORITY(lua_State* L_, std::thread& thread_, int prio_, NativePrioFlag native_, SudoFlag sudo_);
diff --git a/src/universe.hpp b/src/universe.hpp
index fac5f50..ab49f86 100644
--- a/src/universe.hpp
+++ b/src/universe.hpp
@@ -4,6 +4,7 @@
4#include "cancel.hpp" 4#include "cancel.hpp"
5#include "keeper.hpp" 5#include "keeper.hpp"
6#include "lanesconf.h" 6#include "lanesconf.h"
7#include "threading.hpp"
7#include "tracker.hpp" 8#include "tracker.hpp"
8#include "uniquekey.hpp" 9#include "uniquekey.hpp"
9 10
@@ -70,9 +71,9 @@ class Universe final
70 71
71#ifdef PLATFORM_LINUX 72#ifdef PLATFORM_LINUX
72 // Linux needs to check, whether it's been run as root 73 // Linux needs to check, whether it's been run as root
73 bool const sudo{ geteuid() == 0 }; 74 SudoFlag const sudo{ geteuid() == 0 };
74#else 75#else
75 bool const sudo{ false }; 76 SudoFlag const sudo{ false };
76#endif // PLATFORM_LINUX 77#endif // PLATFORM_LINUX
77 78
78 // for verbose errors 79 // for verbose errors