Commit 92e3e9ba authored by Vladimír Čunát's avatar Vladimír Čunát

module: document the API and simplify the code

This does NOT change the module API/ABI in any way.
parent 3f668106
......@@ -761,15 +761,20 @@ void engine_stop(struct engine *engine)
uv_stop(uv_default_loop());
}
/** Register module properties in Lua environment */
/** Register module properties in Lua environment, if any. */
static int register_properties(struct engine *engine, struct kr_module *module)
{
if (!module->config && !module->props) {
return kr_ok();
}
lua_newtable(engine->L);
if (module->config != NULL) {
REGISTER_MODULE_CALL(engine->L, module, module->config, "config");
}
for (struct kr_prop *p = module->props; p && p->name; ++p) {
if (p->cb != NULL && p->name != NULL) {
const struct kr_prop *p = module->props == NULL ? NULL : module->props();
for (; p && p->name; ++p) {
if (p->cb != NULL) {
REGISTER_MODULE_CALL(engine->L, module, p->cb, p->name);
}
}
......@@ -855,12 +860,7 @@ int engine_register(struct engine *engine, const char *name, const char *precede
}
}
/* Register properties */
if (module->props || module->config) {
return register_properties(engine, module);
}
return kr_ok();
return register_properties(engine, module);
}
int engine_unregister(struct engine *engine, const char *name)
......
......@@ -44,30 +44,6 @@ static const struct kr_module embedded_modules[] = {
#define LIBEXT ".so"
#endif
/** Check ABI version, return error on mismatch. */
#define ABI_CHECK(m, prefix, symname, required) do { \
module_api_cb *_api = NULL; \
*(void **) (&_api) = load_symbol((m)->lib, (prefix), (symname)); \
if (_api == NULL) { \
return kr_error(ENOENT); \
} \
if (_api() != (required)) { \
return kr_error(ENOTSUP); \
} \
} while (0)
/** Load ABI by symbol names. */
#define ABI_LOAD(m, prefix, s_init, s_deinit, s_config, s_layer, s_prop) do { \
module_prop_cb *module_prop = NULL; \
*(void **) (&(m)->init) = load_symbol((m)->lib, (prefix), (s_init)); \
*(void **) (&(m)->deinit) = load_symbol((m)->lib, (prefix), (s_deinit)); \
*(void **) (&(m)->config) = load_symbol((m)->lib, (prefix), (s_config)); \
*(void **) (&(m)->layer) = load_symbol((m)->lib, (prefix), (s_layer)); \
*(void **) (&module_prop) = load_symbol((m)->lib, (prefix), (s_prop)); \
if (module_prop != NULL) { \
(m)->props = module_prop(); \
} \
} while(0)
/** Load prefixed symbol. */
static void *load_symbol(void *lib, const char *prefix, const char *name)
......@@ -115,9 +91,27 @@ static int load_sym_c(struct kr_module *module, uint32_t api_required)
}
}
/* Load dynamic library module */
auto_free char *module_prefix = kr_strcatdup(2, module->name, "_");
ABI_CHECK(module, module_prefix, "api", api_required);
ABI_LOAD(module, module_prefix, "init", "deinit", "config", "layer", "props");
auto_free char *m_prefix = kr_strcatdup(2, module->name, "_");
/* Check ABI version, return error on mismatch. */
module_api_cb *api = load_symbol(module->lib, m_prefix, "api");
if (api == NULL) {
return kr_error(ENOENT);
}
if (api() != api_required) {
return kr_error(ENOTSUP);
}
/* Load ABI by symbol names. */
#define ML(symname) module->symname = \
load_symbol(module->lib, m_prefix, #symname)
ML(init);
ML(deinit);
ML(config);
ML(layer);
ML(props);
#undef ML
return kr_ok();
}
......
......@@ -14,56 +14,73 @@
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** @file module API definition and functions for (un)loading modules. */
#pragma once
#include "lib/defines.h"
#include "lib/utils.h"
#include "lib/layer.h"
/*
* Forward decls
*/
struct kr_module;
struct kr_prop;
/*
* API definition.
* @cond internal
/**
* Export module API version (place this at the end of your module).
*
* @param module module name (f.e. hints)
*/
typedef uint32_t (module_api_cb)(void);
typedef int (module_init_cb)(struct kr_module *);
typedef int (module_deinit_cb)(struct kr_module *);
typedef int (module_config_cb)(struct kr_module *, const char *);
typedef const kr_layer_api_t* (module_layer_cb)(struct kr_module *);
typedef struct kr_prop *(module_prop_cb)(void);
typedef char *(kr_prop_cb)(void *, struct kr_module *, const char *);
#define KR_MODULE_EXPORT(module) \
KR_EXPORT uint32_t module ## _api() { return KR_MODULE_API; }
#define KR_MODULE_API ((uint32_t) 0x20161108)
/* @endcond */
typedef uint32_t (module_api_cb)(void);
/**
* Module property (named callable).
* A module property has a free-form JSON output (and optional input).
* Module representation.
*
* The five symbols (init, ...) may be defined by the module as name_init(), etc;
* all are optional and missing symbols are represented as NULLs;
*/
struct kr_prop {
kr_prop_cb *cb;
const char *name;
const char *info;
struct kr_module {
char *name;
/** Constructor. Called after loading the module. @return error code. */
int (*init)(struct kr_module *self);
/** Destructor. Called before unloading the module. @return error code. */
int (*deinit)(struct kr_module *self);
/** Configure with encoded JSON (NULL if missing). @return error code. */
int (*config)(struct kr_module *self, const char *input);
/** Get a pointer to packet processing API specs. See docs on that type. */
const kr_layer_api_t * (*layer)(struct kr_module *self);
/** Get a pointer to list of properties, terminated by { NULL, NULL, NULL }. */
const struct kr_prop * (*props)(void);
void *lib; /**< Shared library handle or RTLD_DEFAULT */
void *data; /**< Custom data context. */
};
/**
* Module representation.
* Module property callback. Input and output is passed via a JSON encoded in a string.
*
* @param env pointer to the lua engine, i.e. struct engine *env (TODO: explicit type)
* @param input parameter (NULL if missing/nil on lua level)
* @return a free-form JSON output (malloc-ated)
*/
struct kr_module {
char *name; /**< Name. */
module_init_cb *init; /**< Constructor */
module_deinit_cb *deinit; /**< Destructor */
module_config_cb *config; /**< Configuration */
module_layer_cb *layer; /**< Layer getter */
struct kr_prop *props; /**< Properties */
void *lib; /**< Shared library handle or RTLD_DEFAULT */
void *data; /**< Custom data context. */
typedef char *(kr_prop_cb)(void *env, struct kr_module *self, const char *input);
/**
* Module property (named callable).
*/
struct kr_prop {
kr_prop_cb *cb;
const char *name;
const char *info;
};
/**
* Load module instance into memory.
*
......@@ -83,10 +100,3 @@ int kr_module_load(struct kr_module *module, const char *name, const char *path)
KR_EXPORT
void kr_module_unload(struct kr_module *module);
/**
* Export module API version (place this at the end of your module).
*
* @param module module name (f.e. hints)
*/
#define KR_MODULE_EXPORT(module) \
KR_EXPORT uint32_t module ## _api() { return KR_MODULE_API; }
......@@ -480,10 +480,10 @@ int kr_ranked_rrarray_set_wire(ranked_rr_array_t *array, bool to_wire, uint32_t
static char *callprop(struct kr_module *module, const char *prop, const char *input, void *env)
{
if (!module || !prop) {
if (!module || !module->props || !prop) {
return NULL;
}
for (struct kr_prop *p = module->props; p && p->name; ++p) {
for (const struct kr_prop *p = module->props(); p && p->name; ++p) {
if (p->cb != NULL && strcmp(p->name, prop) == 0) {
return p->cb(env, module, input);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment