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. --- decoder.c | 86 +++++++++++++++++++-- exception.c | 9 +++ instance.c | 30 +++++++- module_sigrokdecode.c | 6 ++ session.c | 5 ++ srd.c | 30 +++++++- type_decoder.c | 207 ++++++++++++++++++++++++++++++++++++++++---------- util.c | 127 ++++++++++++++++++++++++++----- 8 files changed, 427 insertions(+), 73 deletions(-) diff --git a/decoder.c b/decoder.c index d7395a6..2fece88 100644 --- a/decoder.c +++ b/decoder.c @@ -152,11 +152,15 @@ static void decoder_option_free(void *data) static void decoder_free(struct srd_decoder *dec) { + PyGILState_STATE gstate; + if (!dec) return; + gstate = PyGILState_Ensure(); Py_XDECREF(dec->py_dec); Py_XDECREF(dec->py_mod); + PyGILState_Release(gstate); g_slist_free_full(dec->options, &decoder_option_free); g_slist_free_full(dec->binary, (GDestroyNotify)&g_strfreev); @@ -183,10 +187,15 @@ static int get_channels(const struct srd_decoder *d, const char *attr, struct srd_channel *pdch; GSList *pdchl; ssize_t i; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); - if (!PyObject_HasAttrString(d->py_dec, attr)) + if (!PyObject_HasAttrString(d->py_dec, attr)) { /* No channels of this type specified. */ + PyGILState_Release(gstate); return SRD_OK; + } pdchl = NULL; @@ -227,6 +236,8 @@ static int get_channels(const struct srd_decoder *d, const char *attr, Py_DECREF(py_channellist); *out_pdchl = pdchl; + PyGILState_Release(gstate); + return SRD_OK; except_out: @@ -235,6 +246,7 @@ except_out: err_out: g_slist_free_full(pdchl, &channel_free); Py_XDECREF(py_channellist); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -246,10 +258,15 @@ static int get_options(struct srd_decoder *d) struct srd_decoder_option *o; GVariant *gvar; ssize_t opt, i; + PyGILState_STATE gstate; - if (!PyObject_HasAttrString(d->py_dec, "options")) + gstate = PyGILState_Ensure(); + + if (!PyObject_HasAttrString(d->py_dec, "options")) { /* No options, that's fine. */ + PyGILState_Release(gstate); return SRD_OK; + } options = NULL; @@ -342,6 +359,7 @@ static int get_options(struct srd_decoder *d) } d->options = options; Py_DECREF(py_opts); + PyGILState_Release(gstate); return SRD_OK; @@ -350,6 +368,7 @@ except_out: err_out: g_slist_free_full(options, &decoder_option_free); Py_XDECREF(py_opts); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -362,9 +381,14 @@ static int get_annotations(struct srd_decoder *dec) GSList *annotations; char **annpair; ssize_t i; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); - if (!PyObject_HasAttrString(dec->py_dec, "annotations")) + if (!PyObject_HasAttrString(dec->py_dec, "annotations")) { + PyGILState_Release(gstate); return SRD_OK; + } annotations = NULL; @@ -396,6 +420,7 @@ static int get_annotations(struct srd_decoder *dec) } dec->annotations = annotations; Py_DECREF(py_annlist); + PyGILState_Release(gstate); return SRD_OK; @@ -404,6 +429,7 @@ except_out: err_out: g_slist_free_full(annotations, (GDestroyNotify)&g_strfreev); Py_XDECREF(py_annlist); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -417,9 +443,14 @@ static int get_annotation_rows(struct srd_decoder *dec) struct srd_decoder_annotation_row *ann_row; ssize_t i, k; size_t class_idx; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); - if (!PyObject_HasAttrString(dec->py_dec, "annotation_rows")) + if (!PyObject_HasAttrString(dec->py_dec, "annotation_rows")) { + PyGILState_Release(gstate); return SRD_OK; + } annotation_rows = NULL; @@ -492,6 +523,7 @@ static int get_annotation_rows(struct srd_decoder *dec) } dec->annotation_rows = annotation_rows; Py_DECREF(py_ann_rows); + PyGILState_Release(gstate); return SRD_OK; @@ -501,6 +533,7 @@ except_out: err_out: g_slist_free_full(annotation_rows, &annotation_row_free); Py_XDECREF(py_ann_rows); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -513,9 +546,14 @@ static int get_binary_classes(struct srd_decoder *dec) GSList *bin_classes; char **bin; ssize_t i; + PyGILState_STATE gstate; - if (!PyObject_HasAttrString(dec->py_dec, "binary")) + gstate = PyGILState_Ensure(); + + if (!PyObject_HasAttrString(dec->py_dec, "binary")) { + PyGILState_Release(gstate); return SRD_OK; + } bin_classes = NULL; @@ -548,6 +586,7 @@ static int get_binary_classes(struct srd_decoder *dec) } dec->binary = bin_classes; Py_DECREF(py_bin_classes); + PyGILState_Release(gstate); return SRD_OK; @@ -557,6 +596,7 @@ except_out: err_out: g_slist_free_full(bin_classes, (GDestroyNotify)&g_strfreev); Py_XDECREF(py_bin_classes); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -568,17 +608,23 @@ static int check_method(PyObject *py_dec, const char *mod_name, { PyObject *py_method; int is_callable; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); py_method = PyObject_GetAttrString(py_dec, method_name); if (!py_method) { srd_exception_catch("Protocol decoder %s Decoder class " "has no %s() method", mod_name, method_name); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } is_callable = PyCallable_Check(py_method); Py_DECREF(py_method); + PyGILState_Release(gstate); + if (!is_callable) { srd_err("Protocol decoder %s Decoder class attribute '%s' " "is not a method.", mod_name, method_name); @@ -601,15 +647,20 @@ SRD_PRIV long srd_decoder_apiver(const struct srd_decoder *d) { PyObject *py_apiver; long apiver; + PyGILState_STATE gstate; if (!d) return 0; + gstate = PyGILState_Ensure(); + py_apiver = PyObject_GetAttrString(d->py_dec, "api_version"); apiver = (py_apiver && PyLong_Check(py_apiver)) ? PyLong_AsLong(py_apiver) : 0; Py_XDECREF(py_apiver); + PyGILState_Release(gstate); + return apiver; } @@ -629,6 +680,7 @@ SRD_API int srd_decoder_load(const char *module_name) long apiver; int is_subclass; const char *fail_txt; + PyGILState_STATE gstate; if (!srd_check_init()) return SRD_ERR; @@ -636,8 +688,11 @@ SRD_API int srd_decoder_load(const char *module_name) if (!module_name) return SRD_ERR_ARG; + gstate = PyGILState_Ensure(); + if (PyDict_GetItemString(PyImport_GetModuleDict(), module_name)) { /* Module was already imported. */ + PyGILState_Release(gstate); return SRD_OK; } @@ -775,6 +830,8 @@ SRD_API int srd_decoder_load(const char *module_name) goto err_out; } + PyGILState_Release(gstate); + /* Append it to the list of loaded decoders. */ pd_list = g_slist_append(pd_list, d); @@ -791,6 +848,7 @@ err_out: if (fail_txt) srd_err("Failed to load decoder %s: %s", module_name, fail_txt); decoder_free(d); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } @@ -809,6 +867,7 @@ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) { PyObject *py_str; char *doc; + PyGILState_STATE gstate; if (!srd_check_init()) return NULL; @@ -816,12 +875,14 @@ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) if (!dec) return NULL; + gstate = PyGILState_Ensure(); + if (!PyObject_HasAttrString(dec->py_mod, "__doc__")) - return NULL; + goto err; if (!(py_str = PyObject_GetAttrString(dec->py_mod, "__doc__"))) { srd_exception_catch("Failed to get docstring"); - return NULL; + goto err; } doc = NULL; @@ -829,7 +890,14 @@ SRD_API char *srd_decoder_doc_get(const struct srd_decoder *dec) py_str_as_str(py_str, &doc); Py_DECREF(py_str); + PyGILState_Release(gstate); + return doc; + +err: + PyGILState_Release(gstate); + + return NULL; } /** @@ -880,9 +948,12 @@ static void srd_decoder_load_all_zip_path(char *path) Py_ssize_t pos = 0; char *prefix; size_t prefix_len; + PyGILState_STATE gstate; set = files = prefix_obj = zipimporter = zipimporter_class = NULL; + gstate = PyGILState_Ensure(); + zipimport_mod = py_import_by_name("zipimport"); if (zipimport_mod == NULL) goto err_out; @@ -951,6 +1022,7 @@ err_out: Py_XDECREF(zipimporter_class); Py_XDECREF(zipimport_mod); PyErr_Clear(); + PyGILState_Release(gstate); } static void srd_decoder_load_all_path(char *path) diff --git a/exception.c b/exception.c index 7027df5..b440758 100644 --- a/exception.c +++ b/exception.c @@ -28,6 +28,8 @@ static char *py_stringify(PyObject *py_obj) PyObject *py_str, *py_bytes; char *str = NULL; + /* Note: Caller already ran PyGILState_Ensure(). */ + if (!py_obj) return NULL; @@ -56,6 +58,8 @@ static char *py_get_string_attr(PyObject *py_obj, const char *attr) PyObject *py_str, *py_bytes; char *str = NULL; + /* Note: Caller already ran PyGILState_Ensure(). */ + if (!py_obj) return NULL; @@ -87,6 +91,7 @@ SRD_PRIV void srd_exception_catch(const char *format, ...) PyObject *py_mod, *py_func, *py_tracefmt; char *msg, *etype_name, *evalue_str, *tracefmt_str; const char *etype_name_fallback; + PyGILState_STATE gstate; py_etype = py_evalue = py_etraceback = py_mod = py_func = NULL; @@ -94,6 +99,8 @@ SRD_PRIV void srd_exception_catch(const char *format, ...) msg = g_strdup_vprintf(format, args); va_end(args); + gstate = PyGILState_Ensure(); + PyErr_Fetch(&py_etype, &py_evalue, &py_etraceback); if (!py_etype) { /* No current exception, so just print the message. */ @@ -151,5 +158,7 @@ cleanup: /* Just in case. */ PyErr_Clear(); + PyGILState_Release(gstate); + g_free(msg); } diff --git a/instance.c b/instance.c index 3327926..a47ce69 100644 --- a/instance.c +++ b/instance.c @@ -73,6 +73,7 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, gint64 val_int; int ret; const char *val_str; + PyGILState_STATE gstate; if (!di) { srd_err("Invalid decoder instance."); @@ -84,8 +85,11 @@ SRD_API int srd_inst_option_set(struct srd_decoder_inst *di, return SRD_ERR_ARG; } + gstate = PyGILState_Ensure(); + if (!PyObject_HasAttrString(di->decoder->py_dec, "options")) { /* Decoder has no options. */ + PyGILState_Release(gstate); if (g_hash_table_size(options) == 0) { /* No options provided. */ return SRD_OK; @@ -167,6 +171,7 @@ err_out: srd_exception_catch("Stray exception in srd_inst_option_set()"); ret = SRD_ERR_PYTHON; } + PyGILState_Release(gstate); return ret; } @@ -297,6 +302,7 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, struct srd_decoder *dec; struct srd_decoder_inst *di; char *inst_id; + PyGILState_STATE gstate; i = 1; srd_dbg("Creating new %s instance.", decoder_id); @@ -357,16 +363,21 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, memset(di->old_pins_array->data, SRD_INITIAL_PIN_SAME_AS_SAMPLE0, di->dec_num_channels); + gstate = PyGILState_Ensure(); + /* Create a new instance of this decoder class. */ if (!(di->py_inst = PyObject_CallObject(dec->py_dec, NULL))) { if (PyErr_Occurred()) srd_exception_catch("Failed to create %s instance", decoder_id); + PyGILState_Release(gstate); g_free(di->dec_channelmap); g_free(di); return NULL; } + PyGILState_Release(gstate); + if (options && srd_inst_option_set(di, options) != SRD_OK) { g_free(di->dec_channelmap); g_free(di); @@ -477,7 +488,6 @@ SRD_API int srd_inst_stack(struct srd_session *sess, struct srd_decoder_inst *di_bottom, struct srd_decoder_inst *di_top) { - if (session_is_valid(sess) != SRD_OK) { srd_err("Invalid session."); return SRD_ERR_ARG; @@ -694,14 +704,18 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di) GSList *l; struct srd_decoder_inst *next_di; int ret; + PyGILState_STATE gstate; srd_dbg("Calling start() method on protocol decoder instance %s.", di->inst_id); + gstate = PyGILState_Ensure(); + /* Run self.start(). */ if (!(py_res = PyObject_CallMethod(di->py_inst, "start", NULL))) { srd_exception_catch("Protocol decoder instance %s", di->inst_id); + PyGILState_Release(gstate); return SRD_ERR_PYTHON; } Py_DecRef(py_res); @@ -712,6 +726,8 @@ SRD_PRIV int srd_inst_start(struct srd_decoder_inst *di) /* Set self.matched to None. */ PyObject_SetAttrString(di->py_inst, "matched", Py_None); + PyGILState_Release(gstate); + /* Start all the PDs stacked on top of this one. */ for (l = di->next_di; l; l = l->next) { next_di = l->data; @@ -1033,6 +1049,7 @@ static gpointer di_thread(gpointer data) PyObject *py_res; struct srd_decoder_inst *di; int wanted_term; + PyGILState_STATE gstate; if (!data) return NULL; @@ -1041,6 +1058,8 @@ static gpointer di_thread(gpointer data) srd_dbg("%s: Starting thread routine for decoder.", di->inst_id); + gstate = PyGILState_Ensure(); + /* * Call self.decode(). Only returns if the PD throws an exception. * "Regular" termination of the decode() method is not expected. @@ -1076,6 +1095,7 @@ static gpointer di_thread(gpointer data) */ srd_dbg("%s: Thread done (!res, want_term).", di->inst_id); PyErr_Clear(); + PyGILState_Release(gstate); return NULL; } if (!py_res) { @@ -1087,6 +1107,7 @@ static gpointer di_thread(gpointer data) srd_dbg("%s: decode() terminated unrequested.", di->inst_id); srd_exception_catch("Protocol decoder instance %s: ", di->inst_id); srd_dbg("%s: Thread done (!res, !want_term).", di->inst_id); + PyGILState_Release(gstate); return NULL; } @@ -1099,6 +1120,8 @@ static gpointer di_thread(gpointer data) Py_DecRef(py_res); PyErr_Clear(); + PyGILState_Release(gstate); + srd_dbg("%s: Thread done (with res).", di->inst_id); return NULL; @@ -1228,13 +1251,18 @@ SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di) { GSList *l; struct srd_pd_output *pdo; + PyGILState_STATE gstate; srd_dbg("Freeing instance %s", di->inst_id); srd_inst_join_decode_thread(di); + srd_inst_reset_state(di); + gstate = PyGILState_Ensure(); Py_DecRef(di->py_inst); + PyGILState_Release(gstate); + g_free(di->inst_id); g_free(di->dec_channelmap); g_free(di->channel_samples); diff --git a/module_sigrokdecode.c b/module_sigrokdecode.c index a0d9610..ab5df19 100644 --- a/module_sigrokdecode.c +++ b/module_sigrokdecode.c @@ -42,6 +42,9 @@ static struct PyModuleDef sigrokdecode_module = { PyMODINIT_FUNC PyInit_sigrokdecode(void) { PyObject *mod, *Decoder_type; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); mod = PyModule_Create(&sigrokdecode_module); if (!mod) @@ -68,10 +71,13 @@ PyMODINIT_FUNC PyInit_sigrokdecode(void) mod_sigrokdecode = mod; + PyGILState_Release(gstate); + return mod; err_out: Py_XDECREF(mod); srd_exception_catch("Failed to initialize module"); + PyGILState_Release(gstate); return NULL; } diff --git a/session.c b/session.c index 1448450..0c1ef82 100644 --- a/session.c +++ b/session.c @@ -131,11 +131,14 @@ static int srd_inst_send_meta(struct srd_decoder_inst *di, int key, GSList *l; struct srd_decoder_inst *next_di; int ret; + PyGILState_STATE gstate; if (key != SRD_CONF_SAMPLERATE) /* This is the only key we pass on to the decoder for now. */ return SRD_OK; + gstate = PyGILState_Ensure(); + if (PyObject_HasAttrString(di->py_inst, "metadata")) { py_ret = PyObject_CallMethod(di->py_inst, "metadata", "lK", (long)SRD_CONF_SAMPLERATE, @@ -143,6 +146,8 @@ static int srd_inst_send_meta(struct srd_decoder_inst *di, int key, Py_XDECREF(py_ret); } + PyGILState_Release(gstate); + /* Push metadata to all the PDs stacked on top of this one. */ for (l = di->next_di; l; l = l->next) { next_di = l->data; diff --git a/srd.c b/srd.c index e8fd751..efd1c8e 100644 --- a/srd.c +++ b/srd.c @@ -232,6 +232,12 @@ SRD_API int srd_init(const char *path) } } + /* Initialize the Python GIL (this also happens to acquire it). */ + PyEval_InitThreads(); + + /* Release the GIL (ignore return value, we don't need it here). */ + (void)PyEval_SaveThread(); + max_session_id = 0; return SRD_OK; @@ -261,9 +267,17 @@ SRD_API int srd_exit(void) g_slist_free_full(searchpaths, g_free); searchpaths = NULL; + /* + * Acquire the GIL, otherwise Py_Finalize() might have issues. + * Ignore the return value, we don't need it here. + */ + (void)PyGILState_Ensure(); + /* Py_Finalize() returns void, any finalization errors are ignored. */ Py_Finalize(); + /* Note: No need to release the GIL since Python is shut down now. */ + max_session_id = -1; return SRD_OK; @@ -291,28 +305,38 @@ SRD_API int srd_exit(void) SRD_PRIV int srd_decoder_searchpath_add(const char *path) { PyObject *py_cur_path, *py_item; + PyGILState_STATE gstate; srd_dbg("Adding '%s' to module path.", path); + gstate = PyGILState_Ensure(); + py_cur_path = PySys_GetObject("path"); if (!py_cur_path) - return SRD_ERR_PYTHON; + goto err; py_item = PyUnicode_FromString(path); if (!py_item) { srd_exception_catch("Failed to create Unicode object"); - return SRD_ERR_PYTHON; + goto err; } if (PyList_Insert(py_cur_path, 0, py_item) < 0) { srd_exception_catch("Failed to insert path element"); Py_DECREF(py_item); - return SRD_ERR_PYTHON; + goto err; } Py_DECREF(py_item); + PyGILState_Release(gstate); + searchpaths = g_slist_prepend(searchpaths, g_strdup(path)); return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } /** @} */ diff --git a/type_decoder.c b/type_decoder.c index 231a893..f203377 100644 --- a/type_decoder.c +++ b/type_decoder.c @@ -48,12 +48,15 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, struct srd_proto_data_annotation *pda; int ann_class; char **ann_text; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); /* Should be a list of [annotation class, [string, ...]]. */ if (!PyList_Check(obj)) { srd_err("Protocol decoder %s submitted an annotation that" " is not a list", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } /* Should have 2 elements. */ @@ -61,7 +64,7 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, srd_err("Protocol decoder %s submitted annotation list with " "%zd elements instead of 2", di->decoder->name, PyList_Size(obj)); - return SRD_ERR_PYTHON; + goto err; } /* @@ -72,13 +75,13 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, if (!PyLong_Check(py_tmp)) { srd_err("Protocol decoder %s submitted annotation list, but " "first element was not an integer.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } ann_class = PyLong_AsLong(py_tmp); if (!(pdo = g_slist_nth_data(di->decoder->annotations, ann_class))) { srd_err("Protocol decoder %s submitted data to unregistered " "annotation class %d.", di->decoder->name, ann_class); - return SRD_ERR_PYTHON; + goto err; } /* Second element must be a list. */ @@ -86,12 +89,12 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, if (!PyList_Check(py_tmp)) { srd_err("Protocol decoder %s submitted annotation list, but " "second element was not a list.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } if (py_strseq_to_char(py_tmp, &ann_text) != SRD_OK) { srd_err("Protocol decoder %s submitted annotation list, but " "second element was malformed.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } pda = g_malloc(sizeof(struct srd_proto_data_annotation)); @@ -99,7 +102,14 @@ static int convert_annotation(struct srd_decoder_inst *di, PyObject *obj, pda->ann_text = ann_text; pdata->data = pda; + PyGILState_Release(gstate); + return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, @@ -110,12 +120,15 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, Py_ssize_t size; int bin_class; char *class_name, *buf; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); /* Should be a list of [binary class, bytes]. */ if (!PyList_Check(obj)) { srd_err("Protocol decoder %s submitted non-list for SRD_OUTPUT_BINARY.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } /* Should have 2 elements. */ @@ -123,7 +136,7 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list " "with %zd elements instead of 2", di->decoder->name, PyList_Size(obj)); - return SRD_ERR_PYTHON; + goto err; } /* The first element should be an integer. */ @@ -131,13 +144,13 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, if (!PyLong_Check(py_tmp)) { srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, " "but first element was not an integer.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } bin_class = PyLong_AsLong(py_tmp); if (!(class_name = g_slist_nth_data(di->decoder->binary, bin_class))) { srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY with " "unregistered binary class %d.", di->decoder->name, bin_class); - return SRD_ERR_PYTHON; + goto err; } /* Second element should be bytes. */ @@ -145,19 +158,22 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, if (!PyBytes_Check(py_tmp)) { srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY list, " "but second element was not bytes.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } /* Consider an empty set of bytes a bug. */ if (PyBytes_Size(py_tmp) == 0) { srd_err("Protocol decoder %s submitted SRD_OUTPUT_BINARY " "with empty data set.", di->decoder->name); - return SRD_ERR_PYTHON; + goto err; } pdb = g_malloc(sizeof(struct srd_proto_data_binary)); if (PyBytes_AsStringAndSize(py_tmp, &buf, &size) == -1) - return SRD_ERR_PYTHON; + goto err; + + PyGILState_Release(gstate); + pdb->bin_class = bin_class; pdb->size = size; if (!(pdb->data = g_try_malloc(pdb->size))) @@ -166,36 +182,51 @@ static int convert_binary(struct srd_decoder_inst *di, PyObject *obj, pdata->data = pdb; return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } static int convert_meta(struct srd_proto_data *pdata, PyObject *obj) { long long intvalue; double dvalue; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (pdata->pdo->meta_type == G_VARIANT_TYPE_INT64) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "This output was registered " "as 'int', but something else was passed."); - return SRD_ERR_PYTHON; + goto err; } intvalue = PyLong_AsLongLong(obj); if (PyErr_Occurred()) - return SRD_ERR_PYTHON; + goto err; pdata->data = g_variant_new_int64(intvalue); } else if (pdata->pdo->meta_type == G_VARIANT_TYPE_DOUBLE) { if (!PyFloat_Check(obj)) { PyErr_Format(PyExc_TypeError, "This output was registered " "as 'float', but something else was passed."); - return SRD_ERR_PYTHON; + goto err; } dvalue = PyFloat_AsDouble(obj); if (PyErr_Occurred()) - return SRD_ERR_PYTHON; + goto err; pdata->data = g_variant_new_double(dvalue); } + PyGILState_Release(gstate); + return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR_PYTHON; } static PyObject *Decoder_put(PyObject *self, PyObject *args) @@ -208,11 +239,14 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) uint64_t start_sample, end_sample; int output_id; struct srd_pd_callback *cb; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!(di = srd_inst_find_by_obj(NULL, self))) { /* Shouldn't happen. */ srd_dbg("put(): self instance not found."); - return NULL; + goto err; } if (!PyArg_ParseTuple(args, "KKiO", &start_sample, &end_sample, @@ -222,13 +256,13 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) * Python raise it. This results in a much better trace in * controller.c on the decode() method call. */ - return NULL; + goto err; } if (!(l = g_slist_nth(di->pd_output, output_id))) { srd_err("Protocol decoder %s submitted invalid output ID %d.", di->decoder->name, output_id); - return NULL; + goto err; } pdo = l->data; @@ -250,7 +284,9 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) /* An error was already logged. */ break; } + Py_BEGIN_ALLOW_THREADS cb->cb(pdata, cb->cb_data); + Py_END_ALLOW_THREADS } break; case SRD_OUTPUT_PYTHON: @@ -280,7 +316,9 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) /* An error was already logged. */ break; } + Py_BEGIN_ALLOW_THREADS cb->cb(pdata, cb->cb_data); + Py_END_ALLOW_THREADS } break; case SRD_OUTPUT_META: @@ -290,7 +328,9 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) /* An exception was already set up. */ break; } + Py_BEGIN_ALLOW_THREADS cb->cb(pdata, cb->cb_data); + Py_END_ALLOW_THREADS } break; default: @@ -299,9 +339,16 @@ static PyObject *Decoder_put(PyObject *self, PyObject *args) break; } + PyGILState_Release(gstate); + g_free(pdata); Py_RETURN_NONE; + +err: + PyGILState_Release(gstate); + + return NULL; } static PyObject *Decoder_register(PyObject *self, PyObject *args, @@ -315,6 +362,9 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args, int output_type; char *proto_id, *meta_name, *meta_descr; char *keywords[] = {"output_type", "proto_id", "meta", NULL}; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); meta_type_py = NULL; meta_type_gv = NULL; @@ -322,7 +372,7 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args, if (!(di = srd_inst_find_by_obj(NULL, self))) { PyErr_SetString(PyExc_Exception, "decoder instance not found"); - return NULL; + goto err; } /* Default to instance id, which defaults to class id. */ @@ -331,7 +381,7 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args, &output_type, &proto_id, &meta_type_py, &meta_name, &meta_descr)) { /* Let Python raise this exception. */ - return NULL; + goto err; } /* Check if the meta value's type is supported. */ @@ -342,7 +392,7 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args, meta_type_gv = G_VARIANT_TYPE_DOUBLE; else { PyErr_Format(PyExc_TypeError, "Unsupported type."); - return NULL; + goto err; } } @@ -366,7 +416,14 @@ static PyObject *Decoder_register(PyObject *self, PyObject *args, di->pd_output = g_slist_append(di->pd_output, pdo); py_new_output_id = Py_BuildValue("i", pdo->pdo_id); + PyGILState_Release(gstate); + return py_new_output_id; + +err: + PyGILState_Release(gstate); + + return NULL; } static int get_term_type(const char *v) @@ -405,9 +462,13 @@ static PyObject *get_current_pinvalues(const struct srd_decoder_inst *di) const uint8_t *sample_pos; int byte_offset, bit_offset; PyObject *py_pinvalues; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); if (!di) { srd_err("Invalid decoder instance."); + PyGILState_Release(gstate); return NULL; } @@ -427,6 +488,8 @@ static PyObject *get_current_pinvalues(const struct srd_decoder_inst *di) } } + PyGILState_Release(gstate); + return py_pinvalues; } @@ -448,6 +511,7 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) struct srd_term *term; uint64_t num_samples_to_skip; char *term_str; + PyGILState_STATE gstate; if (!py_dict || !term_list) return SRD_ERR_ARG; @@ -455,6 +519,8 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) /* "Create" an empty GSList of terms. */ *term_list = NULL; + gstate = PyGILState_Ensure(); + /* Iterate over all items in the current dict. */ while (PyDict_Next(py_dict, &pos, &py_key, &py_value)) { /* Check whether the current key is a string or a number. */ @@ -464,7 +530,7 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) /* Get the value string. */ if ((py_pydictitem_as_str(py_dict, py_key, &term_str)) != SRD_OK) { srd_err("Failed to get the value."); - return SRD_ERR; + goto err; } term = g_malloc0(sizeof(struct srd_term)); term->type = get_term_type(term_str); @@ -475,7 +541,7 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) /* TODO: Check if it's "skip". */ if ((py_pydictitem_as_long(py_dict, py_key, &num_samples_to_skip)) != SRD_OK) { srd_err("Failed to get number of samples to skip."); - return SRD_ERR; + goto err; } term = g_malloc0(sizeof(struct srd_term)); term->type = SRD_TERM_SKIP; @@ -483,14 +549,21 @@ static int create_term_list(PyObject *py_dict, GSList **term_list) term->num_samples_already_skipped = 0; } else { srd_err("Term key is neither a string nor a number."); - return SRD_ERR; + goto err; } /* Add the term to the list of terms. */ *term_list = g_slist_append(*term_list, term); } + PyGILState_Release(gstate); + return SRD_OK; + +err: + PyGILState_Release(gstate); + + return SRD_ERR; } /** @@ -510,14 +583,17 @@ static int set_new_condition_list(PyObject *self, PyObject *args) GSList *term_list; PyObject *py_conditionlist, *py_conds, *py_dict; int i, num_conditions, ret; + PyGILState_STATE gstate; if (!self || !args) return SRD_ERR_ARG; + gstate = PyGILState_Ensure(); + /* Get the decoder instance. */ if (!(di = srd_inst_find_by_obj(NULL, self))) { PyErr_SetString(PyExc_Exception, "decoder instance not found"); - return SRD_ERR; + goto err; } /* @@ -526,7 +602,7 @@ static int set_new_condition_list(PyObject *self, PyObject *args) */ if (di->want_wait_terminate) { srd_dbg("%s: %s: Skip (want_term).", di->inst_id, __func__); - return SRD_ERR; + goto err; } /* @@ -539,22 +615,22 @@ static int set_new_condition_list(PyObject *self, PyObject *args) py_conds = Py_None; if (!PyArg_ParseTuple(args, "|O", &py_conds)) { /* Let Python raise this exception. */ - return SRD_ERR; + goto err; } if (py_conds == Py_None) { /* 'py_conds' is None. */ - return 9999; + goto ret_9999; } else if (PyList_Check(py_conds)) { /* 'py_conds' is a list. */ py_conditionlist = py_conds; num_conditions = PyList_Size(py_conditionlist); if (num_conditions == 0) - return 9999; /* The PD invoked self.wait([]). */ + goto ret_9999; /* The PD invoked self.wait([]). */ Py_IncRef(py_conditionlist); } else if (PyDict_Check(py_conds)) { /* 'py_conds' is a dict. */ if (PyDict_Size(py_conds) == 0) - return 9999; /* The PD invoked self.wait({}). */ + goto ret_9999; /* The PD invoked self.wait({}). */ /* Make a list and put the dict in there for convenience. */ py_conditionlist = PyList_New(1); Py_IncRef(py_conds); @@ -562,7 +638,7 @@ static int set_new_condition_list(PyObject *self, PyObject *args) num_conditions = 1; } else { srd_err("Condition list is neither a list nor a dict."); - return SRD_ERR; + goto err; } /* Free the old condition list. */ @@ -590,7 +666,19 @@ static int set_new_condition_list(PyObject *self, PyObject *args) Py_DecRef(py_conditionlist); + PyGILState_Release(gstate); + return ret; + +err: + PyGILState_Release(gstate); + + return SRD_ERR; + +ret_9999: + PyGILState_Release(gstate); + + return 9999; } /** @@ -636,19 +724,23 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) gboolean found_match; struct srd_decoder_inst *di; PyObject *py_pinvalues, *py_matched; + PyGILState_STATE gstate; if (!self || !args) return NULL; + gstate = PyGILState_Ensure(); + if (!(di = srd_inst_find_by_obj(NULL, self))) { PyErr_SetString(PyExc_Exception, "decoder instance not found"); + PyGILState_Release(gstate); Py_RETURN_NONE; } ret = set_new_condition_list(self, args); if (ret < 0) { srd_dbg("%s: %s: Aborting wait().", di->inst_id, __func__); - return NULL; + goto err; } if (ret == 9999) { /* @@ -668,11 +760,14 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) if (ret < 0) { srd_dbg("%s: %s: Cannot setup condition-less wait().", di->inst_id, __func__); - return NULL; + goto err; } } while (1) { + + Py_BEGIN_ALLOW_THREADS + /* Wait for new samples to process, or termination request. */ g_mutex_lock(&di->data_mutex); while (!di->got_new_samples && !di->want_wait_terminate) @@ -688,6 +783,8 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) found_match = FALSE; ret = process_samples_until_condition_match(di, &found_match); + Py_END_ALLOW_THREADS + /* If there's a match, set self.samplenum etc. and return. */ if (found_match) { /* Set self.samplenum to the (absolute) sample number that matched. */ @@ -708,6 +805,8 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) g_mutex_unlock(&di->data_mutex); + PyGILState_Release(gstate); + return py_pinvalues; } @@ -730,13 +829,20 @@ static PyObject *Decoder_wait(PyObject *self, PyObject *args) srd_dbg("%s: %s: Will return from wait().", di->inst_id, __func__); g_mutex_unlock(&di->data_mutex); - return NULL; + goto err; } g_mutex_unlock(&di->data_mutex); } + PyGILState_Release(gstate); + Py_RETURN_NONE; + +err: + PyGILState_Release(gstate); + + return NULL; } /** @@ -754,24 +860,27 @@ static PyObject *Decoder_has_channel(PyObject *self, PyObject *args) int idx, max_idx; struct srd_decoder_inst *di; PyObject *py_channel; + PyGILState_STATE gstate; if (!self || !args) return NULL; + gstate = PyGILState_Ensure(); + if (!(di = srd_inst_find_by_obj(NULL, self))) { PyErr_SetString(PyExc_Exception, "decoder instance not found"); - return NULL; + goto err; } /* Parse the argument of self.has_channel() into 'py_channel'. */ if (!PyArg_ParseTuple(args, "O", &py_channel)) { /* Let Python raise this exception. */ - return NULL; + goto err; } if (!PyLong_Check(py_channel)) { PyErr_SetString(PyExc_Exception, "channel index not a number"); - return NULL; + goto err; } idx = PyLong_AsLong(py_channel); @@ -781,10 +890,17 @@ static PyObject *Decoder_has_channel(PyObject *self, PyObject *args) if (idx < 0 || idx > max_idx) { srd_err("Invalid channel index %d/%d.", idx, max_idx); PyErr_SetString(PyExc_Exception, "invalid channel"); - return NULL; + goto err; } + PyGILState_Release(gstate); + return (di->dec_channelmap[idx] == -1) ? Py_False : Py_True; + +err: + PyGILState_Release(gstate); + + return NULL; } static PyMethodDef Decoder_methods[] = { @@ -815,11 +931,20 @@ SRD_PRIV PyObject *srd_Decoder_type_new(void) { Py_tp_new, (void *)&PyType_GenericNew }, { 0, NULL } }; + PyObject *py_obj; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + spec.name = "sigrokdecode.Decoder"; spec.basicsize = sizeof(srd_Decoder); spec.itemsize = 0; spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; spec.slots = slots; - return PyType_FromSpec(&spec); + py_obj = PyType_FromSpec(&spec); + + PyGILState_Release(gstate); + + return py_obj; } 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