diff options
Diffstat (limited to 'src/tools.cpp')
-rw-r--r-- | src/tools.cpp | 57 |
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 | |||
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 | |||