aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins.c')
-rw-r--r--src/plugins.c91
1 files changed, 86 insertions, 5 deletions
diff --git a/src/plugins.c b/src/plugins.c
index b96aade..8ccde06 100644
--- a/src/plugins.c
+++ b/src/plugins.c
@@ -30,10 +30,22 @@ struct ptx__plugin_handle_tag
ptx_plugin_t *next;
int path_fd;
+ int pl_state; /* used to assert that the application is following its contract with plugins */
+
/* plugin filename */
char fname[1];
};
+enum {
+ PL_STATE_NEW, /* plugin struct just initialized */
+ PL_STATE_LOADED, /* plugin module loaded */
+ PL_STATE_INITIALIZING, /* plugin initializer call started */
+ PL_STATE_INITIALIZED, /* plugin initializer completed */
+ PL_STATE_DEINITIALIZED, /* plugin deinitializer called */
+ PL_STATE_ERROR, /* error in initializer, only valid operation is free */
+ PL_STATE_UNLOADED /* plugin unloaded */
+};
+
ptx_plugin_manager_t *ptx_plugin_manager_new(void)
{
ptx_plugin_manager_t *mgr = malloc(sizeof(ptx_plugin_manager_t));
@@ -46,7 +58,7 @@ ptx_plugin_manager_t *ptx_plugin_manager_new(void)
}
/* inform the plugin that it is about to be unloaded. It should clean up its resources. */
-static void deinit_plugin(ptx_plugin_t *plugin);
+static int deinit_plugin(ptx_plugin_t *plugin, void **presume);
/* unload/cleanup/free the plugin. */
static void free_plugin(ptx_plugin_t *plugin);
@@ -58,7 +70,7 @@ void ptx_plugin_manager_free(ptx_plugin_manager_t *mgr)
/* do cleanup */
for (ptx_plugin_t *plugin = mgr->pl_head, *next; plugin; plugin = next) {
next = plugin->next;
- deinit_plugin(plugin);
+ deinit_plugin(plugin, NULL); /* result ignored (not resuming) */
free_plugin(plugin);
}
@@ -82,6 +94,7 @@ static ptx_plugin_t *load_plugin(ptx_plugin_manager_t *manager, const char *plug
goto cleanup;
}
+ plugin->pl_state = PL_STATE_NEW;
plugin->manager = manager;
memcpy(plugin->fname, plugin_fname, fnamelen); /* NUL-termination achieved thanks to calloc */
@@ -99,8 +112,19 @@ static ptx_plugin_t *load_plugin(ptx_plugin_manager_t *manager, const char *plug
goto cleanup;
}
+ if (pl_desc->desc_len != sizeof(struct ptx_plugin_desc)) {
+ fprintf(stderr, "(plugin) %s: descriptor struct size mismatch: %zu != %zu (expected)\n", plugin_fname, pl_desc->desc_len, sizeof(struct ptx_plugin_desc));
+ goto cleanup;
+ }
+
+ if (pl_desc->desc_ver != PTX_CUR_PLUGIN_VERSION) {
+ fprintf(stderr, "(plugin) %s: is for a different version of ptxmc! %u != %u (expected)\n", plugin_fname, pl_desc->desc_ver, PTX_CUR_PLUGIN_VERSION);
+ goto cleanup;
+ }
+
plugin->desc = pl_desc;
+ plugin->pl_state = PL_STATE_LOADED;
return plugin;
cleanup:
@@ -182,15 +206,72 @@ cleanup_iter:
return 0;
}
-static void deinit_plugin(ptx_plugin_t *plugin)
+static int init_plugin(ptx_plugin_t *plugin, void *resume)
{
- /* TODO */
- UNUSED(plugin);
+ assert(plugin);
+ assert(plugin->pl_state == plugin->pl_state == PL_STATE_LOADED);
+
+ plugin->pl_state = PL_STATE_INITIALIZING;
+ int result = 0;
+
+ if (plugin->desc->init_proc) {
+ result = (plugin->desc->init_proc)(plugin, resume);
+ } else {
+ fprintf(stderr, "(plugin) warning: plugin %s/%s has no initialization function! (does it do anything?)\n", plugin->desc->name, plugin->fname);
+ }
+
+ if (result < 0) {
+ plugin->pl_state = PL_STATE_ERROR;
+ fprintf(stderr, "(plugin) init_plugin: %s/%s: initializer failed (%d)\n", plugin->desc->name, plugin->fname, result);
+ } else {
+ plugin->pl_state = PL_STATE_INITIALIZED;
+ }
+
+ return result;
+}
+
+int ptx_plugin_manager_init_plugins(ptx_plugin_manager_t *mgr)
+{
+ for (ptx_plugin_t *plugin = mgr->pl_head; plugin; plugin = plugin->next)
+ {
+ if (plugin->pl_state >= PL_STATE_INITIALIZED) continue;
+ assert(plugin->pl_state != PL_STATE_INITIALIZING); /* function should never be called from a plugin initializer */
+
+ init_plugin(plugin, NULL);
+ }
+}
+
+static int deinit_plugin(ptx_plugin_t *plugin, void **presume)
+{
+ assert(plugin);
+ assert(plugin->pl_state >= PL_STATE_INITIALIZED && plugin->pl_state < PL_STATE_DEINITIALIZED);
+
+ int result = DEINIT_OK;
+ if (plugin->desc->deinit_proc) {
+ result = (plugin->desc->deinit_proc)(plugin, presume);
+ } else {
+ result = presume ? DEINIT_ERR_RESUME_UNSUPPORTED : DEINIT_OK;
+ }
+
+ plugin->pl_state = PL_STATE_DEINITIALIZED;
+ return result;
}
static void free_plugin(ptx_plugin_t *plugin)
{
+ assert(plugin->pl_state < PL_STATE_INITIALIZED || plugin->pl_state >= PL_STATE_DEINITIALIZED);
+
dlclose(plugin->modp);
close(plugin->path_fd);
+
+ plugin->pl_state = PL_STATE_UNLOADED; /* state never observed by the software */
+
free(plugin);
}
+
+PTX_API void ptx_plugin_set_mainloop_func(ptx_plugin_t *plugin, void *func)
+{
+ assert(plugin);
+ assert(plugin->pl_state == PL_STATE_INITIALIZING || plugin->pl_state == PL_STATE_INITIALIZED);
+ UNUSED(plugin, func);
+}