aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lanes.cpp2
-rw-r--r--src/state.cpp68
-rw-r--r--src/state.h2
-rw-r--r--src/tools.cpp57
-rw-r--r--src/tools.h4
-rw-r--r--src/universe.cpp2
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 */
89void 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 @@
7enum class LookupMode; 7enum class LookupMode;
8class Universe; 8class Universe;
9 9
10void 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
532namespace 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
27void populate_func_lookup_table(lua_State* const L_, int const i_, std::string_view const& name_); 27void populate_func_lookup_table(lua_State* const L_, int const i_, std::string_view const& name_);
28 28
29namespace 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