From: Gerhard Sittig Date: Sun, 17 Dec 2017 17:55:46 +0000 (+0100) Subject: session: add "terminate and reset" support for protocol stacks X-Git-Url: https://sigrok.org/gitweb/?p=libsigrokdecode.git;a=commitdiff_plain;h=9553e9622bb26dfbe6296ef6f330b1cf0f5b40e6;hp=7d82e3c1ec96ac8a9ef358de1e9c87715dcb8f43 session: add "terminate and reset" support for protocol stacks Implement routines which terminate currently pending decoder operations and reset internal state (on the C and Python sides) for instances as well as sessions. This allows to re-use previously created stacks for new input data. --- diff --git a/instance.c b/instance.c index 5281510..6fbdc01 100644 --- a/instance.c +++ b/instance.c @@ -1270,6 +1270,70 @@ SRD_PRIV int srd_inst_decode(struct srd_decoder_inst *di, return SRD_OK; } +/** + * Terminate current decoder work, prepare for re-use on new input data. + * + * Terminates all decoder operations in the specified decoder instance + * and the instances stacked on top of it. Resets internal state such + * that the previously constructed stack can process new input data that + * is not related to previously processed input data. This avoids the + * expensive and complex re-construction of decoder stacks. + * + * Callers are expected to follow up with start, metadata, and decode + * calls like they would for newly constructed decoder stacks. + * + * @param di The decoder instance to call. Must not be NULL. + * @return SRD_OK upon success, a (negative) error code otherwise. + * @private + */ +SRD_PRIV int srd_inst_terminate_reset(struct srd_decoder_inst *di) +{ + PyGILState_STATE gstate; + PyObject *py_ret; + GSList *l; + int ret; + + if (!di) + return SRD_ERR_ARG; + + /* + * Request termination and wait for previously initiated + * background operation to finish. Reset internal state, but + * do not start releasing resources yet. This shall result in + * decoders' state just like after creation. This block handles + * the C language library side. + */ + srd_dbg("Terminating instance %s", di->inst_id); + srd_inst_join_decode_thread(di); + srd_inst_reset_state(di); + + /* + * Have the Python side's .reset() method executed (if the PD + * implements it). It's assumed that .reset() assigns variables + * very much like __init__() used to do in the past. Thus memory + * that was allocated in previous calls gets released by Python + * as it's not referenced any longer. + */ + gstate = PyGILState_Ensure(); + if (PyObject_HasAttrString(di->py_inst, "reset")) { + srd_dbg("Calling .reset() of instance %s", di->inst_id); + py_ret = PyObject_CallMethod(di->py_inst, "reset", NULL); + Py_XDECREF(py_ret); + } + PyGILState_Release(gstate); + + /* + * Pass the "restart" request to all stacked decoders. + */ + for (l = di->next_di; l; l = l->next) { + ret = srd_inst_terminate_reset(l->data); + if (ret != SRD_OK) + return ret; + } + + return SRD_OK; +} + /** @private */ SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di) { diff --git a/libsigrokdecode-internal.h b/libsigrokdecode-internal.h index eb79287..6fb590c 100644 --- a/libsigrokdecode-internal.h +++ b/libsigrokdecode-internal.h @@ -84,6 +84,7 @@ SRD_PRIV int srd_inst_decode(struct srd_decoder_inst *di, uint64_t abs_start_samplenum, uint64_t abs_end_samplenum, const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize); SRD_PRIV int process_samples_until_condition_match(struct srd_decoder_inst *di, gboolean *found_match); +SRD_PRIV int srd_inst_terminate_reset(struct srd_decoder_inst *di); SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di); SRD_PRIV void srd_inst_free_all(struct srd_session *sess); diff --git a/libsigrokdecode.h b/libsigrokdecode.h index 982ae19..ee610c9 100644 --- a/libsigrokdecode.h +++ b/libsigrokdecode.h @@ -330,6 +330,7 @@ SRD_API int srd_session_metadata_set(struct srd_session *sess, int key, SRD_API int srd_session_send(struct srd_session *sess, uint64_t abs_start_samplenum, uint64_t abs_end_samplenum, const uint8_t *inbuf, uint64_t inbuflen, uint64_t unitsize); +SRD_API int srd_session_terminate_reset(struct srd_session *sess); SRD_API int srd_session_destroy(struct srd_session *sess); SRD_API int srd_pd_output_callback_add(struct srd_session *sess, int output_type, srd_pd_output_callback cb, void *cb_data); diff --git a/session.c b/session.c index 0c1ef82..4d794df 100644 --- a/session.c +++ b/session.c @@ -297,6 +297,45 @@ SRD_API int srd_session_send(struct srd_session *sess, return SRD_OK; } +/** + * Terminate currently executing decoders in a session, reset internal state. + * + * All decoder instances have their .wait() method terminated, which + * shall terminate .decode() as well. Afterwards the decoders' optional + * .reset() method gets executed. + * + * This routine allows callers to abort pending expensive operations, + * when they are no longer interested in the decoders' results. Note + * that the decoder state is lost and aborted work cannot resume. + * + * This routine also allows callers to re-use previously created decoder + * stacks to process new input data which is not related to previously + * processed input data. This avoids the necessity to re-construct the + * decoder stack. + * + * @param sess The session in which to terminate decoders. + * @return SRD_OK upon success, a (negative) error code otherwise. + * + * @since 0.6.0 + */ +SRD_API int srd_session_terminate_reset(struct srd_session *sess) +{ + GSList *d; + int ret; + + if (session_is_valid(sess) != SRD_OK) { + srd_err("Invalid session."); + return SRD_ERR_ARG; + } + + for (d = sess->di_list; d; d = d->next) { + ret = srd_inst_terminate_reset(d->data); + if (ret != SRD_OK) + return ret; + } + return SRD_OK; +} + /** * Destroy a decoding session. *