From: Karl Palsson Date: Mon, 11 Apr 2016 15:25:42 +0000 (+0200) Subject: Support adding multiple instances of a decoder X-Git-Tag: libsigrokdecode-0.5.0~83 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=3262ef0203e23399f3cab796391da06969c8306b;p=libsigrokdecode.git Support adding multiple instances of a decoder srd_inst_new() used the decoder ID as the instance ID, preventing the use of multiple instances of the same decoder in the same session. Simply append a numerical suffix to later instances to allow more. Required changes to cleanup to reliably free all memory. Valgrind checked. This fixes parts of bug #868. Based on original work by: Soeren Apel Signed-off-by: Karl Palsson --- diff --git a/decoder.c b/decoder.c index 8ad0c5a..f15a799 100644 --- a/decoder.c +++ b/decoder.c @@ -849,7 +849,7 @@ SRD_API int srd_decoder_unload(struct srd_decoder *dec) */ for (l = sessions; l; l = l->next) { sess = l->data; - srd_inst_free_all(sess, NULL); + srd_inst_free_all(sess); } /* Remove the PD from the list of loaded decoders. */ diff --git a/instance.c b/instance.c index b56a3e6..79b72e1 100644 --- a/instance.c +++ b/instance.c @@ -297,6 +297,7 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, struct srd_decoder_inst *di; char *inst_id; + i = 1; srd_dbg("Creating new %s instance.", decoder_id); if (session_is_valid(sess) != SRD_OK) { @@ -313,12 +314,22 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, di->decoder = dec; di->sess = sess; + if (options) { inst_id = g_hash_table_lookup(options, "id"); - di->inst_id = g_strdup(inst_id ? inst_id : decoder_id); + if (inst_id) + di->inst_id = g_strdup(inst_id); g_hash_table_remove(options, "id"); - } else - di->inst_id = g_strdup(decoder_id); + } + + /* Create a unique instance ID (as none was provided). */ + if (!di->inst_id) { + di->inst_id = g_strdup_printf("%s-%d", decoder_id, i++); + while (srd_inst_find_by_id(sess, di->inst_id)) { + g_free(di->inst_id); + di->inst_id = g_strdup_printf("%s-%d", decoder_id, i++); + } + } /* * Prepare a default channel map, where samples come in the @@ -368,6 +379,7 @@ SRD_API struct srd_decoder_inst *srd_inst_new(struct srd_session *sess, /* Instance takes input from a frontend by default. */ sess->di_list = g_slist_append(sess->di_list, di); + srd_dbg("Created new %s instance with ID %s.", decoder_id, di->inst_id); return di; } @@ -1018,27 +1030,14 @@ SRD_PRIV void srd_inst_free(struct srd_decoder_inst *di) } /** @private */ -SRD_PRIV void srd_inst_free_all(struct srd_session *sess, GSList *stack) +SRD_PRIV void srd_inst_free_all(struct srd_session *sess) { - GSList *l; - struct srd_decoder_inst *di; - if (session_is_valid(sess) != SRD_OK) { srd_err("Invalid session."); return; } - di = NULL; - for (l = stack ? stack : sess->di_list; di == NULL && l != NULL; l = l->next) { - di = l->data; - if (di->next_di) - srd_inst_free_all(sess, di->next_di); - srd_inst_free(di); - } - if (!stack) { - g_slist_free(sess->di_list); - sess->di_list = NULL; - } + g_slist_free_full(sess->di_list, (GDestroyNotify)srd_inst_free); } /** @} */ diff --git a/libsigrokdecode-internal.h b/libsigrokdecode-internal.h index 9db255c..2609388 100644 --- a/libsigrokdecode-internal.h +++ b/libsigrokdecode-internal.h @@ -85,7 +85,7 @@ SRD_PRIV int srd_inst_decode(struct srd_decoder_inst *di, 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 void srd_inst_free(struct srd_decoder_inst *di); -SRD_PRIV void srd_inst_free_all(struct srd_session *sess, GSList *stack); +SRD_PRIV void srd_inst_free_all(struct srd_session *sess); /* log.c */ #if defined(G_OS_WIN32) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)) diff --git a/session.c b/session.c index e1bb4f9..6a7628e 100644 --- a/session.c +++ b/session.c @@ -278,7 +278,7 @@ SRD_API int srd_session_destroy(struct srd_session *sess) session_id = sess->session_id; if (sess->di_list) - srd_inst_free_all(sess, NULL); + srd_inst_free_all(sess); if (sess->callbacks) g_slist_free_full(sess->callbacks, g_free); sessions = g_slist_remove(sessions, sess);