【问题标题】:Luasocket + nginx error - lua entry thread aborted: runtime error: attempt to yield across C-call boundaryLuasocket + nginx 错误 - lua 入口线程中止:运行时错误:尝试跨 C 调用边界让步
【发布时间】:2015-07-18 15:50:29
【问题描述】:

当我使用以下脚本时:

local smtp = require("socket.smtp")
local from = "from@host"
local rcpt = "rcpt@host"
local msg = {
  headers = {
    to = rcpt,
    subject = "Hi"
  },
  body = "Hello"
}
smtp.send{from = from,rcpt = rcpt,source = smtp.message(msg)}

我收到一条错误消息:lua entry thread aborted: runtime error: attempt to yield across C-call boundary

我正在使用从luarocks 安装的最新luasocket 和 Lua 5.1,使用 LuaJIT 2.1 编译的 nginx。是什么导致了此错误消息,我该如何解决?

【问题讨论】:

  • 你有一个完整的例子,我们可以插入content_by_lua_file 看看它失败的地方吗?它是否在smtp.sendrequire 行上失败?我怀疑是前者,但想确认一下。
  • 这几乎是完整的示例。它在发送功能上失败。

标签: nginx lua luajit luasocket luarocks


【解决方案1】:

smtp.send 使用 LuaSocket 的 socket.protect 函数来处理内部错误。这个函数在 C 中实现,并且在当前版本中不允许屈服(git HEAD 中的版本现在允许在 Lua 5.2+ 上屈服,参见讨论here)。显然有人试图从中屈服。在 LuaSocket 包中的 etc/dispatch.lua 中(最好使用 git HEAD 版本)有一个 replacement function for socket.protect 应该允许在所有 Lua 版本上屈服(以额外的临时协程为代价)。您可以尝试用 Lua 函数替换 C 函数,如下所示:

local socket = require("socket")
local base = _G
-- paste modified socket.protect function here

-- continue with your own code:
local smtp = require("socket.smtp")
-- ...

【讨论】:

  • someone tries to yield from within it 是问题的症结所在。如果相同的脚本使用 luasocket 包从独立的 LuaJIT 工作,它必须与 ngx_lua 相关。就我而言,问题是使用了 ngx_lua 套接字库(它会隐式产生),而解决方法是使用库存的 luasocket 库。
  • 消除yield 也可以解决问题。但是,你是怎么做的? socket.smtp 模块已经尝试通过require("socket") 加载默认的 LuaSocket 函数——它甚至不知道 Nginx 版本。你如何防止 Nginx 替换 LuaSocket 的内部函数(显然)?即使您管理,原始的 LuaSocket 函数也是阻塞的(这可能是 Nginx 首先实现自己的基于协程的调度程序的原因)...
【解决方案2】:

这是由 LuaJIT 和 socket.smtp 的组合使用引起的,它启动了一个协程。来自https://github.com/openresty/lua-nginx-module/issues/376

@AterCattus 这是 LuaJIT(以及标准 Lua 5.1 解释器),require() 内置当前实现为 C 内置的,您无法在其中启动收益。

看起来最好的解决方法可能是使用 require.lua 的这个实现:https://github.com/pygy/require.lua。它是用纯 Lua 而不是 C 编写的,以解决 LuaJIT 的这个问题。

【讨论】:

  • 嗯,我下载了require-lua 0.1.7-2并通过luarocks安装,然后将require = require"require".require放在我的脚本顶部。我仍然收到同样的错误:来自 smtp.send 函数的attempt to yield across C-call boundary
  • arby,看起来@siffiejoe 的答案是正确的。如果 socket.protect 是用 C 编写的,那么这就是真正的潜在问题!
【解决方案3】:

我在类似的情况下看到过这条消息;在我的例子中,它与 ngx_lua 的设计有关,它实现了自己的协程调度程序。这意味着sock:receive 不会阻塞,而是对调度程序隐含yield,因此,如果调用sock:receive 时使用堆栈上的C 函数,您可能会得到你看到的错误。

在我的情况下,我从调试钩子进行sock:receive 调用并收到此错误,直到我切换到使用我自己版本的 luasocket 中的套接字方法,但没有产生。我会检查socket.smtp 是否正在使用“普通”版本的 luasocket。

【讨论】:

    猜你喜欢
    • 2023-01-24
    • 1970-01-01
    • 2021-01-01
    • 2016-07-26
    • 2021-04-16
    • 2018-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-01-06
    相关资源
    最近更新 更多