Export host C functions to luajit FFI without export

  • From: Domingo Alvarez Duarte <mingodad@xxxxxxxxx>
  • To: luajit@xxxxxxxxxxxxx
  • Date: Sun, 18 Jan 2015 21:52:05 -0800

Hello !

I have read a post
//www.freelists.org/post/luajit/FFI-newby-question-importing-C-functions
that describes the same problem I'm trying to solve.

Expose host C functions to luajit FFI without make then externally dynamic
linkable, on that post it was said that this isn't actually supported by
luajit FFI.

So I was thing on a workaround and need some feedback from people with more
experience with luajit FFI.

I'm thinking on creating something like a function pointer in luajit FFI
and pass that pointer to the host to set the address of the function then
call it from luajit.

Bellow is a partial code example showing the idea of how it could be done,
any help, comment, suggestion, improvement are welcome.

Thanks in advance for your time and attention !

ffi.cdef[[
typedef struct {
        int (*getStatus)(void *ctx);
        void (*setStatus)(void *ctx, int status);
} host_funcs_t;
]]

local host_funcs = ffi.new("host_funcs_t")

hostSetHostFuncs(host_funcs)

function handleWithContext(ctx)
        local i = host_funcs.getStatus(ctx)
        host_funcs.setStatus(ctx, 10)
end

------- C side

typedef struct {
        int (*getStatus)(void *ctx);
        void (*setStatus)(void *ctx, int status);
} host_funcs_t;

static int lua_hostSetHostFuncs(lua_State *L)
{
        if(!lua_islightuserdata (L, 1)
        {
                luaL_error(L, "a lightuserata is expected for this function");
        }
        host_funcs_t *host_funcs = (host_funcs_t*)lua_topointer (L, 1);
        host_funcs->getStatus = myHostGetStatusFuncAddress;
        host_funcs->setStatus = myHostSetStatusFuncAddress;
        return 0;
}

static int traceback (lua_State *L) {
  if (!lua_isstring(L, 1))  /* 'message' not a string? */
    return 1;  /* keep it intact */
  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  if (!lua_istable(L, -1)) {
    lua_pop(L, 1);
    return 1;
  }
  lua_getfield(L, -1, "traceback");
  if (!lua_isfunction(L, -1)) {
    lua_pop(L, 2);
    return 1;
  }
  lua_pushvalue(L, 1);  /* pass error message */
  lua_pushinteger(L, 2);  /* skip this function and traceback */
  lua_call(L, 2, 1);  /* call debug.traceback */
  return 1;
}

typedef struct {
        lua_State *L;
        void *ctx;
} my_context_t;

static int lua_handle_request(my_context_t *req)
{
    lua_State *L = req->L;
    int result = 0;
    if(L)
    {
        int saved_top = lua_gettop(L);
        lua_pushcfunction(L, traceback);  /* push traceback function */
        int error_func = lua_gettop(L);

        lua_getglobal(L, "handleWithContext");
        if(lua_isfunction(L,-1)) {
            lua_pushlightuserdata(L,req);
            if(lua_pcall(L, 1, 1, error_func)) {
                size_t error_len;
                const char *error_msg = lua_tolstring(L, -1, &error_len);
                if(show_errors_on_stdout) printf("%s\n", error_msg);
                //write_error_message(conn, error_msg, error_len);
                result = 0;
            } else {
                result = lua_toboolean(L, -1) ? 1 : 0;
            }
        };
        lua_settop(L, saved_top);
    }

    return result;
}

Other related posts: