diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lane.cpp | 4 | ||||
| -rw-r--r-- | src/lane.hpp | 2 | ||||
| -rw-r--r-- | src/lanes.cpp | 62 | ||||
| -rw-r--r-- | src/lanes.lua | 42 | ||||
| -rw-r--r-- | src/threading.cpp | 146 | ||||
| -rw-r--r-- | src/threading.hpp | 14 | ||||
| -rw-r--r-- | src/universe.hpp | 5 |
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 | ||
| 1172 | void Lane::startThread(int const priority_) | 1172 | void 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) | |||
| 137 | LUAG_FUNC(set_thread_priority) | 137 | LUAG_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 | ||
| 242 | LUAG_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 | ||
| 301 | local process_gen_opt = function(...) | 305 | local 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 |
| 371 | end -- process_gen_opt | 380 | end -- 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 | 422 | local make_generator = function(is_coro_, ...) |
| 412 | local 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 |
| 431 | end -- make_generator | ||
| 432 | |||
| 433 | -- ################################################################################################# | ||
| 434 | |||
| 435 | -- receives a sequence of strings and tables, plus a function | ||
| 436 | local gen = function(...) | ||
| 437 | return make_generator(false, ...) | ||
| 420 | end -- gen() | 438 | end -- gen() |
| 421 | 439 | ||
| 440 | -- ################################################################################################# | ||
| 441 | |||
| 422 | local coro = function(...) | 442 | local 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 | ||
| 430 | end -- coro() | 444 | end -- 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 | ||
| 86 | static 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 |
| 90 | static void FAIL(char const* funcname_, DWORD const rc_) | 102 | |
| 103 | template <typename F, typename... ARGS> | ||
| 104 | void 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 | ||
| 124 | void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) | 142 | std::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 | ||
| 134 | void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool sudo_) | 149 | [[nodiscard]] |
| 150 | void 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 | ||
| 146 | void THREAD_SET_AFFINITY(unsigned int aff_) | 158 | [[nodiscard]] |
| 159 | void 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]] | ||
| 168 | void 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 | ||
| 218 | static void _PT_FAIL(int rc, const char* name, const char* file, int line) | 238 | template <typename F, typename... ARGS> |
| 239 | void 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 |
| 238 | static int const gs_prio_remap[] = { | 258 | static 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 | ||
| 360 | void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) | 380 | // ################################################################################################# |
| 381 | |||
| 382 | std::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 | |||
| 391 | void 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 | ||
| 375 | void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool sudo_) | 406 | void 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 | ||
| 392 | void THREAD_SET_AFFINITY(unsigned int aff_) | 423 | void 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 | ||
| 399 | void THREAD_SET_AFFINITY(unsigned int aff_) | 430 | void 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 | ||
| 448 | void THREAD_SETNAME(std::string_view const& name_) | 478 | void 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 | ||
| 77 | DECLARE_UNIQUE_TYPE(SudoFlag, bool); | ||
| 78 | DECLARE_UNIQUE_TYPE(NativePrioFlag, bool); | ||
| 79 | |||
| 80 | std::pair<int, int> THREAD_NATIVE_PRIOS(); | ||
| 81 | |||
| 76 | void THREAD_SETNAME(std::string_view const& name_); | 82 | void THREAD_SETNAME(std::string_view const& name_); |
| 77 | void THREAD_SET_PRIORITY(int prio_, bool sudo_); | ||
| 78 | void THREAD_SET_AFFINITY(unsigned int aff_); | ||
| 79 | 83 | ||
| 80 | void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, bool sudo_); | 84 | void THREAD_SET_PRIORITY(lua_State* L_, int prio_, NativePrioFlag native_, SudoFlag sudo_); |
| 85 | |||
| 86 | void THREAD_SET_AFFINITY(lua_State* L_, unsigned int aff_); | ||
| 87 | |||
| 88 | void 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 |
