aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deep_test/deeptest.lua5
-rw-r--r--docs/index.html21
-rw-r--r--src/lanes.cpp134
-rw-r--r--src/lanes.lua22
-rw-r--r--src/lanes_private.h2
5 files changed, 114 insertions, 70 deletions
diff --git a/deep_test/deeptest.lua b/deep_test/deeptest.lua
index 09b638c..33de003 100644
--- a/deep_test/deeptest.lua
+++ b/deep_test/deeptest.lua
@@ -7,7 +7,7 @@ local dt = lanes.require "deep_test"
7local test_deep = true 7local test_deep = true
8local test_clonable = true 8local test_clonable = true
9local test_uvtype = "string" 9local test_uvtype = "string"
10local nupvals = _VERSION == "Lua 5.4" and 3 or 1 10local nupvals = _VERSION == "Lua 5.4" and 2 or 1
11 11
12local makeUserValue = function( obj_) 12local makeUserValue = function( obj_)
13 if test_uvtype == "string" then 13 if test_uvtype == "string" then
@@ -43,8 +43,7 @@ local performTest = function( obj_)
43 obj_:setuv( 1, makeUserValue( obj_)) 43 obj_:setuv( 1, makeUserValue( obj_))
44 -- lua 5.4 supports multiple uservalues of arbitrary types 44 -- lua 5.4 supports multiple uservalues of arbitrary types
45 if nupvals > 1 then 45 if nupvals > 1 then
46 -- keep uv #2 as nil 46 obj_:setuv( 2, "ENDUV")
47 obj_:setuv( 3, "ENDUV")
48 end 47 end
49 48
50 local t = 49 local t =
diff --git a/docs/index.html b/docs/index.html
index ed1c367..f08947e 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -684,7 +684,7 @@
684 <td>table</td> 684 <td>table</td>
685 <td> 685 <td>
686 Sets the globals table for the launched threads. This can be used for giving them constants. The key/value pairs of <tt>table</tt> are transfered in the lane globals after the libraries have been loaded and the modules required. 686 Sets the globals table for the launched threads. This can be used for giving them constants. The key/value pairs of <tt>table</tt> are transfered in the lane globals after the libraries have been loaded and the modules required.
687 <br/> 687 <br />
688 The global values of different lanes are in no manner connected; modifying one will only affect the particular lane. 688 The global values of different lanes are in no manner connected; modifying one will only affect the particular lane.
689 </td> 689 </td>
690 </tr> 690 </tr>
@@ -698,11 +698,20 @@
698 These tables are built from the modules listed here. <tt>required</tt> must be a list of strings, each one being the name of a module to be required. Each module is required with <tt>require()</tt> before the lanes function is invoked. 698 These tables are built from the modules listed here. <tt>required</tt> must be a list of strings, each one being the name of a module to be required. Each module is required with <tt>require()</tt> before the lanes function is invoked.
699 So, from the required module's point of view, requiring it manually from inside the lane body or having it required this way doesn't change anything. From the lane body's point of view, the only difference is that a module not creating a global won't be accessible. 699 So, from the required module's point of view, requiring it manually from inside the lane body or having it required this way doesn't change anything. From the lane body's point of view, the only difference is that a module not creating a global won't be accessible.
700 Therefore, a lane body will also have to require a module manually, but this won't do anything more (see Lua's <tt>require</tt> documentation). 700 Therefore, a lane body will also have to require a module manually, but this won't do anything more (see Lua's <tt>require</tt> documentation).
701 <br/> 701 <br />
702 ATTEMPTING TO TRANSFER A FUNCTION REGISTERED BY A MODULE NOT LISTED HERE WILL RAISE AN ERROR. 702 ATTEMPTING TO TRANSFER A FUNCTION REGISTERED BY A MODULE NOT LISTED HERE WILL RAISE AN ERROR.
703 </td> 703 </td>
704 </tr> 704 </tr>
705 <tr id="Tr1" valign=top> 705 <tr id=".name" valign=top>
706 <td>
707 <code>.name</code>
708 </td>
709 <td>string</td>
710 <td>
711 Name of the lane. If <tt>"auto"</tt>, name is built from <tt>ar.short_src:ar.linedefined</tt>. Can be changed later from the inside of the lane with <tt>set_debug_threadname()</tt> (see below).
712 </td>
713 </tr>
714 <tr id=".gc_cb" valign=top>
706 <td> 715 <td>
707 <code>.gc_cb</code> 716 <code>.gc_cb</code>
708 </td> 717 </td>
@@ -719,9 +728,9 @@
719 <td> 728 <td>
720 The priority of lanes generated in the range -3..+3 (default is 0). 729 The priority of lanes generated in the range -3..+3 (default is 0).
721 These values are a mapping over the actual priority range of the underlying implementation. 730 These values are a mapping over the actual priority range of the underlying implementation.
722 <br/> 731 <br />
723 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode. 732 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.
724 <br/> 733 <br />
725 A lane can also change its own thread priority dynamically with <a href="#priority"><tt>lanes.set_thread_priority()</tt></a>. 734 A lane can also change its own thread priority dynamically with <a href="#priority"><tt>lanes.set_thread_priority()</tt></a>.
726 </td> 735 </td>
727 </tr> 736 </tr>
@@ -732,7 +741,7 @@
732 <td> table</td> 741 <td> table</td>
733 <td> 742 <td>
734 Specifying it when <code>libs_str</code> doesn't cause the <code>package</code> library to be loaded will generate an error. 743 Specifying it when <code>libs_str</code> doesn't cause the <code>package</code> library to be loaded will generate an error.
735 <br/> 744 <br />
736 If not specified, the created lane will receive the current values of <tt>package</tt>. Only <tt>path</tt>, <tt>cpath</tt>, <tt>preload</tt> and <tt>loaders</tt> (Lua 5.1)/<tt>searchers</tt> (Lua 5.2) are transfered. 745 If not specified, the created lane will receive the current values of <tt>package</tt>. Only <tt>path</tt>, <tt>cpath</tt>, <tt>preload</tt> and <tt>loaders</tt> (Lua 5.1)/<tt>searchers</tt> (Lua 5.2) are transfered.
737 </td> 746 </td>
738 </tr> 747 </tr>
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