lua_tothread

Lua中协程与钩子函数的问题
本文探讨了在Lua 5.1.4版本中使用协程(coroutine)和钩子函数(testHook)时遇到的问题。当从C调用Lua_State并设置行钩子(line hook)时,程序会在lvm.c的第71行崩溃。通过提供复现问题的代码示例,作者希望找到问题的原因及解决方案。
http://arcemu.org/forums/index.php?showtopic=19327


    Hello.

Call to lua function from c using yielded lua_State works fine. But same call with line hook set crashes in lvm.c line 71.
    Lua version 5.1.4

    Code to reproduce:

#include <stdio.h>

extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

void testHook(lua_State *L, lua_Debug *ar)
{
    static int c = 0;
    c++;
}

int main(void)
{
    lua_State* l = lua_open();
    luaopen_base(l);

lua_sethook(l, testHook, LUA_MASKLINE, 0); //works fine when this line is commented
    const char* script =   "function func()    \
                                print('func1')    \
                            end    \
                            function threadFunc()    \
                                print('before yield')    \
                                coroutine.yield()    \
                                print('after yield')    \
                            end    \
                            thread = coroutine.create(threadFunc)    \
                            coroutine.resume(thread)    \
                            ";
    int rez = luaL_dostring(l, script);
    if (rez) {
        return 1;
    }

    lua_getglobal(l, "thread");
    lua_State* thread = lua_tothread(l, -1);

lua_getglobal(thread, "func"); //will work too if "l" state is used....
    if (lua_pcall(thread, 0, 0, 0)) {
        return 1;
    }

    lua_resume(thread, 0);

    return 0;
}

I believe that it should either work in both cases (wonder how?...) or report error even if no hook set...
--
WBR, Anatoly Ahmedov
这段代码是一个名为 `lua_call_luci` 的 Lua C API 函数,用于调用 Lua 函数并处理其返回值。以下是代码的逐步解析: --- ### **1. 函数签名** ```c lua_call_luci(lua_State *L) ``` - **作用**:调用 Lua 函数并处理返回值。 - **参数**:`L` 是 Lua 状态机指针。 - **返回值**:成功返回 `0`,失败返回 `ERROR`(可能是预定义的错误码)。 --- ### **2. 调用 Lua 函数** ```c if (lua_pcall(L, 1, 1, 0) != 0) { printf("ERROR: pcall: %s\r\n", lua_tostring(L, -1)); lua_pop(L, 1); return ERROR; } ``` - **`lua_pcall(L, 1, 1, 0)`**: - 调用 Lua 函数,传入 **1 个参数**,期望返回 **1 个结果**,**不使用错误处理函数**(`errfunc=0`)。 - 如果调用失败(返回值非零),打印错误信息并清理栈(`lua_pop`),然后返回错误。 --- ### **3. 检查返回值是否为表** ```c if (!lua_istable(L, -1)) { printf("ERROR: lua_istable\r\n"); lua_pop(L, 1); return ERROR; } ``` - **`lua_istable(L, -1)`**: - 检查栈顶的返回值是否是一个 Lua 表(table)。 - 如果不是表,打印错误并清理栈,返回错误。 --- ### **4. 检查 `success` 字段** ```c lua_getfield(L, -1, "success"); if (!lua_toboolean(L, -1)) { printf("ERROR: success != true\r\n"); lua_pop(L, 2); return ERROR; } lua_pop(L, 1); ``` - **`lua_getfield(L, -1, "success")`**: - 从表中获取 `success` 字段的值并压入栈顶。 - **`lua_toboolean(L, -1)`**: - 检查 `success` 是否为 `true`(Lua 逻辑真)。 - 如果不是,打印错误,清理栈(弹出 `success` 和表),返回错误。 - **`lua_pop(L, 1)`**: - 弹出 `success` 字段,保留表在栈顶。 --- ### **5. 检查 `data` 字段** ```c lua_getfield(L, -1, "data"); if (!lua_istable(L, -1) && !lua_isnil(L, -1)) { printf("ERROR: lua_istable\r\n"); lua_pop(L, 2); return ERROR; } ``` - **`lua_getfield(L, -1, "data")`**: - 从表中获取 `data` 字段的值并压入栈顶。 - **`lua_istable(L, -1) || lua_isnil(L, -1)`**: - 检查 `data` 是否是表(table)或 `nil`。 - 如果不是,打印错误,清理栈(弹出 `data` 和表),返回错误。 --- ### **6. 清理栈并返回** ```c lua_remove(L, -2); return 0; ``` - **`lua_remove(L, -2)`**: - 移除栈上的表(原表在 `-2`,`data` 在 `-1`),现在栈顶只剩 `data`。 - **`return 0`**: - 成功返回 `0`,此时栈顶是 `data` 字段的值(可能是表或 `nil`)。 --- ### **功能总结** 1. **调用 Lua 函数**:传入 1 个参数,期望 1 个返回值。 2. **错误处理**: - 如果调用失败或返回值不符合预期(非表、`success` 非 `true`、`data` 非法),打印错误并返回 `ERROR`。 3. **返回 `data`**: - 最终栈顶是 `data` 字段的值(可能是表或 `nil`),供后续使用。 --- ### **典型用途** 这段代码可能用于调用一个返回结构化数据的 Lua 函数(如 LuCI 的 API),并验证其返回值是否符合预期格式: ```lua -- 假设 Lua 函数返回如下表: return { success = true, -- 必须为 true data = { ... } -- 必须是表或 nil } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值