diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lanes.cpp | 134 | ||||
| -rw-r--r-- | src/lanes.lua | 22 | ||||
| -rw-r--r-- | src/lanes_private.h | 2 |
3 files changed, 97 insertions, 61 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp index e09956c..bce75a6 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
| @@ -201,8 +201,8 @@ void Lane::startThread(int priority_) | |||
| 201 | */ | 201 | */ |
| 202 | #define ERROR_FULL_STACK 1 // must be either 0 or 1 as we do some index arithmetics with it! | 202 | #define ERROR_FULL_STACK 1 // must be either 0 or 1 as we do some index arithmetics with it! |
| 203 | 203 | ||
| 204 | // intern the debug name in the specified lua state so that the pointer remains valid when the lane's state is closed | 204 | // intern the debug name in the caller lua state so that the pointer remains valid after the lane's state is closed |
| 205 | static void securize_debug_threadname(lua_State* L_, Lane* lane_) | 205 | void Lane::securizeDebugName(lua_State* L_) |
| 206 | { | 206 | { |
| 207 | STACK_CHECK_START_REL(L_, 0); | 207 | STACK_CHECK_START_REL(L_, 0); |
| 208 | STACK_GROW(L_, 3); | 208 | STACK_GROW(L_, 3); |
| @@ -212,8 +212,8 @@ static void securize_debug_threadname(lua_State* L_, Lane* lane_) | |||
| 212 | // we don't care about the actual key, so long as it's unique and can't collide with anything. | 212 | // we don't care about the actual key, so long as it's unique and can't collide with anything. |
| 213 | lua_newtable(L_); // L_: lane ... {uv} {} | 213 | lua_newtable(L_); // L_: lane ... {uv} {} |
| 214 | // Lua 5.1 can't do 'lane_->debugName = lua_pushstring(L_, lane_->debugName);' | 214 | // Lua 5.1 can't do 'lane_->debugName = lua_pushstring(L_, lane_->debugName);' |
| 215 | lua_pushstring(L_, lane_->debugName); // L_: lane ... {uv} {} name | 215 | lua_pushstring(L_, debugName); // L_: lane ... {uv} {} name |
| 216 | lane_->debugName = lua_tostring(L_, -1); | 216 | debugName = lua_tostring(L_, -1); |
| 217 | lua_rawset(L_, -3); // L_: lane ... {uv} | 217 | lua_rawset(L_, -3); // L_: lane ... {uv} |
| 218 | lua_pop(L_, 1); // L_: lane | 218 | lua_pop(L_, 1); // L_: lane |
| 219 | STACK_CHECK(L_, 0); | 219 | STACK_CHECK(L_, 0); |
| @@ -674,23 +674,36 @@ LUAG_FUNC(set_error_reporting) | |||
| 674 | 674 | ||
| 675 | // ################################################################################################# | 675 | // ################################################################################################# |
| 676 | 676 | ||
| 677 | void Lane::changeDebugName(int nameIdx_) | ||
| 678 | { | ||
| 679 | // xxh64 of string "debugName" generated at https://www.pelock.com/products/hash-calculator | ||
| 680 | static constexpr RegistryUniqueKey hidden_regkey{ 0xA194E2645C57F6DDull }; | ||
| 681 | nameIdx_ = lua_absindex(L, nameIdx_); | ||
| 682 | luaL_checktype(L, nameIdx_, LUA_TSTRING); // L: ... "name" ... | ||
| 683 | STACK_CHECK_START_REL(L, 0); | ||
| 684 | // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... | ||
| 685 | hidden_regkey.setValue(L, [nameIdx = nameIdx_](lua_State* L_) { lua_pushvalue(L_, nameIdx); });// L: ... "name" ... | ||
| 686 | // keep a direct pointer on the string | ||
| 687 | debugName = lua_tostring(L, nameIdx_); | ||
| 688 | // to see VM name in Decoda debugger Virtual Machine window | ||
| 689 | lua_pushvalue(L, nameIdx_); // L: ... "name" ... "name" | ||
| 690 | lua_setglobal(L, "decoda_name"); // L: ... "name" ... | ||
| 691 | // and finally set the OS thread name | ||
| 692 | THREAD_SETNAME(debugName); | ||
| 693 | STACK_CHECK(L, 0); | ||
| 694 | } | ||
| 695 | |||
| 696 | // ################################################################################################# | ||
| 697 | |||
| 698 | // upvalue #1 is the lane userdata | ||
| 677 | LUAG_FUNC(set_debug_threadname) | 699 | LUAG_FUNC(set_debug_threadname) |
| 678 | { | 700 | { |
| 679 | // fnv164 of string "debug_threadname" generated at https://www.pelock.com/products/hash-calculator | ||
| 680 | constexpr RegistryUniqueKey hidden_regkey{ 0x79C0669AAAE04440ull }; | ||
| 681 | // C s_lane structure is a light userdata upvalue | 701 | // C s_lane structure is a light userdata upvalue |
| 682 | Lane* const lane{ lua_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) }; | 702 | Lane* const lane{ lua_tolightuserdata<Lane>(L_, lua_upvalueindex(1)) }; |
| 683 | luaL_checktype(L_, -1, LUA_TSTRING); // "name" | 703 | LUA_ASSERT(L_, L_ == lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state |
| 684 | lua_settop(L_, 1); | 704 | lua_settop(L_, 1); |
| 685 | STACK_CHECK_START_ABS(L_, 1); | 705 | STACK_CHECK_START_REL(L_, 0); |
| 686 | // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... | 706 | lane->changeDebugName(-1); |
| 687 | hidden_regkey.setValue(L_, [](lua_State* L_) { lua_pushvalue(L_, -2); }); | ||
| 688 | STACK_CHECK(L_, 1); | ||
| 689 | lane->debugName = lua_tostring(L_, -1); | ||
| 690 | // keep a direct pointer on the string | ||
| 691 | THREAD_SETNAME(lane->debugName); | ||
| 692 | // to see VM name in Decoda debugger Virtual Machine window | ||
| 693 | lua_setglobal(L_, "decoda_name"); // | ||
| 694 | STACK_CHECK(L_, 0); | 707 | STACK_CHECK(L_, 0); |
| 695 | return 0; | 708 | return 0; |
| 696 | } | 709 | } |
| @@ -911,13 +924,14 @@ static constexpr UniqueKey kLaneGC{ 0x5D6122141727F960ull }; | |||
| 911 | // , [package_tbl] | 924 | // , [package_tbl] |
| 912 | // , [required_tbl] | 925 | // , [required_tbl] |
| 913 | // , [gc_cb_func] | 926 | // , [gc_cb_func] |
| 927 | // , [name] | ||
| 914 | // [, ... args ...]) | 928 | // [, ... args ...]) |
| 915 | // | 929 | // |
| 916 | // Upvalues: metatable to use for 'lane_ud' | 930 | // Upvalues: metatable to use for 'lane_ud' |
| 917 | // | 931 | // |
| 918 | LUAG_FUNC(lane_new) | 932 | LUAG_FUNC(lane_new) |
| 919 | { | 933 | { |
| 920 | // first 7 args: func libs priority globals package required gc_cb | 934 | // first 8 args: func libs priority globals package required gc_cb name |
| 921 | char const* const libs_str{ lua_tostring(L_, 2) }; | 935 | char const* const libs_str{ lua_tostring(L_, 2) }; |
| 922 | bool const have_priority{ !lua_isnoneornil(L_, 3) }; | 936 | bool const have_priority{ !lua_isnoneornil(L_, 3) }; |
| 923 | int const priority{ have_priority ? static_cast<int>(lua_tointeger(L_, 3)) : kThreadPrioDefault }; | 937 | int const priority{ have_priority ? static_cast<int>(lua_tointeger(L_, 3)) : kThreadPrioDefault }; |
| @@ -925,8 +939,9 @@ LUAG_FUNC(lane_new) | |||
| 925 | int const package_idx{ lua_isnoneornil(L_, 5) ? 0 : 5 }; | 939 | int const package_idx{ lua_isnoneornil(L_, 5) ? 0 : 5 }; |
| 926 | int const required_idx{ lua_isnoneornil(L_, 6) ? 0 : 6 }; | 940 | int const required_idx{ lua_isnoneornil(L_, 6) ? 0 : 6 }; |
| 927 | int const gc_cb_idx{ lua_isnoneornil(L_, 7) ? 0 : 7 }; | 941 | int const gc_cb_idx{ lua_isnoneornil(L_, 7) ? 0 : 7 }; |
| 942 | int const name_idx{ lua_isnoneornil(L_, 8) ? 0 : 8 }; | ||
| 928 | 943 | ||
| 929 | static constexpr int kFixedArgsIdx{ 7 }; | 944 | static constexpr int kFixedArgsIdx{ 8 }; |
| 930 | int const nargs{ lua_gettop(L_) - kFixedArgsIdx }; | 945 | int const nargs{ lua_gettop(L_) - kFixedArgsIdx }; |
| 931 | Universe* const U{ universe_get(L_) }; | 946 | Universe* const U{ universe_get(L_) }; |
| 932 | LUA_ASSERT(L_, nargs >= 0); | 947 | LUA_ASSERT(L_, nargs >= 0); |
| @@ -942,7 +957,7 @@ LUAG_FUNC(lane_new) | |||
| 942 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: setup\n" INDENT_END(U))); | 957 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: setup\n" INDENT_END(U))); |
| 943 | 958 | ||
| 944 | // populate with selected libraries at the same time. | 959 | // populate with selected libraries at the same time. |
| 945 | lua_State* const L2{ luaG_newstate(U, SourceState{ L_ }, libs_str) }; // L_: [7 args] ... L2: | 960 | lua_State* const L2{ luaG_newstate(U, SourceState{ L_ }, libs_str) }; // L_: [8 args] ... L2: |
| 946 | STACK_CHECK_START_REL(L2, 0); | 961 | STACK_CHECK_START_REL(L2, 0); |
| 947 | 962 | ||
| 948 | // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) | 963 | // 'lane' is allocated from heap, not Lua, since its life span may surpass the handle's (if free running thread) |
| @@ -957,14 +972,16 @@ LUAG_FUNC(lane_new) | |||
| 957 | lua_State* const m_L; | 972 | lua_State* const m_L; |
| 958 | Lane* m_lane{ nullptr }; | 973 | Lane* m_lane{ nullptr }; |
| 959 | int const m_gc_cb_idx; | 974 | int const m_gc_cb_idx; |
| 975 | int const m_name_idx; | ||
| 960 | DEBUGSPEW_CODE(Universe* const U); | 976 | DEBUGSPEW_CODE(Universe* const U); |
| 961 | DEBUGSPEW_CODE(DebugSpewIndentScope m_scope); | 977 | DEBUGSPEW_CODE(DebugSpewIndentScope m_scope); |
| 962 | 978 | ||
| 963 | public: | 979 | public: |
| 964 | OnExit(lua_State* L_, Lane* lane_, int gc_cb_idx_ DEBUGSPEW_COMMA_PARAM(Universe* U_)) | 980 | OnExit(lua_State* L_, Lane* lane_, int gc_cb_idx_, int name_idx_ DEBUGSPEW_COMMA_PARAM(Universe* U_)) |
| 965 | : m_L{ L_ } | 981 | : m_L{ L_ } |
| 966 | , m_lane{ lane_ } | 982 | , m_lane{ lane_ } |
| 967 | , m_gc_cb_idx{ gc_cb_idx_ } | 983 | , m_gc_cb_idx{ gc_cb_idx_ } |
| 984 | , m_name_idx{ name_idx_ } | ||
| 968 | DEBUGSPEW_COMMA_PARAM(U{ U_ }) | 985 | DEBUGSPEW_COMMA_PARAM(U{ U_ }) |
| 969 | DEBUGSPEW_COMMA_PARAM(m_scope{ U_ }) | 986 | DEBUGSPEW_COMMA_PARAM(m_scope{ U_ }) |
| 970 | { | 987 | { |
| @@ -1019,6 +1036,24 @@ LUAG_FUNC(lane_new) | |||
| 1019 | } | 1036 | } |
| 1020 | 1037 | ||
| 1021 | lua_setiuservalue(m_L, -2, 1); // m_L: ... lane | 1038 | lua_setiuservalue(m_L, -2, 1); // m_L: ... lane |
| 1039 | |||
| 1040 | lua_State* L2{ m_lane->L }; | ||
| 1041 | STACK_CHECK_START_REL(L2, 0); | ||
| 1042 | char const* const debugName{ (m_name_idx > 0) ? lua_tostring(m_L, m_name_idx) : nullptr }; | ||
| 1043 | if (debugName) | ||
| 1044 | { | ||
| 1045 | if (strcmp(debugName, "auto") != 0) { | ||
| 1046 | lua_pushstring(L2, debugName); // m_L: ... lane L2: "<name>" | ||
| 1047 | } else { | ||
| 1048 | lua_Debug ar; | ||
| 1049 | lua_pushvalue(m_L, 1); // m_L: ... lane func | ||
| 1050 | lua_getinfo(m_L, ">S", &ar); // m_L: ... lane | ||
| 1051 | lua_pushfstring(L2, "%s:%d", ar.short_src, ar.linedefined); // m_L: ... lane L2: "<name>" | ||
| 1052 | } | ||
| 1053 | m_lane->changeDebugName(-1); | ||
| 1054 | lua_pop(L2, 1); // m_L: ... lane L2: | ||
| 1055 | } | ||
| 1056 | STACK_CHECK(L2, 0); | ||
| 1022 | STACK_CHECK(m_L, 1); | 1057 | STACK_CHECK(m_L, 1); |
| 1023 | } | 1058 | } |
| 1024 | 1059 | ||
| @@ -1029,7 +1064,7 @@ LUAG_FUNC(lane_new) | |||
| 1029 | m_lane->ready.count_down(); | 1064 | m_lane->ready.count_down(); |
| 1030 | m_lane = nullptr; | 1065 | m_lane = nullptr; |
| 1031 | } | 1066 | } |
| 1032 | } onExit{ L_, lane, gc_cb_idx DEBUGSPEW_COMMA_PARAM(U) }; | 1067 | } onExit{ L_, lane, gc_cb_idx, name_idx DEBUGSPEW_COMMA_PARAM(U) }; |
| 1033 | // launch the thread early, it will sync with a std::latch to parallelize OS thread warmup and L2 preparation | 1068 | // launch the thread early, it will sync with a std::latch to parallelize OS thread warmup and L2 preparation |
| 1034 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END(U))); | 1069 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END(U))); |
| 1035 | lane->startThread(priority); | 1070 | lane->startThread(priority); |
| @@ -1038,11 +1073,6 @@ LUAG_FUNC(lane_new) | |||
| 1038 | STACK_GROW(L_, 3); | 1073 | STACK_GROW(L_, 3); |
| 1039 | STACK_CHECK_START_REL(L_, 0); | 1074 | STACK_CHECK_START_REL(L_, 0); |
| 1040 | 1075 | ||
| 1041 | // give a default "Lua" name to the thread to see VM name in Decoda debugger | ||
| 1042 | lua_pushfstring(L2, "Lane #%p", L2); // L_: [7 args] args... L2: "<name>" | ||
| 1043 | lua_setglobal(L2, "decoda_name"); // L_: [7 args] args... L2: | ||
| 1044 | LUA_ASSERT(L_, lua_gettop(L2) == 0); | ||
| 1045 | |||
| 1046 | // package | 1076 | // package |
| 1047 | if (package_idx != 0) { | 1077 | if (package_idx != 0) { |
| 1048 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END(U))); | 1078 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END(U))); |
| @@ -1062,8 +1092,8 @@ LUAG_FUNC(lane_new) | |||
| 1062 | raise_luaL_error(L_, "expected required module list as a table, got %s", luaL_typename(L_, required_idx)); | 1092 | raise_luaL_error(L_, "expected required module list as a table, got %s", luaL_typename(L_, required_idx)); |
| 1063 | } | 1093 | } |
| 1064 | 1094 | ||
| 1065 | lua_pushnil(L_); // L_: [7 args] args... nil L2: | 1095 | lua_pushnil(L_); // L_: [8 args] args... nil L2: |
| 1066 | while (lua_next(L_, required_idx) != 0) { // L_: [7 args] args... n "modname" L2: | 1096 | while (lua_next(L_, required_idx) != 0) { // L_: [8 args] args... n "modname" L2: |
| 1067 | if (lua_type(L_, -1) != LUA_TSTRING || lua_type(L_, -2) != LUA_TNUMBER || lua_tonumber(L_, -2) != nbRequired) { | 1097 | if (lua_type(L_, -1) != LUA_TSTRING || lua_type(L_, -2) != LUA_TNUMBER || lua_tonumber(L_, -2) != nbRequired) { |
| 1068 | raise_luaL_error(L_, "required module list should be a list of strings"); | 1098 | raise_luaL_error(L_, "required module list should be a list of strings"); |
| 1069 | } else { | 1099 | } else { |
| @@ -1073,30 +1103,30 @@ LUAG_FUNC(lane_new) | |||
| 1073 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END(U), name)); | 1103 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: require '%s'\n" INDENT_END(U), name)); |
| 1074 | 1104 | ||
| 1075 | // require the module in the target lane | 1105 | // require the module in the target lane |
| 1076 | lua_getglobal(L2, "require"); // L_: [7 args] args... n "modname" L2: require()? | 1106 | lua_getglobal(L2, "require"); // L_: [8 args] args... n "modname" L2: require()? |
| 1077 | if (lua_isnil(L2, -1)) { | 1107 | if (lua_isnil(L2, -1)) { |
| 1078 | lua_pop(L2, 1); // L_: [7 args] args... n "modname" L2: | 1108 | lua_pop(L2, 1); // L_: [8 args] args... n "modname" L2: |
| 1079 | raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first"); | 1109 | raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first"); |
| 1080 | } else { | 1110 | } else { |
| 1081 | lua_pushlstring(L2, name, len); // L_: [7 args] args... n "modname" L2: require() name | 1111 | lua_pushlstring(L2, name, len); // L_: [8 args] args... n "modname" L2: require() name |
| 1082 | if (lua_pcall(L2, 1, 1, 0) != LUA_OK) { // L_: [7 args] args... n "modname" L2: ret/errcode | 1112 | if (lua_pcall(L2, 1, 1, 0) != LUA_OK) { // L_: [8 args] args... n "modname" L2: ret/errcode |
| 1083 | // propagate error to main state if any | 1113 | // propagate error to main state if any |
| 1084 | InterCopyContext c{ U, DestState{ L_ }, SourceState{ L2 }, {}, {}, {}, {}, {} }; | 1114 | InterCopyContext c{ U, DestState{ L_ }, SourceState{ L2 }, {}, {}, {}, {}, {} }; |
| 1085 | std::ignore = c.inter_move(1); // L_: [7 args] args... n "modname" error L2: | 1115 | std::ignore = c.inter_move(1); // L_: [8 args] args... n "modname" error L2: |
| 1086 | raise_lua_error(L_); | 1116 | raise_lua_error(L_); |
| 1087 | } | 1117 | } |
| 1088 | // here the module was successfully required // L_: [7 args] args... n "modname" L2: ret | 1118 | // here the module was successfully required // L_: [8 args] args... n "modname" L2: ret |
| 1089 | // after requiring the module, register the functions it exported in our name<->function database | 1119 | // after requiring the module, register the functions it exported in our name<->function database |
| 1090 | populate_func_lookup_table(L2, -1, name); | 1120 | populate_func_lookup_table(L2, -1, name); |
| 1091 | lua_pop(L2, 1); // L_: [7 args] args... n "modname" L2: | 1121 | lua_pop(L2, 1); // L_: [8 args] args... n "modname" L2: |
| 1092 | } | 1122 | } |
| 1093 | } | 1123 | } |
| 1094 | lua_pop(L_, 1); // L_: func libs priority globals package required gc_cb [... args ...] n | 1124 | lua_pop(L_, 1); // L_: func libs priority globals package required gc_cb [... args ...] n |
| 1095 | ++nbRequired; | 1125 | ++nbRequired; |
| 1096 | } // L_: [7 args] args... | 1126 | } // L_: [8 args] args... |
| 1097 | } | 1127 | } |
| 1098 | STACK_CHECK(L_, 0); | 1128 | STACK_CHECK(L_, 0); |
| 1099 | STACK_CHECK(L2, 0); // L_: [7 args] args... L2: | 1129 | STACK_CHECK(L2, 0); // L_: [8 args] args... L2: |
| 1100 | 1130 | ||
| 1101 | // Appending the specified globals to the global environment | 1131 | // Appending the specified globals to the global environment |
| 1102 | // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... | 1132 | // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed... |
| @@ -1108,17 +1138,17 @@ LUAG_FUNC(lane_new) | |||
| 1108 | } | 1138 | } |
| 1109 | 1139 | ||
| 1110 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 1140 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
| 1111 | lua_pushnil(L_); // L_: [7 args] args... nil L2: | 1141 | lua_pushnil(L_); // L_: [8 args] args... nil L2: |
| 1112 | // Lua 5.2 wants us to push the globals table on the stack | 1142 | // Lua 5.2 wants us to push the globals table on the stack |
| 1113 | InterCopyContext c{ U, DestState{ L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; | 1143 | InterCopyContext c{ U, DestState{ L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; |
| 1114 | lua_pushglobaltable(L2); // L_: [7 args] args... nil L2: _G | 1144 | lua_pushglobaltable(L2); // L_: [8 args] args... nil L2: _G |
| 1115 | while (lua_next(L_, globals_idx)) { // L_: [7 args] args... k v L2: _G | 1145 | while (lua_next(L_, globals_idx)) { // L_: [8 args] args... k v L2: _G |
| 1116 | std::ignore = c.inter_copy(2); // L_: [7 args] args... k v L2: _G k v | 1146 | std::ignore = c.inter_copy(2); // L_: [8 args] args... k v L2: _G k v |
| 1117 | // assign it in L2's globals table | 1147 | // assign it in L2's globals table |
| 1118 | lua_rawset(L2, -3); // L_: [7 args] args... k v L2: _G | 1148 | lua_rawset(L2, -3); // L_: [8 args] args... k v L2: _G |
| 1119 | lua_pop(L_, 1); // L_: [7 args] args... k | 1149 | lua_pop(L_, 1); // L_: [8 args] args... k |
| 1120 | } // L_: [7 args] args... | 1150 | } // L_: [8 args] args... |
| 1121 | lua_pop(L2, 1); // L_: [7 args] args... L2: | 1151 | lua_pop(L2, 1); // L_: [8 args] args... L2: |
| 1122 | } | 1152 | } |
| 1123 | STACK_CHECK(L_, 0); | 1153 | STACK_CHECK(L_, 0); |
| 1124 | STACK_CHECK(L2, 0); | 1154 | STACK_CHECK(L2, 0); |
| @@ -1128,16 +1158,16 @@ LUAG_FUNC(lane_new) | |||
| 1128 | if (func_type == LuaType::FUNCTION) { | 1158 | if (func_type == LuaType::FUNCTION) { |
| 1129 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END(U))); | 1159 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END(U))); |
| 1130 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 1160 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
| 1131 | lua_pushvalue(L_, 1); // L_: [7 args] args... func L2: | 1161 | lua_pushvalue(L_, 1); // L_: [8 args] args... func L2: |
| 1132 | InterCopyContext c{ U, DestState{ L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; | 1162 | InterCopyContext c{ U, DestState{ L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; |
| 1133 | InterCopyResult const res{ c.inter_move(1) }; // L_: [7 args] args... L2: func | 1163 | InterCopyResult const res{ c.inter_move(1) }; // L_: [8 args] args... L2: func |
| 1134 | if (res != InterCopyResult::Success) { | 1164 | if (res != InterCopyResult::Success) { |
| 1135 | raise_luaL_error(L_, "tried to copy unsupported types"); | 1165 | raise_luaL_error(L_, "tried to copy unsupported types"); |
| 1136 | } | 1166 | } |
| 1137 | } else if (func_type == LuaType::STRING) { | 1167 | } else if (func_type == LuaType::STRING) { |
| 1138 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: compile lane body\n" INDENT_END(U))); | 1168 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: compile lane body\n" INDENT_END(U))); |
| 1139 | // compile the string | 1169 | // compile the string |
| 1140 | if (luaL_loadstring(L2, lua_tostring(L_, 1)) != 0) { // L_: [7 args] args... L2: func | 1170 | if (luaL_loadstring(L2, lua_tostring(L_, 1)) != 0) { // L_: [8 args] args... L2: func |
| 1141 | raise_luaL_error(L_, "error when parsing lane function code"); | 1171 | raise_luaL_error(L_, "error when parsing lane function code"); |
| 1142 | } | 1172 | } |
| 1143 | } else { | 1173 | } else { |
| @@ -1152,7 +1182,7 @@ LUAG_FUNC(lane_new) | |||
| 1152 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END(U))); | 1182 | DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: transfer lane arguments\n" INDENT_END(U))); |
| 1153 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); | 1183 | DEBUGSPEW_CODE(DebugSpewIndentScope scope{ U }); |
| 1154 | InterCopyContext c{ U, DestState{ L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; | 1184 | InterCopyContext c{ U, DestState{ L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; |
| 1155 | InterCopyResult const res{ c.inter_move(nargs) }; // L_: [7 args] L2: func args... | 1185 | InterCopyResult const res{ c.inter_move(nargs) }; // L_: [8 args] L2: func args... |
| 1156 | if (res != InterCopyResult::Success) { | 1186 | if (res != InterCopyResult::Success) { |
| 1157 | raise_luaL_error(L_, "tried to copy unsupported types"); | 1187 | raise_luaL_error(L_, "tried to copy unsupported types"); |
| 1158 | } | 1188 | } |
| @@ -1161,12 +1191,12 @@ LUAG_FUNC(lane_new) | |||
| 1161 | LUA_ASSERT(L_, lua_gettop(L_) == kFixedArgsIdx); | 1191 | LUA_ASSERT(L_, lua_gettop(L_) == kFixedArgsIdx); |
| 1162 | 1192 | ||
| 1163 | // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). | 1193 | // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). |
| 1164 | kLanePointerRegKey.setValue(L2, [lane](lua_State* L_) { lua_pushlightuserdata(L_, lane); }); // L_: [7 args] L2: func args... | 1194 | kLanePointerRegKey.setValue(L2, [lane](lua_State* L_) { lua_pushlightuserdata(L_, lane); }); // L_: [8 args] L2: func args... |
| 1165 | STACK_CHECK(L2, 1 + nargs); | 1195 | STACK_CHECK(L2, 1 + nargs); |
| 1166 | 1196 | ||
| 1167 | STACK_CHECK_RESET_REL(L_, 0); | 1197 | STACK_CHECK_RESET_REL(L_, 0); |
| 1168 | // all went well, the lane's thread can start working | 1198 | // all went well, the lane's thread can start working |
| 1169 | onExit.success(); // L_: [7 args] lane L2: <living its own life> | 1199 | onExit.success(); // L_: [8 args] lane L2: <living its own life> |
| 1170 | // we should have the lane userdata on top of the stack | 1200 | // we should have the lane userdata on top of the stack |
| 1171 | STACK_CHECK(L_, 1); | 1201 | STACK_CHECK(L_, 1); |
| 1172 | return 1; | 1202 | return 1; |
| @@ -1298,7 +1328,7 @@ LUAG_FUNC(thread_join) | |||
| 1298 | Universe* const U{ lane->U }; | 1328 | Universe* const U{ lane->U }; |
| 1299 | // debugName is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed | 1329 | // debugName is a pointer to string possibly interned in the lane's state, that no longer exists when the state is closed |
| 1300 | // so store it in the userdata uservalue at a key that can't possibly collide | 1330 | // so store it in the userdata uservalue at a key that can't possibly collide |
| 1301 | securize_debug_threadname(L_, lane); | 1331 | lane->securizeDebugName(L_); |
| 1302 | switch (lane->status) { | 1332 | switch (lane->status) { |
| 1303 | case Lane::Done: | 1333 | case Lane::Done: |
| 1304 | { | 1334 | { |
diff --git a/src/lanes.lua b/src/lanes.lua index 8a2592b..f95dddf 100644 --- a/src/lanes.lua +++ b/src/lanes.lua | |||
| @@ -208,25 +208,29 @@ end | |||
| 208 | 208 | ||
| 209 | local opt_validators = | 209 | local opt_validators = |
| 210 | { | 210 | { |
| 211 | priority = function(v_) | 211 | gc_cb = function(v_) |
| 212 | local tv = type(v_) | 212 | local tv = type(v_) |
| 213 | return (tv == "number") and v_ or raise_option_error("priority", tv, v_) | 213 | return (tv == "function") and v_ or raise_option_error("gc_cb", tv, v_) |
| 214 | end, | 214 | end, |
| 215 | globals = function(v_) | 215 | globals = function(v_) |
| 216 | local tv = type(v_) | 216 | local tv = type(v_) |
| 217 | return (tv == "table") and v_ or raise_option_error("globals", tv, v_) | 217 | return (tv == "table") and v_ or raise_option_error("globals", tv, v_) |
| 218 | end, | 218 | end, |
| 219 | name = function(v_) | ||
| 220 | local tv = type(v_) | ||
| 221 | return (tv == "string") and v_ or raise_option_error("name", tv, v_) | ||
| 222 | end, | ||
| 219 | package = function(v_) | 223 | package = function(v_) |
| 220 | local tv = type(v_) | 224 | local tv = type(v_) |
| 221 | return (tv == "table") and v_ or raise_option_error("package", tv, v_) | 225 | return (tv == "table") and v_ or raise_option_error("package", tv, v_) |
| 222 | end, | 226 | end, |
| 223 | required = function(v_) | 227 | priority = function(v_) |
| 224 | local tv = type(v_) | 228 | local tv = type(v_) |
| 225 | return (tv == "table") and v_ or raise_option_error("required", tv, v_) | 229 | return (tv == "number") and v_ or raise_option_error("priority", tv, v_) |
| 226 | end, | 230 | end, |
| 227 | gc_cb = function(v_) | 231 | required = function(v_) |
| 228 | local tv = type(v_) | 232 | local tv = type(v_) |
| 229 | return (tv == "function") and v_ or raise_option_error("gc_cb", tv, v_) | 233 | return (tv == "table") and v_ or raise_option_error("required", tv, v_) |
| 230 | end | 234 | end |
| 231 | } | 235 | } |
| 232 | 236 | ||
| @@ -338,10 +342,10 @@ local gen = function(...) | |||
| 338 | end | 342 | end |
| 339 | 343 | ||
| 340 | local core_lane_new = assert(core.lane_new) | 344 | local core_lane_new = assert(core.lane_new) |
| 341 | local priority, globals, package, required, gc_cb = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb | 345 | local priority, globals, package, required, gc_cb, name = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name |
| 342 | return function(...) | 346 | return function(...) |
| 343 | -- must pass functions args last else they will be truncated to the first one | 347 | -- must pass functions args last else they will be truncated to the first one |
| 344 | return core_lane_new(func, libs, priority, globals, package, required, gc_cb, ...) | 348 | return core_lane_new(func, libs, priority, globals, package, required, gc_cb, name, ...) |
| 345 | end | 349 | end |
| 346 | end -- gen() | 350 | end -- gen() |
| 347 | 351 | ||
| @@ -569,7 +573,7 @@ local configure_timers = function() | |||
| 569 | end | 573 | end |
| 570 | end | 574 | end |
| 571 | end -- timer_body() | 575 | end -- timer_body() |
| 572 | timer_lane = gen("*", { package= {}, priority = core.max_prio}, timer_body)() -- "*" instead of "io,package" for LuaJIT compatibility... | 576 | timer_lane = gen("*", { package= {}, priority = core.max_prio, name = "LanesTimer"}, timer_body)() -- "*" instead of "io,package" for LuaJIT compatibility... |
| 573 | end -- first_time | 577 | end -- first_time |
| 574 | 578 | ||
| 575 | ----- | 579 | ----- |
diff --git a/src/lanes_private.h b/src/lanes_private.h index 01630ba..309b632 100644 --- a/src/lanes_private.h +++ b/src/lanes_private.h | |||
| @@ -89,6 +89,8 @@ class Lane | |||
| 89 | [[nodiscard]] bool waitForCompletion(lua_Duration duration_); | 89 | [[nodiscard]] bool waitForCompletion(lua_Duration duration_); |
| 90 | void startThread(int priority_); | 90 | void startThread(int priority_); |
| 91 | void pushThreadStatus(lua_State* L_); | 91 | void pushThreadStatus(lua_State* L_); |
| 92 | void changeDebugName(int nameIdx_); | ||
| 93 | void securizeDebugName(lua_State* L_); | ||
| 92 | }; | 94 | }; |
| 93 | 95 | ||
| 94 | // xxh64 of string "kLanePointerRegKey" generated at https://www.pelock.com/products/hash-calculator | 96 | // xxh64 of string "kLanePointerRegKey" generated at https://www.pelock.com/products/hash-calculator |
