static void srd_inst_join_decode_thread(struct srd_decoder_inst *di);
static void srd_inst_reset_state(struct srd_decoder_inst *di);
+SRD_PRIV void oldpins_array_seed(struct srd_decoder_inst *di);
SRD_PRIV void oldpins_array_free(struct srd_decoder_inst *di);
/** @endcond */
return ret;
}
-/* Helper GComparefunc for g_slist_find_custom() in srd_inst_channel_set_all() */
+/* Helper GComparefunc for g_slist_find_custom() in srd_inst_channel_set_all(). */
static gint compare_channel_id(const struct srd_channel *pdch,
const char *channel_id)
{
return SRD_ERR_ARG;
}
- new_channelmap = g_malloc(sizeof(int) * di->dec_num_channels);
+ new_channelmap = g_malloc0(sizeof(int) * di->dec_num_channels);
/*
* For now, map all indexes to channel -1 (can be overridden later).
srd_dbg("Final channel map:");
num_required_channels = g_slist_length(di->decoder->channels);
for (i = 0; i < di->dec_num_channels; i++) {
- GSList *l = g_slist_nth(di->decoder->channels, i);
- if (!l)
- l = g_slist_nth(di->decoder->opt_channels,
+ GSList *ll = g_slist_nth(di->decoder->channels, i);
+ if (!ll)
+ ll = g_slist_nth(di->decoder->opt_channels,
i - num_required_channels);
- pdch = l->data;
+ pdch = ll->data;
srd_dbg(" - PD ch idx %d (%s) = input data ch idx %d (%s)", i,
pdch->id, new_channelmap[i],
(i < num_required_channels) ? "required" : "optional");
pdch = g_slist_nth(di->decoder->channels, i)->data;
srd_err("Required channel '%s' (index %d) was not specified.",
pdch->id, i);
+ g_free(new_channelmap);
return SRD_ERR;
}
* Create a new protocol decoder instance.
*
* @param sess The session holding the protocol decoder instance.
+ * Must not be NULL.
* @param decoder_id Decoder 'id' field.
* @param options GHashtable of options which override the defaults set in
* the decoder class. May be NULL.
i = 1;
srd_dbg("Creating new %s instance.", decoder_id);
- if (session_is_valid(sess) != SRD_OK) {
- srd_err("Invalid session.");
+ if (!sess)
return NULL;
- }
if (!(dec = srd_decoder_get_by_id(decoder_id))) {
srd_err("Protocol decoder %s not found.", decoder_id);
}
/* Default to the initial pins being the same as in sample 0. */
- di->old_pins_array = g_array_sized_new(FALSE, TRUE, sizeof(uint8_t),
- di->dec_num_channels);
- g_array_set_size(di->old_pins_array, di->dec_num_channels);
- memset(di->old_pins_array->data, SRD_INITIAL_PIN_SAME_AS_SAMPLE0,
- di->dec_num_channels);
+ oldpins_array_seed(di);
gstate = PyGILState_Ensure();
srd_dbg("%s: Resetting decoder state.", di->inst_id);
- /*
- * Reset internal state of the decoder.
- */
+ /* Reset internal state of the decoder. */
condition_list_free(di);
match_array_free(di);
di->abs_start_samplenum = 0;
* Stack a decoder instance on top of another.
*
* @param sess The session holding the protocol decoder instances.
+ * Must not be NULL.
* @param di_bottom The instance on top of which di_top will be stacked.
* @param di_top The instance to go on top.
*
struct srd_decoder_inst *di_bottom,
struct srd_decoder_inst *di_top)
{
- if (session_is_valid(sess) != SRD_OK) {
- srd_err("Invalid session.");
+ if (!sess)
return SRD_ERR_ARG;
- }
if (!di_bottom || !di_top) {
srd_err("Invalid from/to instance pair.");
* given session.
*
* @param sess The session holding the protocol decoder instance.
+ * Must not be NULL.
* @param inst_id The instance ID to be found.
*
* @return Pointer to struct srd_decoder_inst, or NULL if not found.
GSList *l;
struct srd_decoder_inst *tmp, *di;
- if (session_is_valid(sess) != SRD_OK) {
- srd_err("Invalid session.");
+ if (!sess)
return NULL;
- }
di = NULL;
for (l = sess->di_list; l; l = l->next) {
const GSList *l;
struct srd_decoder_inst *tmp, *di;
- if (session_is_valid(sess) != SRD_OK) {
- srd_err("Invalid session.");
+ if (!sess)
return NULL;
- }
di = NULL;
for (l = stack ? stack : sess->di_list; di == NULL && l != NULL; l = l->next) {
}
s = g_string_sized_new(100);
+ oldpins_array_seed(di);
for (i = 0; i < di->dec_num_channels; i++) {
di->old_pins_array->data[i] = initial_pins->data[i];
g_string_append_printf(s, "%d, ", di->old_pins_array->data[i]);
return SRD_OK;
}
+/** @private */
+SRD_PRIV void oldpins_array_seed(struct srd_decoder_inst *di)
+{
+ size_t count;
+ GArray *arr;
+
+ if (!di)
+ return;
+ if (di->old_pins_array)
+ return;
+
+ srd_dbg("%s: Seeding old pins, %s().", di->inst_id, __func__);
+ count = di->dec_num_channels;
+ arr = g_array_sized_new(FALSE, TRUE, sizeof(uint8_t), count);
+ g_array_set_size(arr, count);
+ memset(arr->data, SRD_INITIAL_PIN_SAME_AS_SAMPLE0, count);
+ di->old_pins_array = arr;
+}
+
/** @private */
SRD_PRIV void oldpins_array_free(struct srd_decoder_inst *di)
{
if (!di || !di->dec_channelmap || !sample_pos)
return;
+ oldpins_array_seed(di);
for (i = 0; i < di->dec_num_channels; i++) {
byte_offset = di->dec_channelmap[i] / 8;
bit_offset = di->dec_channelmap[i] % 8;
sample_pos = di->inbuf + ((di->abs_cur_samplenum - di->abs_start_samplenum) * di->data_unitsize);
+ oldpins_array_seed(di);
for (i = 0; i < di->dec_num_channels; i++) {
if (di->old_pins_array->data[i] != SRD_INITIAL_PIN_SAME_AS_SAMPLE0)
continue;
di->inbuflen = inbuflen;
di->got_new_samples = TRUE;
di->handled_all_samples = FALSE;
- di->want_wait_terminate = FALSE;
/* Signal the thread that we have new data. */
g_cond_signal(&di->got_new_samples_cond);
g_cond_wait(&di->handled_all_samples_cond, &di->data_mutex);
g_mutex_unlock(&di->data_mutex);
+ if (di->want_wait_terminate)
+ return SRD_ERR_TERM_REQ;
+
+ 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;
}
struct srd_pd_output *pdo;
PyGILState_STATE gstate;
- srd_dbg("Freeing instance %s", di->inst_id);
+ srd_dbg("Freeing instance %s.", di->inst_id);
srd_inst_join_decode_thread(di);
/** @private */
SRD_PRIV void srd_inst_free_all(struct srd_session *sess)
{
- if (session_is_valid(sess) != SRD_OK) {
- srd_err("Invalid session.");
+ if (!sess)
return;
- }
g_slist_free_full(sess->di_list, (GDestroyNotify)srd_inst_free);
}