Support adding multiple instances of a decoder
authorKarl Palsson <karlp@etactica.com>
Mon, 11 Apr 2016 15:25:42 +0000 (17:25 +0200)
committerUwe Hermann <uwe@hermann-uwe.de>
Mon, 20 Feb 2017 15:28:27 +0000 (16:28 +0100)
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 <soeren@apelpie.net>
Signed-off-by: Karl Palsson <karlp@etactica.com>
decoder.c
instance.c
libsigrokdecode-internal.h
session.c

index 8ad0c5a132e1bac021184bab8c9ee60e28aa5ff6..f15a7995bdf18d7f9354fb6af6e9d5895a2a1ce3 100644 (file)
--- 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. */
index b56a3e662400938839a89d99d8ce0bd8ebd0dfd1..79b72e18eb630ecb775892275cf554b78710d066 100644 (file)
@@ -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);
 }
 
 /** @} */
index 9db255c51a28c5e1f54fcac7990ad00854038bb6..26093884111b40b70e7d7c23ed685ff149142ad3 100644 (file)
@@ -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))
index e1bb4f9880d36a8f64f8603827a7df8585d088bc..6a7628eb5c43ff351d0c88aac0de86e588d95aff 100644 (file)
--- 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);