6

当我使用以下脚本时:

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

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

4

3 回答 3

4

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

@AterCattus 这是 LuaJIT(和标准 Lua 5.1 解释器)中的一个已知限制,即 require() 内置函数当前实现为 C 内置函数,您无法通过该 C 内置函数启动 yield。

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

于 2015-05-13T14:37:20.143 回答
4

smtp.send使用 LuaSocket 的socket.protect函数来处理内部错误。这个函数是用 C 实现的,并且在当前版本中不允许屈服(git HEAD 中的版本现在允许在 Lua 5.2+ 上屈服,请参阅此处的讨论)。显然有人试图从中屈服。在etc/dispatch.luaLuaSocket 包中(最好使用 git HEAD 版本),有一个替换函数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")
-- ...
于 2015-05-14T06:53:20.023 回答
2

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

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

于 2015-05-08T15:43:02.930 回答