aboutsummaryrefslogtreecommitdiff
path: root/src/tools.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools.cpp')
-rw-r--r--src/tools.cpp57
1 files changed, 57 insertions, 0 deletions
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