diff options
author | Gerhard Sittig <gerhard.sittig@gmx.net> | 2021-12-26 08:23:27 +0100 |
---|---|---|
committer | Gerhard Sittig <gerhard.sittig@gmx.net> | 2021-12-26 13:45:09 +0100 |
commit | 7cfa9f7aa2426c617990f3ecfcabed8765aff46c (patch) | |
tree | e3edca5bcd18328b0cd91049a6bbd0aa3c666aa3 /irmp | |
parent | de219b2b77dba06815869823789458581500ca03 (diff) | |
download | libsigrokdecode-7cfa9f7aa2426c617990f3ecfcabed8765aff46c.tar.gz libsigrokdecode-7cfa9f7aa2426c617990f3ecfcabed8765aff46c.zip |
ir_irmp: wrapper lib, add locking and Python threading support
The IRMP core library is not thread safe (known limitation, heritage of
the AVR firmware origin). Add a mutex so that calling applications can
lock IR decoder core instances. Allow Python threading while waiting for
the locks, we can safely assume that this IRMP wrapper is used in the
sigrok context which does require Python for decoders. Add my copyright
for the non-trivial changes.
This implementation uses glib for locking to improve portability, which
already is a dependency of the libsigrokdecode component. This version
uses belt and suspenders by implementing a constructor as well as adding
auto init calls to each of the public API code paths. The client ID is
not an essential requirement, but useful during application maintenance.
Diffstat (limited to 'irmp')
-rw-r--r-- | irmp/irmp-main-sharedlib.c | 112 | ||||
-rw-r--r-- | irmp/irmp-main-sharedlib.h | 44 |
2 files changed, 156 insertions, 0 deletions
diff --git a/irmp/irmp-main-sharedlib.c b/irmp/irmp-main-sharedlib.c index cbf239a..4d02460 100644 --- a/irmp/irmp-main-sharedlib.c +++ b/irmp/irmp-main-sharedlib.c @@ -3,6 +3,7 @@ * * Copyright (c) 2009-2019 Frank Meyer - frank(at)fli4l.de * Copyright (c) 2009-2019 René Staffen - r.staffen(at)gmx.de + * Copyright (c) 2020-2021 Gerhard Sittig <gerhard.sittig@gmx.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,6 +17,9 @@ */ #include "irmp-main-sharedlib.h" +#include <errno.h> +#include <glib.h> +#include <Python.h> #include <stdlib.h> #include <string.h> @@ -98,6 +102,109 @@ # define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif +static int irmp_lib_initialized; +static size_t irmp_lib_client_id; +static GMutex irmp_lib_mutex; + +struct irmp_instance { + size_t client_id; + GMutex *mutex; +}; + +static void irmp_lib_autoinit(void) +{ + if (irmp_lib_initialized) + return; + + irmp_lib_client_id = 0; + g_mutex_init(&irmp_lib_mutex); + + irmp_lib_initialized = 1; +} + +static size_t irmp_next_client_id(void) +{ + size_t id; + + do { + id = ++irmp_lib_client_id; + } while (!id); + + return id; +} + +IRMP_DLLEXPORT struct irmp_instance *irmp_instance_alloc(void) +{ + struct irmp_instance *inst; + + irmp_lib_autoinit(); + + inst = g_malloc0(sizeof(*inst)); + if (!inst) + return NULL; + + inst->client_id = irmp_next_client_id(); + inst->mutex = &irmp_lib_mutex; + + return inst; +} + +IRMP_DLLEXPORT void irmp_instance_free(struct irmp_instance *state) +{ + + irmp_lib_autoinit(); + + if (!state) + return; + + g_free(state); +} + +IRMP_DLLEXPORT size_t irmp_instance_id(struct irmp_instance *state) +{ + + irmp_lib_autoinit(); + + return state ? state->client_id : 0; +} + +IRMP_DLLEXPORT int irmp_instance_lock(struct irmp_instance *state, int wait) +{ + int rc; + PyGILState_STATE pyst; + + irmp_lib_autoinit(); + + if (!state || !state->mutex) + return -EINVAL; + + pyst = PyGILState_Ensure(); + Py_BEGIN_ALLOW_THREADS + if (wait) { + g_mutex_lock(state->mutex); + rc = 0; + } else { + rc = g_mutex_trylock(state->mutex); + } + Py_END_ALLOW_THREADS + PyGILState_Release(pyst); + if (rc != 0) + return rc; + + return 0; +} + +IRMP_DLLEXPORT void irmp_instance_unlock(struct irmp_instance *state) +{ + + irmp_lib_autoinit(); + + if (!state || !state->mutex) + return; + + g_mutex_unlock(state->mutex); +} + static uint32_t s_end_sample; IRMP_DLLEXPORT uint32_t irmp_get_sample_rate(void) @@ -195,3 +302,8 @@ IRMP_DLLEXPORT const char *irmp_get_protocol_name(uint32_t protocol) return "unknown"; return name; } + +static __attribute__((constructor)) void init(void) +{ + irmp_lib_autoinit(); +} diff --git a/irmp/irmp-main-sharedlib.h b/irmp/irmp-main-sharedlib.h index 94065f3..67e7997 100644 --- a/irmp/irmp-main-sharedlib.h +++ b/irmp/irmp-main-sharedlib.h @@ -3,6 +3,7 @@ * * Copyright (c) 2009-2019 Frank Meyer - frank(at)fli4l.de * Copyright (c) 2009-2019 René Staffen - r.staffen(at)gmx.de + * Copyright (c) 2020-2021 Gerhard Sittig <gerhard.sittig@gmx.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -33,6 +34,49 @@ extern "C" { #define WITH_IRMP_DETECT_BUFFER 0 /** + * @brief State container for a decoder core instance. Opaque to clients. + */ +struct irmp_instance; + +/** + * @brief Allocate a decoder instance. + * + * @returns Reference to the allocated instance state. + */ +IRMP_DLLEXPORT struct irmp_instance *irmp_instance_alloc(void); + +/** + * @brief Release a decoder instance. + * + * @param[in] state Reference to the instance's state. + */ +IRMP_DLLEXPORT void irmp_instance_free(struct irmp_instance *state); + +/** + * @brief Get the client ID of an IRMP decoder core instance. + */ +IRMP_DLLEXPORT size_t irmp_instance_id(struct irmp_instance *state); + +/** + * @brief Acquire a decoder instance's lock. + * + * @param[in] state Reference to the instance's state. + * @param[in] wait Whether to block until the lock is acquired. + * + * @returns 0 upon success, non-zero upon failure + */ +IRMP_DLLEXPORT int irmp_instance_lock(struct irmp_instance *state, int wait); + +/** + * @brief Release a decoder instance's lock. + * + * @param[in] state Reference to the instance's state. + * + * @returns 0 upon success, non-zero upon failure + */ +IRMP_DLLEXPORT void irmp_instance_unlock(struct irmp_instance *state); + +/** * @brief IR decoder result data at the library's public API. */ struct irmp_result_data { |