From 514b2edc54efda9c6698456748c4256bb901eddd Mon Sep 17 00:00:00 2001 From: Uwe Hermann Date: Wed, 28 Jun 2017 22:29:06 +0200 Subject: Acquire/release the Python GIL where needed to avoid threading issues. With these additions, frontends can now call libsigrokdecode API functions from different threads without running into threading issues. The backend releases the GIL when it is performing tasks that might take a while and it doesn't need to run Python/C API calls during that time. This allows frontends to run multiple PD stacks (in multiple frontend threads) "at the same time" in a time-sharing, "interlocked" manner. Whenever one of the decoders is inside e.g. self.wait() it releases the GIL and thus allows other decoders to do some work in the mean time. The user-visible effect is that for use-cases such as running 3 different decoder stacks at the same time for an acquisition, the user will not have to wait for PD 1 to finish decoding, then wait for PD 2 to finish decoding, and only *then* being able to see annotations from PD 3. Instead, all three PDs will decode some chunks of data from time to time, thus the user is able to inspect annotations from all 3 PDs while the acquisition and decoding is still going on. --- util.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 21 deletions(-) (limited to 'util.c') diff --git a/util.c b/util.c index 9a573cc..430a7fb 100644 --- a/util.c +++ b/util.c @@ -36,14 +36,21 @@ SRD_PRIV PyObject *py_import_by_name(const char *name) { PyObject *py_mod, *py_modname; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); py_modname = PyUnicode_FromString(name); - if (!py_modname) + if (!py_modname) { + PyGILState_Release(gstate); return NULL; + } py_mod = PyImport_Import(py_modname); Py_DECREF(py_modname); + PyGILState_Release(gstate); + return py_mod; } @@ -64,21 +71,31 @@ SRD_PRIV int py_attr_as_str(PyObject *py_obj, const char *attr, char **outstr) { PyObject *py_str; int ret; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!PyObject_HasAttrString(py_obj, attr)) { srd_dbg("Object has no attribute '%s'.", attr); - return SRD_ERR_PYTHON; + goto err; } if (!(py_str = PyObject_GetAttrString(py_obj, attr))) { srd_exception_catch("Failed to get attribute '%s'", attr); - return SRD_ERR_PYTHON; + goto err; } ret = py_str_as_str(py_str, outstr); Py_DECREF(py_str); + PyGILState_Release(gstate); + return ret; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @@ -101,20 +118,23 @@ SRD_PRIV int py_attr_as_strlist(PyObject *py_obj, const char *attr, GSList **out Py_ssize_t i; int ret; char *outstr; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!PyObject_HasAttrString(py_obj, attr)) { srd_dbg("Object has no attribute '%s'.", attr); - return SRD_ERR_PYTHON; + goto err; } if (!(py_list = PyObject_GetAttrString(py_obj, attr))) { srd_exception_catch("Failed to get attribute '%s'", attr); - return SRD_ERR_PYTHON; + goto err; } if (!PyList_Check(py_list)) { srd_dbg("Object is not a list."); - return SRD_ERR_PYTHON; + goto err; } *outstrlist = NULL; @@ -123,14 +143,21 @@ SRD_PRIV int py_attr_as_strlist(PyObject *py_obj, const char *attr, GSList **out ret = py_listitem_as_str(py_list, i, &outstr); if (ret < 0) { srd_dbg("Couldn't get item %" PY_FORMAT_SIZE_T "d.", i); - return SRD_ERR_PYTHON; + goto err; } *outstrlist = g_slist_append(*outstrlist, outstr); } Py_DECREF(py_list); + PyGILState_Release(gstate); + return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @@ -150,18 +177,28 @@ SRD_PRIV int py_dictitem_as_str(PyObject *py_obj, const char *key, char **outstr) { PyObject *py_value; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!PyDict_Check(py_obj)) { srd_dbg("Object is not a dictionary."); - return SRD_ERR_PYTHON; + goto err; } if (!(py_value = PyDict_GetItemString(py_obj, key))) { srd_dbg("Dictionary has no attribute '%s'.", key); - return SRD_ERR_PYTHON; + goto err; } + PyGILState_Release(gstate); + return py_str_as_str(py_value, outstr); + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @@ -181,18 +218,28 @@ SRD_PRIV int py_listitem_as_str(PyObject *py_obj, Py_ssize_t idx, char **outstr) { PyObject *py_value; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!PyList_Check(py_obj)) { srd_dbg("Object is not a list."); - return SRD_ERR_PYTHON; + goto err; } if (!(py_value = PyList_GetItem(py_obj, idx))) { srd_dbg("Couldn't get list item %" PY_FORMAT_SIZE_T "d.", idx); - return SRD_ERR_PYTHON; + goto err; } + PyGILState_Release(gstate); + return py_str_as_str(py_value, outstr); + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @@ -212,26 +259,34 @@ SRD_PRIV int py_pydictitem_as_str(PyObject *py_obj, PyObject *py_key, char **outstr) { PyObject *py_value; + PyGILState_STATE gstate; if (!py_obj || !py_key || !outstr) return SRD_ERR_ARG; + gstate = PyGILState_Ensure(); + if (!PyDict_Check(py_obj)) { srd_dbg("Object is not a dictionary."); - return SRD_ERR_PYTHON; + goto err; } if (!(py_value = PyDict_GetItem(py_obj, py_key))) { srd_dbg("Dictionary has no such key."); - return SRD_ERR_PYTHON; + goto err; } if (!PyUnicode_Check(py_value)) { srd_dbg("Dictionary value should be a string."); - return SRD_ERR_PYTHON; + goto err; } return py_str_as_str(py_value, outstr); + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @@ -249,28 +304,38 @@ SRD_PRIV int py_pydictitem_as_str(PyObject *py_obj, PyObject *py_key, SRD_PRIV int py_pydictitem_as_long(PyObject *py_obj, PyObject *py_key, uint64_t *out) { PyObject *py_value; + PyGILState_STATE gstate; if (!py_obj || !py_key || !out) return SRD_ERR_ARG; + gstate = PyGILState_Ensure(); + if (!PyDict_Check(py_obj)) { srd_dbg("Object is not a dictionary."); - return SRD_ERR_PYTHON; + goto err; } if (!(py_value = PyDict_GetItem(py_obj, py_key))) { srd_dbg("Dictionary has no such key."); - return SRD_ERR_PYTHON; + goto err; } if (!PyLong_Check(py_value)) { srd_dbg("Dictionary value should be a long."); - return SRD_ERR_PYTHON; + goto err; } *out = PyLong_AsUnsignedLongLong(py_value); + PyGILState_Release(gstate); + return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @@ -289,9 +354,13 @@ SRD_PRIV int py_str_as_str(PyObject *py_str, char **outstr) { PyObject *py_bytes; char *str; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!PyUnicode_Check(py_str)) { srd_dbg("Object is not a string object."); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -301,11 +370,14 @@ SRD_PRIV int py_str_as_str(PyObject *py_str, char **outstr) Py_DECREF(py_bytes); if (str) { *outstr = str; + PyGILState_Release(gstate); return SRD_OK; } } srd_exception_catch("Failed to extract string"); + PyGILState_Release(gstate); + return SRD_ERR_PYTHON; } @@ -327,22 +399,27 @@ SRD_PRIV int py_strseq_to_char(PyObject *py_strseq, char ***out_strv) PyObject *py_item, *py_bytes; char **strv, *str; ssize_t seq_len, i; + PyGILState_STATE gstate; + int ret = SRD_ERR_PYTHON; + + gstate = PyGILState_Ensure(); if (!PySequence_Check(py_strseq)) { srd_err("Object does not provide sequence protocol."); - return SRD_ERR_PYTHON; + goto err; } seq_len = PySequence_Size(py_strseq); if (seq_len < 0) { srd_exception_catch("Failed to obtain sequence size"); - return SRD_ERR_PYTHON; + goto err; } strv = g_try_new0(char *, seq_len + 1); if (!strv) { srd_err("Failed to allocate result string vector."); - return SRD_ERR_MALLOC; + ret = SRD_ERR_MALLOC; + goto err; } for (i = 0; i < seq_len; i++) { @@ -374,7 +451,10 @@ err_out: g_strfreev(strv); srd_exception_catch("Failed to obtain string item"); - return SRD_ERR_PYTHON; +err: + PyGILState_Release(gstate); + + return ret; } /** @@ -389,6 +469,9 @@ err_out: SRD_PRIV GVariant *py_obj_to_variant(PyObject *py_obj) { GVariant *var = NULL; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (PyUnicode_Check(py_obj)) { /* string */ PyObject *py_bytes; @@ -426,5 +509,7 @@ SRD_PRIV GVariant *py_obj_to_variant(PyObject *py_obj) srd_err("Failed to extract value of unsupported type."); } + PyGILState_Release(gstate); + return var; } -- cgit v1.2.3-70-g09d2