1

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

lua代码:

local lt = luatimer

lt.register_timer(1, function(id)
        io.stdout:write("id" .. id .. "timeout\n");
    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);
}
4

1 回答 1

0

非常感谢,我犯了一个愚蠢的错误,我L在本地变量和全局变量中使用了相同的名称。对不起,谢谢greatwold 和immibis

于 2014-12-22T08:46:36.900 回答