CP_HIDDEN void cpi_wait_mutex(cpi_mutex_t *mutex) { DWORD self = GetCurrentThreadId(); assert(mutex != NULL); lock_mutex(mutex->os_mutex); if (mutex->lock_count > 0 && self == mutex->os_thread) { int lc = mutex->lock_count; // Release mutex mutex->lock_count = 0; mutex->num_wait_threads++; set_event(mutex->os_cond_lock); unlock_mutex(mutex->os_mutex); // Wait for signal wait_for_event(mutex->os_cond_wake); // Reset wake signal if last one waking up lock_mutex(mutex->os_mutex); if (--mutex->num_wait_threads == 0) { reset_event(mutex->os_cond_wake); } // Re-acquire mutex and restore lock count for this thread lock_mutex_holding(mutex); mutex->lock_count = lc; } else { cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at waiting on a mutex.")); } unlock_mutex(mutex->os_mutex); }
static void wait_for_event(HANDLE event) { if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) { char buffer[256]; DWORD ec = GetLastError(); cpi_fatalf(_("Could not wait for an event due to error %ld: %s"), (long) ec, get_win_errormsg(ec, buffer, sizeof(buffer))); } }
static void reset_event(HANDLE event) { if (!ResetEvent(event)) { char buffer[256]; DWORD ec = GetLastError(); cpi_fatalf(_("Could not reset an event due to error %ld: %s"), (long) ec, get_win_errormsg(ec, buffer, sizeof(buffer))); } }
static void unlock_mutex(HANDLE mutex) { if (!ReleaseMutex(mutex)) { char buffer[256]; DWORD ec = GetLastError(); cpi_fatalf(_("Could not release a mutex due to error %ld: %s"), (long) ec, get_win_errormsg(ec, buffer, sizeof(buffer))); } }
CP_C_API cp_status_t cp_define_symbol(cp_context_t *context, const char *name, void *ptr) { cp_status_t status = CP_OK; CHECK_NOT_NULL(context); CHECK_NOT_NULL(name); CHECK_NOT_NULL(ptr); if (context->plugin == NULL) { cpi_fatalf(_("Only plug-ins can define context specific symbols.")); } cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER | CPI_CF_LISTENER, __func__); do { char *n; // Create a symbol hash if necessary if (context->plugin->defined_symbols == NULL) { if ((context->plugin->defined_symbols = hash_create(HASHCOUNT_T_MAX, (int (*)(const void *, const void *)) strcmp, NULL)) == NULL) { status = CP_ERR_RESOURCE; break; } } // Check for a previously defined symbol if (hash_lookup(context->plugin->defined_symbols, name) != NULL) { status = CP_ERR_CONFLICT; break; } // Insert the symbol into the symbol hash n = strdup(name); if (n == NULL || !hash_alloc_insert(context->plugin->defined_symbols, n, ptr)) { free(n); status = CP_ERR_RESOURCE; break; } } while (0); // Report error if (status != CP_OK) { switch (status) { case CP_ERR_RESOURCE: cpi_errorf(context, N_("Plug-in %s could not define symbol %s due to insufficient memory."), context->plugin->plugin->identifier, name); break; case CP_ERR_CONFLICT: cpi_errorf(context, N_("Plug-in %s tried to redefine symbol %s."), context->plugin->plugin->identifier, name); break; default: break; } } cpi_unlock_context(context); return status; }
static void lock_mutex(HANDLE mutex) { DWORD ec; if ((ec = WaitForSingleObject(mutex, INFINITE)) != WAIT_OBJECT_0) { char buffer[256]; ec = GetLastError(); cpi_fatalf(_("Could not lock a mutex due to error %ld: %s"), (long) ec, get_win_errormsg(ec, buffer, sizeof(buffer))); } }
CP_HIDDEN void cpi_check_invocation(cp_context_t *ctx, int funcmask, const char *func) { assert(ctx != NULL); assert(funcmask != 0); assert(func != NULL); assert(cpi_is_context_locked(ctx)); if ((funcmask & CPI_CF_LOGGER) &&ctx->env->in_logger_invocation) { cpi_fatalf(_("Function %s was called from within a logger invocation."), func); } if ((funcmask & CPI_CF_LISTENER) && ctx->env->in_event_listener_invocation) { cpi_fatalf(_("Function %s was called from within an event listener invocation."), func); } if ((funcmask & CPI_CF_START) && ctx->env->in_start_func_invocation) { cpi_fatalf(_("Function %s was called from within a plug-in start function invocation."), func); } if ((funcmask & CPI_CF_STOP) && ctx->env->in_stop_func_invocation) { cpi_fatalf(_("Function %s was called from within a plug-in stop function invocation."), func); } if (ctx->env->in_create_func_invocation) { cpi_fatalf(_("Function %s was called from within a plug-in create function invocation."), func); } if (ctx->env->in_destroy_func_invocation) { cpi_fatalf(_("Function %s was called from within a plug-in destroy function invocation."), func); } }
CP_HIDDEN void cpi_signal_mutex(cpi_mutex_t *mutex) { DWORD self = GetCurrentThreadId(); assert(mutex != NULL); lock_mutex(mutex->os_mutex); if (mutex->lock_count > 0 && self == mutex->os_thread) { set_event(mutex->os_cond_wake); } else { cpi_fatalf(_("Internal C-Pluff error: Unauthorized attempt at signaling a mutex.")); } unlock_mutex(mutex->os_mutex); }
CP_C_API void cp_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) { CHECK_NOT_NULL(context); CHECK_NOT_NULL(msg); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER, __func__); if (severity < CP_LOG_DEBUG || severity > CP_LOG_ERROR) { cpi_fatalf(_("Illegal severity value in call to %s."), __func__); } if (cpi_is_logged(context, severity)) { do_log(context, severity, msg); } cpi_unlock_context(context); }
CP_C_API void cp_set_context_args(cp_context_t *ctx, char **argv) { int argc; CHECK_NOT_NULL(ctx); CHECK_NOT_NULL(argv); for (argc = 0; argv[argc] != NULL; argc++); if (argc < 1) { cpi_fatalf(_("At least one startup argument must be given in call to function %s."), __func__); } cpi_lock_context(ctx); ctx->env->argc = argc; ctx->env->argv = argv; cpi_unlock_context(ctx); }
CP_C_API void cp_destroy_context(cp_context_t *context) { CHECK_NOT_NULL(context); if (context->plugin != NULL) { cpi_fatalf(_("Only the main program can destroy a plug-in context.")); } // Check invocation cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); cpi_unlock_context(context); #ifdef CP_THREADS assert(context->env->mutex == NULL || !cpi_is_mutex_locked(context->env->mutex)); #else assert(!context->env->locked); #endif // Remove context from the context list cpi_lock_framework(); if (contexts != NULL) { lnode_t *node; if ((node = list_find(contexts, context, cpi_comp_ptr)) != NULL) { list_delete(contexts, node); lnode_destroy(node); } } cpi_unlock_framework(); // Unload all plug-ins cp_uninstall_plugins(context); // Unregister all plug-in loaders cp_unregister_ploaders(context); // Unregister implicit local plug-in loader, if any if (context->env->local_loader != NULL) { cp_unregister_ploader(context, context->env->local_loader); } // Release remaining information objects cpi_release_infos(context); // Free context cpi_free_context(context); }
static void do_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) { lnode_t *node; const char *apid = NULL; assert(cpi_is_context_locked(context)); if (context->env->in_logger_invocation) { cpi_fatalf(_("Encountered a recursive logging request within a logger invocation.")); } if (context->plugin != NULL) { apid = context->plugin->plugin->identifier; } context->env->in_logger_invocation++; node = list_first(context->env->loggers); while (node != NULL) { logger_t *lh = lnode_get(node); if (severity >= lh->min_severity) { lh->logger(severity, msg, apid, lh->user_data); } node = list_next(context->env->loggers, node); } context->env->in_logger_invocation--; }