C - 使用 Lua 的 LightUserData 注册定时器回调



我想包装 C 计时器(不是警报(并在 lua 中使用它,以一种我的方式可以指定要在一秒后触发的回调函数。为了使用多个计时器,计时器 ID 和回调将被存储到表中,但是调用"lua_rawset"时发生了分段错误,所以我使用stack_dump检查 Lua 堆栈,第 66(lr_register_timer( 行的"lua_rawget"返回了一个 nil,由 FIXME 标记(,这里有什么问题?对不起,我的英语很差。干杯。

路易码:

local lt = luatimer
lt.register_timer(1, function(id)
        io.stdout:write("id" .. id .. "timeoutn");
    end)

C 代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
#include "timer.h"
static lua_State *L;
static void stack_dump(lua_State *L, FILE *fp)
{
    int i;
    int top = lua_gettop(L);
    for (i = 1; i <= top; i++) {
        int t = lua_type(L, i);
        switch (t) {
        case LUA_TSTRING: fprintf(fp, "'%s'", lua_tostring(L, i)); break;
        case LUA_TBOOLEAN: fprintf(fp, lua_toboolean(L, i) ? "true" : "false"); break;
        case LUA_TNUMBER: fprintf(fp, "%g", lua_tonumber(L, i)); break;
        default: fprintf(fp, "%s", lua_typename(L, t)); break;
        }
        fprintf(fp, " ");
    }
    fprintf(fp, "n");
}
struct timer_env {
    int id;
    struct event *ev;
};
static void callback_timer_wrap(int id, void *arg)
{
    struct timer_env *env = arg;
    /* get timer id table */
    lua_pushlightuserdata(L, &L);
    lua_rawget(L, LUA_REGISTRYINDEX);
    lua_pushinteger(L, env->id);
    lua_gettable(L, -2);
    /* call lua handler with one result */
    lua_pushinteger(L, env->id);
    if (lua_pcall(L, 1, 1, 0) == 0) {
        lua_pop(L, 1); /* pop result */
    }
}
/* id, callback */
static int lr_register_timer(lua_State *L)
{
    struct timer_env *env;
    int id;
    int err;
    id = (int)luaL_checkinteger(L, 1);
    if (!lua_isfunction(L, 2) || lua_iscfunction(L, 2))
        return 0;
    /* set lua handler */
    lua_pushlightuserdata(L, &L);
    lua_rawget(L, LUA_REGISTRYINDEX); /* FIXME */
    lua_pushvalue(L, 1); /* key: id */
    lua_pushvalue(L, 2); /* value: callback */
    stack_dump(L, stderr);
    /* FIXME  crashed */
    lua_rawset(L, -3);
    lua_pop(L, 1);
    env = malloc(sizeof(*env));
    memset(env, 0, sizeof(*env));
    env->id = id;
    if ((err = register_timer(id, callback_timer_wrap, env)) < 0)
        free(env);
    lua_pushinteger(L, err);
    return 1;
}
static const luaL_Reg luatimer_lib[] = {
    { "register_timer", lr_register_timer },
    { NULL, NULL }
};
static int luaopen_luatimer(lua_State *L)
{
    luaL_register(L, "luatimer", luatimer_lib);
    /* timer id table */
    lua_pushlightuserdata(L, &L); /* key */
    lua_newtable(L); /* value */
    lua_rawset(L, LUA_REGISTRYINDEX);
    return 1;
}
int luaenv_init(void)
{
    L = luaL_newstate();
    luaL_openlibs(L);
    lua_pushcfunction(L, luaopen_luatimer);
    lua_pushstring(L, "luatimer");
    lua_call(L, 1, 0);
    return 0;
}
void luaenv_exit(void)
{
    if (L)
        lua_close(L);
}

非常感谢,我犯了一个愚蠢的错误,我在本地变量和全局变量中使用了相同的名称L。对不起谢谢大沃尔德和伊米比斯

最新更新