aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-05-06 15:37:44 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2024-05-13 18:15:46 +0200
commit2c69c99da47b1d708606da713433608c73ecdb88 (patch)
treec355f51dd8cfc261ab8589cf00d49eedf0c4da0b /src
parentc9db798d184ceb8b3913a2f15d454f20ea978864 (diff)
downloadlanes-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.cpp134
-rw-r--r--src/lanes.lua22
-rw-r--r--src/lanes_private.h2
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
205static void securize_debug_threadname(lua_State* L_, Lane* lane_) 205void 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
677void 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
677LUAG_FUNC(set_debug_threadname) 699LUAG_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//
918LUAG_FUNC(lane_new) 932LUAG_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
209local opt_validators = 209local 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
346end -- gen() 350end -- 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