diff options
-rw-r--r-- | src/lanes.cpp | 2 | ||||
-rw-r--r-- | src/state.cpp | 68 | ||||
-rw-r--r-- | src/state.h | 2 | ||||
-rw-r--r-- | src/tools.cpp | 57 | ||||
-rw-r--r-- | src/tools.h | 4 | ||||
-rw-r--r-- | src/universe.cpp | 2 |
6 files changed, 64 insertions, 71 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp index bd5f69e..a82e4ba 100644 --- a/src/lanes.cpp +++ b/src/lanes.cpp | |||
@@ -684,7 +684,7 @@ LUAG_FUNC(configure) | |||
684 | STACK_CHECK(L_, 1); | 684 | STACK_CHECK(L_, 1); |
685 | 685 | ||
686 | // Serialize calls to 'require' from now on, also in the primary state | 686 | // Serialize calls to 'require' from now on, also in the primary state |
687 | serialize_require(L_); | 687 | tools::SerializeRequire(L_); |
688 | 688 | ||
689 | // Retrieve main module interface table | 689 | // Retrieve main module interface table |
690 | lua_pushvalue(L_, lua_upvalueindex(2)); // L_: settings M | 690 | lua_pushvalue(L_, lua_upvalueindex(2)); // L_: settings M |
diff --git a/src/state.cpp b/src/state.cpp index d9f5499..8520346 100644 --- a/src/state.cpp +++ b/src/state.cpp | |||
@@ -43,72 +43,6 @@ THE SOFTWARE. | |||
43 | 43 | ||
44 | // ################################################################################################# | 44 | // ################################################################################################# |
45 | 45 | ||
46 | /*---=== Serialize require ===--- | ||
47 | */ | ||
48 | |||
49 | //--- | ||
50 | // [val,...]= new_require( ... ) | ||
51 | // | ||
52 | // Call 'old_require' but only one lane at a time. | ||
53 | // | ||
54 | // Upvalues: [1]: original 'require' function | ||
55 | // | ||
56 | [[nodiscard]] static int luaG_new_require(lua_State* L_) | ||
57 | { | ||
58 | int const _args{ lua_gettop(L_) }; // L_: args | ||
59 | Universe* const _U{ universe_get(L_) }; | ||
60 | //[[maybe_unused]] std::string_view const _modname{ luaL_checkstringview(L_, 1) }; | ||
61 | |||
62 | STACK_GROW(L_, 1); | ||
63 | |||
64 | lua_pushvalue(L_, lua_upvalueindex(1)); // L_: args require | ||
65 | lua_insert(L_, 1); // L_: require args | ||
66 | |||
67 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | ||
68 | // leave us locked, blocking any future 'require' calls from other lanes. | ||
69 | |||
70 | _U->requireMutex.lock(); | ||
71 | // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET | ||
72 | LuaError const _rc{ lua_pcall(L_, _args, LUA_MULTRET, 0 /*errfunc*/) }; // L_: err|result(s) | ||
73 | _U->requireMutex.unlock(); | ||
74 | |||
75 | // the required module (or an error message) is left on the stack as returned value by original require function | ||
76 | |||
77 | if (_rc != LuaError::OK) { // LUA_ERRRUN / LUA_ERRMEM ? | ||
78 | raise_lua_error(L_); | ||
79 | } | ||
80 | // should be 1 for Lua <= 5.3, 1 or 2 starting with Lua 5.4 | ||
81 | return lua_gettop(L_); // L_: result(s) | ||
82 | } | ||
83 | |||
84 | // ################################################################################################# | ||
85 | |||
86 | /* | ||
87 | * Serialize calls to 'require', if it exists | ||
88 | */ | ||
89 | void serialize_require(lua_State* L_) | ||
90 | { | ||
91 | STACK_GROW(L_, 1); | ||
92 | STACK_CHECK_START_REL(L_, 0); | ||
93 | DEBUGSPEW_CODE(DebugSpew(universe_get(L_)) << "serializing require()" << std::endl); | ||
94 | |||
95 | // Check 'require' is there and not already wrapped; if not, do nothing | ||
96 | // | ||
97 | lua_getglobal(L_, "require"); | ||
98 | if (lua_isfunction(L_, -1) && lua_tocfunction(L_, -1) != luaG_new_require) { | ||
99 | // [-1]: original 'require' function | ||
100 | lua_pushcclosure(L_, luaG_new_require, 1 /*upvalues*/); | ||
101 | lua_setglobal(L_, "require"); | ||
102 | } else { | ||
103 | // [-1]: nil | ||
104 | lua_pop(L_, 1); | ||
105 | } | ||
106 | |||
107 | STACK_CHECK(L_, 0); | ||
108 | } | ||
109 | |||
110 | // ################################################################################################# | ||
111 | |||
112 | /*---=== luaG_newstate ===---*/ | 46 | /*---=== luaG_newstate ===---*/ |
113 | 47 | ||
114 | [[nodiscard]] static int require_lanes_core(lua_State* L_) | 48 | [[nodiscard]] static int require_lanes_core(lua_State* L_) |
@@ -397,7 +331,7 @@ lua_State* luaG_newstate(Universe* U_, SourceState from_, std::optional<std::str | |||
397 | } | 331 | } |
398 | lua_gc(_L, LUA_GCRESTART, 0); | 332 | lua_gc(_L, LUA_GCRESTART, 0); |
399 | 333 | ||
400 | serialize_require(_L); | 334 | tools::SerializeRequire(_L); |
401 | 335 | ||
402 | // call this after the base libraries are loaded and GC is restarted | 336 | // call this after the base libraries are loaded and GC is restarted |
403 | // will raise an error in from_ in case of problem | 337 | // will raise an error in from_ in case of problem |
diff --git a/src/state.h b/src/state.h index a97fdab..ff70196 100644 --- a/src/state.h +++ b/src/state.h | |||
@@ -7,8 +7,6 @@ | |||
7 | enum class LookupMode; | 7 | enum class LookupMode; |
8 | class Universe; | 8 | class Universe; |
9 | 9 | ||
10 | void serialize_require(lua_State* L_); | ||
11 | |||
12 | // ################################################################################################# | 10 | // ################################################################################################# |
13 | 11 | ||
14 | [[nodiscard]] lua_State* create_state(Universe* U_, lua_State* from_); | 12 | [[nodiscard]] lua_State* create_state(Universe* U_, lua_State* from_); |
diff --git a/src/tools.cpp b/src/tools.cpp index 0b10464..d270aac 100644 --- a/src/tools.cpp +++ b/src/tools.cpp | |||
@@ -526,3 +526,60 @@ int luaG_nameof(lua_State* L_) | |||
526 | lua_replace(L_, -3); // L_: "type" "result" | 526 | lua_replace(L_, -3); // L_: "type" "result" |
527 | return 2; | 527 | return 2; |
528 | } | 528 | } |
529 | |||
530 | // ################################################################################################# | ||
531 | |||
532 | namespace tools { | ||
533 | |||
534 | // Serialize calls to 'require', if it exists | ||
535 | void SerializeRequire(lua_State* L_) | ||
536 | { | ||
537 | static constexpr lua_CFunction _lockedRequire{ | ||
538 | +[](lua_State* L_) | ||
539 | { | ||
540 | int const _args{ lua_gettop(L_) }; // L_: args... | ||
541 | //[[maybe_unused]] std::string_view const _modname{ luaL_checkstringview(L_, 1) }; | ||
542 | |||
543 | STACK_GROW(L_, 1); | ||
544 | |||
545 | lua_pushvalue(L_, lua_upvalueindex(1)); // L_: args... require | ||
546 | lua_insert(L_, 1); // L_: require args... | ||
547 | |||
548 | // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would | ||
549 | // leave us locked, blocking any future 'require' calls from other lanes. | ||
550 | LuaError const _rc{ std::invoke( | ||
551 | [L = L_, args = _args]() | ||
552 | { | ||
553 | std::lock_guard _guard{ universe_get(L)->requireMutex }; | ||
554 | // starting with Lua 5.4, require may return a second optional value, so we need LUA_MULTRET | ||
555 | return lua_pcall(L, args, LUA_MULTRET, 0 /*errfunc*/); // L_: err|result(s) | ||
556 | }) | ||
557 | }; | ||
558 | |||
559 | // the required module (or an error message) is left on the stack as returned value by original require function | ||
560 | |||
561 | if (_rc != LuaError::OK) { // LUA_ERRRUN / LUA_ERRMEM ? | ||
562 | raise_lua_error(L_); | ||
563 | } | ||
564 | // should be 1 for Lua <= 5.3, 1 or 2 starting with Lua 5.4 | ||
565 | return lua_gettop(L_); // L_: result(s) | ||
566 | } | ||
567 | }; | ||
568 | |||
569 | STACK_GROW(L_, 1); | ||
570 | STACK_CHECK_START_REL(L_, 0); | ||
571 | DEBUGSPEW_CODE(DebugSpew(universe_get(L_)) << "serializing require()" << std::endl); | ||
572 | |||
573 | // Check 'require' is there and not already wrapped; if not, do nothing | ||
574 | lua_getglobal(L_, "require"); // L_: _G.require()|nil | ||
575 | if (lua_isfunction(L_, -1) && lua_tocfunction(L_, -1) != _lockedRequire) { | ||
576 | lua_pushcclosure(L_, _lockedRequire, 1 /*upvalues*/); // L_: _lockedRequire() | ||
577 | lua_setglobal(L_, "require"); // L_: | ||
578 | } else { | ||
579 | lua_pop(L_, 1); // L_: | ||
580 | } | ||
581 | |||
582 | STACK_CHECK(L_, 0); | ||
583 | } | ||
584 | } // namespace tools | ||
585 | |||
diff --git a/src/tools.h b/src/tools.h index 4857eeb..3659b42 100644 --- a/src/tools.h +++ b/src/tools.h | |||
@@ -26,6 +26,10 @@ enum class FuncSubType | |||
26 | 26 | ||
27 | void populate_func_lookup_table(lua_State* const L_, int const i_, std::string_view const& name_); | 27 | void populate_func_lookup_table(lua_State* const L_, int const i_, std::string_view const& name_); |
28 | 28 | ||
29 | namespace tools { | ||
30 | void SerializeRequire(lua_State* L_); | ||
31 | } // namespace tools | ||
32 | |||
29 | // ################################################################################################# | 33 | // ################################################################################################# |
30 | 34 | ||
31 | // xxh64 of string "kConfigRegKey" generated at https://www.pelock.com/products/hash-calculator | 35 | // xxh64 of string "kConfigRegKey" generated at https://www.pelock.com/products/hash-calculator |
diff --git a/src/universe.cpp b/src/universe.cpp index 620be79..172cc4c 100644 --- a/src/universe.cpp +++ b/src/universe.cpp | |||
@@ -287,7 +287,7 @@ void Universe::initializeKeepers(lua_State* L_) | |||
287 | luaL_requiref(_K, LUA_LOADLIBNAME, luaopen_package, 1); // L_: settings K: package | 287 | luaL_requiref(_K, LUA_LOADLIBNAME, luaopen_package, 1); // L_: settings K: package |
288 | lua_pop(_K, 1); // L_: settings K: | 288 | lua_pop(_K, 1); // L_: settings K: |
289 | STACK_CHECK(_K, 0); | 289 | STACK_CHECK(_K, 0); |
290 | serialize_require(_K); | 290 | tools::SerializeRequire(_K); |
291 | STACK_CHECK(_K, 0); | 291 | STACK_CHECK(_K, 0); |
292 | 292 | ||
293 | // copy package.path and package.cpath from the source state | 293 | // copy package.path and package.cpath from the source state |