]> sigrok.org Git - libsigrokdecode.git/blobdiff - irmp/irmp-main-sharedlib.c
ir_irmp: wrapper lib, add locking and Python threading support
[libsigrokdecode.git] / irmp / irmp-main-sharedlib.c
index cbf239a3341eab68975eb4f419a1856fb6bcecdb..4d02460014baa4687429bc8cd7a79ad0261c8247 100644 (file)
@@ -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>
 
 #  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();
+}