diff --git a/daemon/ffimodule.c b/daemon/ffimodule.c index 6b967a948a46b6080fb4931a4e7e901dac9a3d16..c95201c843b18f816606d80da820f705cde4eaa1 100644 --- a/daemon/ffimodule.c +++ b/daemon/ffimodule.c @@ -33,34 +33,21 @@ static inline lua_State *l_ffi_preface(struct kr_module *module, const char *cal lua_State *L = module->lib; lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t)module->data); lua_getfield(L, -1, call); + lua_remove(L, -2); lua_pushlightuserdata(L, module); return L; } -/** @internal Helper for calling the entrypoint. */ -static inline int l_ffi_resume(lua_State *L, bool resume, int argc) -{ - int status = resume ? l_resume(L, argc) : engine_pcall(L, argc); - switch(status) { - case LUA_YIELD: /* Continuation */ - return kr_error(EAGAIN); - case 0: /* Finished */ - return lua_tonumber(L, 1); - default: /* Error */ - lua_pop(L, 1); - return kr_error(EIO); - } -} - /** @internal Continue with coroutine. */ static void l_ffi_resume_cb(uv_idle_t *check) { lua_State *L = check->data; - int status = l_ffi_resume(L, true, 0); - if (status != kr_error(EAGAIN)) { + int status = l_resume(L, 0); + if (status != LUA_YIELD) { uv_idle_stop(check); /* Stop coroutine */ uv_close((uv_handle_t *)check, (uv_close_cb)free); } + lua_pop(L, lua_gettop(L)); } /** @internal Schedule deferred continuation. */ @@ -78,9 +65,20 @@ static int l_ffi_defer(lua_State *L) /** @internal Helper for calling the entrypoint. */ static inline int l_ffi_call(lua_State *L, int argc) { - int status = l_ffi_resume(L, false, argc); - if (status == kr_error(EAGAIN)) { - return l_ffi_defer(L); + int status = lua_pcall(L, argc, LUA_MULTRET, 0); + if (status != 0) { + lua_pop(L, 1); + return kr_error(EIO); + } + + int n = lua_gettop(L); + if (n > 0) { + if (lua_isthread(L, -1)) { /* Continuations */ + status = l_ffi_defer(lua_tothread(L, -1)); + } else if (lua_isnumber(L, -1)) { /* Return code */ + status = lua_tonumber(L, 1); + } + lua_pop(L, n); } return status; } @@ -94,13 +92,12 @@ static int l_ffi_init(struct kr_module *module) static int l_ffi_deinit(struct kr_module *module) { lua_State *L = l_ffi_preface(module, "deinit"); - /* @note Do not allow coroutine here. */ - int ret = l_ffi_resume(L, false, 1); + int ret = l_ffi_call(L, 1); /* Free the layer API wrapper */ lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t)module->data); lua_getfield(L, -1, "_layercdata"); free(lua_touserdata(L, -1)); - lua_pop(L, 1); + lua_pop(L, 2); /* Unref module and unset 'lib', so the module * interface doesn't attempt to close it. */ @@ -117,8 +114,11 @@ static int l_ffi_deinit(struct kr_module *module) lua_State *L = module->lib; \ lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t)module->data); \ lua_getfield(L, -1, "layer"); \ + lua_remove(L, -2); \ lua_getfield(L, -1, (name)); \ + lua_remove(L, -2); \ if (lua_isnil(L, -1)) { \ + lua_pop(L, 1); \ return ctx->state; \ } \ lua_pushnumber(L, ctx->state); @@ -128,21 +128,21 @@ static int l_ffi_layer_begin(knot_layer_t *ctx, void *module_param) LAYER_FFI_CALL(ctx, "begin"); lua_pushlightuserdata(L, module_param); ctx->data = module_param; - return l_ffi_resume(L, false, 2); + return l_ffi_call(L, 2); } static int l_ffi_layer_reset(knot_layer_t *ctx) { LAYER_FFI_CALL(ctx, "reset"); lua_pushlightuserdata(L, ctx->data); - return l_ffi_resume(L, false, 2); + return l_ffi_call(L, 2); } static int l_ffi_layer_finish(knot_layer_t *ctx) { LAYER_FFI_CALL(ctx, "finish"); lua_pushlightuserdata(L, ctx->data); - return l_ffi_resume(L, false, 2); + return l_ffi_call(L, 2); } static int l_ffi_layer_consume(knot_layer_t *ctx, knot_pkt_t *pkt) @@ -150,7 +150,7 @@ static int l_ffi_layer_consume(knot_layer_t *ctx, knot_pkt_t *pkt) LAYER_FFI_CALL(ctx, "consume"); lua_pushlightuserdata(L, ctx->data); lua_pushlightuserdata(L, pkt); - return l_ffi_resume(L, false, 3); + return l_ffi_call(L, 3); } static int l_ffi_layer_produce(knot_layer_t *ctx, knot_pkt_t *pkt) @@ -158,7 +158,7 @@ static int l_ffi_layer_produce(knot_layer_t *ctx, knot_pkt_t *pkt) LAYER_FFI_CALL(ctx, "produce"); lua_pushlightuserdata(L, ctx->data); lua_pushlightuserdata(L, pkt); - return l_ffi_resume(L, false, 3); + return l_ffi_call(L, 3); } static int l_ffi_layer_fail(knot_layer_t *ctx, knot_pkt_t *pkt) @@ -166,7 +166,7 @@ static int l_ffi_layer_fail(knot_layer_t *ctx, knot_pkt_t *pkt) LAYER_FFI_CALL(ctx, "fail"); lua_pushlightuserdata(L, ctx->data); lua_pushlightuserdata(L, pkt); - return l_ffi_resume(L, false, 3); + return l_ffi_call(L, 3); } /** @internal Retrieve C layer api wrapper. */ @@ -175,27 +175,26 @@ static const knot_layer_api_t* l_ffi_layer(struct kr_module *module) lua_State *L = module->lib; lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t)module->data); lua_getfield(L, -1, "_layer_capi"); - if (lua_isnil(L, -1)) { + knot_layer_api_t *api = lua_touserdata(L, -1); + lua_pop(L, 1); + if (!api) { /* Fabricate layer API wrapping the Lua functions */ knot_layer_api_t *api = malloc(sizeof(*api)); - if (!api) { - return NULL; + if (api) { + api->begin = l_ffi_layer_begin; + api->finish = l_ffi_layer_finish; + api->consume = l_ffi_layer_consume; + api->produce = l_ffi_layer_produce; + api->reset = l_ffi_layer_reset; + api->fail = l_ffi_layer_fail; + api->data = module; } - api->begin = l_ffi_layer_begin; - api->finish = l_ffi_layer_finish; - api->consume = l_ffi_layer_consume; - api->produce = l_ffi_layer_produce; - api->reset = l_ffi_layer_reset; - api->fail = l_ffi_layer_fail; - api->data = module; /* Store the api in the registry. */ - lua_pop(L, 1); lua_pushlightuserdata(L, api); lua_setfield(L, -2, "_layer_capi"); - return api; - } else { - return lua_touserdata(L, -1); } + lua_pop(L, 1); /* Clear module table */ + return api; } #undef LAYER_FFI_CALL @@ -229,6 +228,7 @@ int ffimodule_register_lua(struct engine *engine, struct kr_module *module, cons REGISTER_FFI_CALL(L, module->layer, "layer", &l_ffi_layer); module->data = (void *)(intptr_t)luaL_ref(L, LUA_REGISTRYINDEX); module->lib = L; + lua_pop(L, 1); /* Clear the module global */ return module->init(module); } diff --git a/modules/README.rst b/modules/README.rst index 8c48642648a509ff7d350a6618ae965ed5caf2c3..a8da3c50a6f5317317db475b4a863a4c9b662640 100644 --- a/modules/README.rst +++ b/modules/README.rst @@ -139,6 +139,9 @@ The modules follow the `Lua way <http://lua-users.org/wiki/ModuleDefinition>`_, return counter +.. tip:: The API functions may return an integer value just like in other languages, but they may also return a coroutine that will be continued asynchronously. A good use case for this approach is is a deferred initialization, +e.g. loading a chunks of data or waiting for I/O. + The created module can be then loaded just like any other module, except it isn't very useful since it doesn't provide any layer to capture events. The Lua module can however provide a processing layer, just :ref:`like its C counterpart <lib-layers>`.