aboutsummaryrefslogtreecommitdiff
path: root/lib/cpluff/libcpluff/serial.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cpluff/libcpluff/serial.c')
-rw-r--r--lib/cpluff/libcpluff/serial.c201
1 files changed, 201 insertions, 0 deletions
diff --git a/lib/cpluff/libcpluff/serial.c b/lib/cpluff/libcpluff/serial.c
new file mode 100644
index 0000000000..b4b27740e2
--- /dev/null
+++ b/lib/cpluff/libcpluff/serial.c
@@ -0,0 +1,201 @@
+/*-------------------------------------------------------------------------
+ * C-Pluff, a plug-in framework for C
+ * Copyright 2007 Johannes Lehtinen
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *-----------------------------------------------------------------------*/
+
+/** @file
+ * Serial execution implementation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "cpluff.h"
+#include "internal.h"
+
+
+/* ------------------------------------------------------------------------
+ * Data types
+ * ----------------------------------------------------------------------*/
+
+/// A holder structure for a run function.
+typedef struct run_func_t {
+
+ /// The run function
+ cp_run_func_t runfunc;
+
+ /// The registering plug-in instance
+ cp_plugin_t *plugin;
+
+ /// Whether currently in execution
+ int in_execution;
+
+} run_func_t;
+
+CP_C_API cp_status_t cp_run_function(cp_context_t *ctx, cp_run_func_t runfunc) {
+ lnode_t *node = NULL;
+ run_func_t *rf = NULL;
+ cp_status_t status = CP_OK;
+
+ CHECK_NOT_NULL(ctx);
+ CHECK_NOT_NULL(runfunc);
+ if (ctx->plugin == NULL) {
+ cpi_fatalf(_("Only plug-ins can register run functions."));
+ }
+ if (ctx->plugin->state != CP_PLUGIN_ACTIVE
+ && ctx->plugin->state != CP_PLUGIN_STARTING) {
+ cpi_fatalf(_("Only starting or active plug-ins can register run functions."));
+ }
+
+ cpi_lock_context(ctx);
+ cpi_check_invocation(ctx, CPI_CF_STOP | CPI_CF_LOGGER, __func__);
+ do {
+ int found = 0;
+ lnode_t *n;
+
+ // Check if already registered
+ n = list_first(ctx->env->run_funcs);
+ while (n != NULL && !found) {
+ run_func_t *r = lnode_get(n);
+ if (runfunc == r->runfunc && ctx->plugin == r->plugin) {
+ found = 1;
+ }
+ n = list_next(ctx->env->run_funcs, n);
+ }
+ if (found) {
+ break;
+ }
+
+ // Allocate memory for a new run function entry
+ if ((rf = malloc(sizeof(run_func_t))) == NULL) {
+ status = CP_ERR_RESOURCE;
+ break;
+ }
+ if ((node = lnode_create(rf)) == NULL) {
+ status = CP_ERR_RESOURCE;
+ break;
+ }
+
+ // Initialize run function entry
+ memset(rf, 0, sizeof(run_func_t));
+ rf->runfunc = runfunc;
+ rf->plugin = ctx->plugin;
+
+ // Append the run function to queue
+ list_append(ctx->env->run_funcs, node);
+ if (ctx->env->run_wait == NULL) {
+ ctx->env->run_wait = node;
+ }
+
+ } while (0);
+
+ // Log error
+ if (status == CP_ERR_RESOURCE) {
+ cpi_error(ctx, N_("Could not register a run function due to insufficient memory."));
+ }
+ cpi_unlock_context(ctx);
+
+ // Free resources on error
+ if (status != CP_OK) {
+ if (node != NULL) {
+ lnode_destroy(node);
+ }
+ if (rf != NULL) {
+ free(rf);
+ }
+ }
+
+ return status;
+}
+
+CP_C_API void cp_run_plugins(cp_context_t *ctx) {
+ while (cp_run_plugins_step(ctx));
+}
+
+CP_C_API int cp_run_plugins_step(cp_context_t *ctx) {
+ int runnables;
+
+ CHECK_NOT_NULL(ctx);
+ cpi_lock_context(ctx);
+ if (ctx->env->run_wait != NULL) {
+ lnode_t *node = ctx->env->run_wait;
+ run_func_t *rf = lnode_get(node);
+ int rerun;
+
+ ctx->env->run_wait = list_next(ctx->env->run_funcs, node);
+ rf->in_execution = 1;
+ cpi_unlock_context(ctx);
+ rerun = rf->runfunc(rf->plugin->plugin_data);
+ cpi_lock_context(ctx);
+ rf->in_execution = 0;
+ list_delete(ctx->env->run_funcs, node);
+ if (rerun) {
+ list_append(ctx->env->run_funcs, node);
+ if (ctx->env->run_wait == NULL) {
+ ctx->env->run_wait = node;
+ }
+ } else {
+ lnode_destroy(node);
+ free(rf);
+ }
+ cpi_signal_context(ctx);
+ }
+ runnables = (ctx->env->run_wait != NULL);
+ cpi_unlock_context(ctx);
+ return runnables;
+}
+
+CP_HIDDEN void cpi_stop_plugin_run(cp_plugin_t *plugin) {
+ int stopped = 0;
+ cp_context_t *ctx;
+
+ CHECK_NOT_NULL(plugin);
+ ctx = plugin->context;
+ assert(cpi_is_context_locked(ctx));
+ while (!stopped) {
+ lnode_t *node;
+
+ stopped = 1;
+ node = list_first(ctx->env->run_funcs);
+ while (node != NULL) {
+ run_func_t *rf = lnode_get(node);
+ lnode_t *next_node = list_next(ctx->env->run_funcs, node);
+
+ if (rf->plugin == plugin) {
+ if (rf->in_execution) {
+ stopped = 0;
+ } else {
+ if (ctx->env->run_wait == node) {
+ ctx->env->run_wait = list_next(ctx->env->run_funcs, node);
+ }
+ list_delete(ctx->env->run_funcs, node);
+ lnode_destroy(node);
+ free(rf);
+ }
+ }
+ node = next_node;
+ }
+
+ // If some run functions were in execution, wait for them to finish
+ if (!stopped) {
+ cpi_wait_context(ctx);
+ }
+ }
+}