diff options
author | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-06 15:37:44 +0200 |
---|---|---|
committer | Benoit Germain <benoit.germain@ubisoft.com> | 2024-05-13 18:15:46 +0200 |
commit | 2c69c99da47b1d708606da713433608c73ecdb88 (patch) | |
tree | c355f51dd8cfc261ab8589cf00d49eedf0c4da0b /src | |
parent | c9db798d184ceb8b3913a2f15d454f20ea978864 (diff) | |
download | lanes-2c69c99da47b1d708606da713433608c73ecdb88.tar.gz lanes-2c69c99da47b1d708606da713433608c73ecdb88.tar.bz2 lanes-2c69c99da47b1d708606da713433608c73ecdb88.zip |
New lane generator option opt_tbl.name
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 |