Lua C-一种不错的LuaJIT兼容方式,将错误抛出到恢复协程中

时间:2019-03-27 13:28:48

标签: lua coroutine

简而言之,虽然代码似乎可以正常工作,但我很好奇是否存在比目前为止更少的骇人听闻的方法。

假设您通过lua_newthread创建了一个协程,然后通过cclocure将其从lua_yield中挂起。您的程序花了非Lua代码一圈,现在是时候通过lua_resume恢复协程了,但是-假设提供Lua代码的参数极其非法,我们应该给它指明一个错误。

您可能知道,除非当前正在运行,否则无法在状态上调用lua_error(或luaL_error)。因此状态必须恢复,但立即会被错误击中。

在5.3中,您将使用lua_yieldk,提供一个延续函数,并在其中调用lua_error或luaL_error。等等。

但是,可惜-LuaJIT没有实现lua_yieldk,所以我们还有什么选择?

  1. 一次性挂钩

    假设错误消息存储在char error_text[256]中。然后,我们可以在恢复之前立即绑定每个指令的钩子,

    lua_sethook(L, throw_error, LUA_MASKCOUNT, 1);
    int result = lua_resume(L, NULL, ret_count);
    

    然后解开钩子并在其中抛出错误

    void throw_error(lua_State *L, lua_Debug *ar) {
        lua_sethook(L, throw_error, 0, 0);
        if (error_text == nullptr) return; // trust no one, especially yourself
        luaL_error(L, "%s", error_text);
    }
    

    如果需要清理字符串,您当然更喜欢在调用error_text之前将luaL_where(L, 1)连接到_error,就像lua_errorluaL_error一样跳远,因此将是您的函数要做的最后一件事。

  2. Lua侧包装器

    假设您决定对此进行某种程度的类似于node.js的操作,并使用一对error, result对C代码进行恢复,以便可以使用像这样的包装器功能

    function some(arg)
        local e, r = some_native(arg)
        if (e) then
            error(e)
        else
            return r
        end
    end
    

    或者完全重构您的API,以便也可以使用相同的模式来处理错误,但这又是另一回事了。

选项1似乎不那么笨拙。

选项2似乎不太可能引起任何麻烦。

我不禁感到自己有一种更好的方法被我忽略了(毕竟lua_yieldk是相对较新的补充)。

0 个答案:

没有答案