可以搜索 Lua Sandbox 的实现;例如,这个wiki 页面和SO question提供了一些指示。请注意,沙盒的大部分工作都集中在不允许您执行错误代码上,但不一定要防止无限循环。为了更好地控制,您可能需要将 Lua 沙盒与LXC或cpulimit 之类的东西结合起来。(根据评论不相关)
如果您正在寻找基于 Lua 的、轻量级的但不一定 100% 万无一失的东西,那么您可以尝试在单独的协程中运行您的客户端代码,并在该协程上设置一个调试钩子,该钩子将每第 N 行触发一次。在那个钩子中,您可以检查您正在运行的进程是否超出了它的报价。您还需要处理新启动的协程,因为它们需要设置自己的钩子(您需要禁用 coroutine.create/wrap 或用设置您需要的调试钩子的东西替换它们)。
这种情况下的代码可能如下所示:
local coro = coroutine.create(client_func)
debug.sethook(coro, debug_hook, "l", 1000) -- trigger hook on every 1000th line
这不是万无一失的,因为它可能会阻塞某些 IO 操作,并且调试钩子在那里无济于事。
[根据更新的问题和评论进行编辑]
在“无基于 lua 代码协程的控制器”和“无外部进程控制机制”之间,我认为您别无选择。可能您唯一的选择是为每个用户脚本运行一个虚拟机,并以某种方式给这些虚拟机打勾(最近有一个关于 SO 的问题,但我找不到)。在走这条路之前,我仍然会尝试使用协程(应该可以轻松扩展到数万;Tir 声称支持 1M 活跃用户和基于协程的架构)。
该机制大致如下所示:您安装调试钩子,如上所示,然后从该钩子返回到控制器,然后控制器决定要恢复的其他协程(用户脚本)。我在我一直在开发的Lua 调试器中使用了这种机制(尽管它只适用于一个客户端脚本)。这并不能保护您免受可能阻塞的 IO 调用的影响,因此您可能仍需要在 VM 级别有一个看门狗来查看它是否被阻塞的时间超过了需要的时间。
如果您需要序列化和反序列化运行代码片段以保留上值等,那么Pluto可能是您唯一的选择。