diff options
author | Gerhard Sittig <gerhard.sittig@gmx.net> | 2021-12-26 07:42:27 +0100 |
---|---|---|
committer | Gerhard Sittig <gerhard.sittig@gmx.net> | 2021-12-26 13:45:09 +0100 |
commit | 819e508972da02a0dcff7f81178f0283546a9afd (patch) | |
tree | 5a48cb02cf7b712e2d152e547b7fab6ab969c8dd /instance.c | |
parent | 487890c822762d9886dfd022ed599c9909ceaab9 (diff) | |
download | libsigrokdecode-819e508972da02a0dcff7f81178f0283546a9afd.tar.gz libsigrokdecode-819e508972da02a0dcff7f81178f0283546a9afd.zip |
session: introduce the public "send EOF" API routine
Introduce the public srd_session_send_eof() routine which is backed by
the internal srd_inst_send_eof() helper. Applications can tell decoders
when the input stream of sample data is exhausted, so that decoders can
optionally "flush" their previously accumulated information when
desired. Previous implementations just kept decoders in blocking .wait()
calls and somehow terminated them at arbitrary times afterwards.
When EOF is sent to the decoder session, then calls to the .wait()
method which typically are done from .decode() or its descendents will
end with an EOFError Python exception. Termination of .decode() with the
EOFError exception is non-fatal for backwards compatibility and to keep
the convenience for current decoder implementations. Decoders can either
catch the exception, or use context managers, or do nothing.
This API extension is motivated by research for bug #1581 and provides
the infrastructure to address bug #292. Decoders need to remain careful,
and should not claim that protocol activities would have completed when
their end condition was not even seen in the capture. Marking incomplete
activities with warnings is the most appropriate reaction.
Diffstat (limited to 'instance.c')
-rw-r--r-- | instance.c | 71 |
1 files changed, 71 insertions, 0 deletions
@@ -426,6 +426,7 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, di->got_new_samples = FALSE; di->handled_all_samples = FALSE; di->want_wait_terminate = FALSE; + di->communicate_eof = FALSE; di->decoder_state = SRD_OK; /* @@ -500,6 +501,7 @@ static void srd_inst_reset_state(struct srd_decoder_inst *di) di->got_new_samples = FALSE; di->handled_all_samples = FALSE; di->want_wait_terminate = FALSE; + di->communicate_eof = FALSE; di->decoder_state = SRD_OK; /* Conditions and mutex got reset after joining the thread. */ } @@ -1058,6 +1060,17 @@ static gpointer di_thread(gpointer data) py_res = PyObject_CallMethod(di->py_inst, "decode", NULL); srd_dbg("%s: decode() terminated.", di->inst_id); + /* + * Termination with an EOFError exception is accepted to simplify + * the implementation of decoders and for backwards compatibility. + */ + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_EOFError)) { + srd_dbg("%s: ignoring EOFError during decode() execution.", + di->inst_id); + PyErr_Clear(); + if (!py_res) + py_res = Py_None; + } if (!py_res) di->decoder_state = SRD_ERR; @@ -1282,6 +1295,64 @@ SRD_PRIV int srd_inst_flush(struct srd_decoder_inst *di) } /** + * Communicate the end of the stream of sample data to a decoder instance. + * + * @param[in] 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_send_eof(struct srd_decoder_inst *di) +{ + GSList *l; + int ret; + + if (!di) + return SRD_ERR_ARG; + + /* + * Send EOF to the caller specified decoder instance. Only + * communicate EOF to currently executing decoders. Never + * started or previously finished is perfectly acceptable. + */ + srd_dbg("End of sample data: instance %s.", di->inst_id); + if (!di->thread_handle) { + srd_dbg("No worker thread, nothing to do."); + return SRD_OK; + } + + /* Signal the thread about the EOF condition. */ + g_mutex_lock(&di->data_mutex); + di->inbuf = NULL; + di->inbuflen = 0; + di->got_new_samples = TRUE; + di->handled_all_samples = FALSE; + di->want_wait_terminate = TRUE; + di->communicate_eof = TRUE; + g_cond_signal(&di->got_new_samples_cond); + g_mutex_unlock(&di->data_mutex); + + /* Only return from here when the condition was handled. */ + g_mutex_lock(&di->data_mutex); + while (!di->handled_all_samples && !di->want_wait_terminate) + g_cond_wait(&di->handled_all_samples_cond, &di->data_mutex); + g_mutex_unlock(&di->data_mutex); + + /* Flush the decoder instance which handled EOF. */ + srd_inst_flush(di); + + /* Pass EOF to all stacked decoders. */ + for (l = di->next_di; l; l = l->next) { + ret = srd_inst_send_eof(l->data); + if (ret != SRD_OK) + return ret; + } + + return SRD_OK; +} + +/** * Terminate current decoder work, prepare for re-use on new input data. * * Terminates all decoder operations in the specified decoder instance |