diff options
author | Mark Ryan <mark.d.ryan@intel.com> | 2013-05-08 12:16:00 +0200 |
---|---|---|
committer | Mark Ryan <mark.d.ryan@intel.com> | 2013-05-08 12:16:00 +0200 |
commit | 776de4f5fba35f629770fed5aa5e4740336724d4 (patch) | |
tree | be2a4649144da11afd6f460a3eff8e90f18666d5 | |
parent | 25d270897da7fad5ea3c8b18a0aa70c470447d14 (diff) | |
download | dleyna-core-776de4f5fba35f629770fed5aa5e4740336724d4.tar.gz |
This is the second fix for https://github.com/01org/dleyna-renderer/issues/69.
The first fix correctly ensured that all queues were cancelled when shutting down
but unfortunately the queue cancellation code was buggy. It could result in a
hash table entry being removed from a hash table during a call to g_hash_table_for_each.
This meant that if multiple devices were being constructed at once, not all of
the queues responsible for device construction got cancelled. The uncancelled queues
were executing code during shutdown which lead to nasty things happening.
Signed-off-by: Mark Ryan <mark.d.ryan@intel.com>
-rw-r--r-- | libdleyna/core/task-processor.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/libdleyna/core/task-processor.c b/libdleyna/core/task-processor.c index 0a55d1f..efbd9ab 100644 --- a/libdleyna/core/task-processor.c +++ b/libdleyna/core/task-processor.c @@ -180,9 +180,11 @@ static void prv_task_cancel_and_free_cb(gpointer data, gpointer user_data) task_queue->task_delete_cb(data, task_queue->user_data); } -static void prv_cancel(const dleyna_task_queue_key_t *queue_id, - dleyna_task_queue_t *task_queue) +static gboolean prv_cancel_only(const dleyna_task_queue_key_t *queue_id, + dleyna_task_queue_t *task_queue) { + gboolean remove_queue = FALSE; + if (task_queue->cancelled) goto out; @@ -197,32 +199,50 @@ static void prv_cancel(const dleyna_task_queue_key_t *queue_id, task_queue->idle_id = 0; } - if (task_queue->current_task) { + if (task_queue->current_task) task_queue->task_cancel_cb(task_queue->current_task, task_queue->user_data); - } else if (task_queue->flags & DLEYNA_TASK_QUEUE_FLAG_AUTO_REMOVE) { + else + remove_queue = task_queue->flags & + DLEYNA_TASK_QUEUE_FLAG_AUTO_REMOVE; + +out: + + return remove_queue; +} + + +static void prv_cancel(const dleyna_task_queue_key_t *queue_id, + dleyna_task_queue_t *task_queue) +{ + if (prv_cancel_only(queue_id, task_queue)) { DLEYNA_LOG_DEBUG("Removing queue <%s,%s>", queue_id->source, queue_id->sink); g_hash_table_remove(queue_id->processor->task_queues, queue_id); } - -out: - return; } -static void prv_cancel_cb(gpointer key, gpointer value, gpointer user_data) +static gboolean prv_cancel_cb(gpointer key, gpointer value, gpointer user_data) { dleyna_task_queue_key_t *queue_id = key; dleyna_task_queue_t *task_queue = value; + gboolean retval = prv_cancel_only(queue_id, task_queue); + +#if DLEYNA_LOG_LEVEL & DLEYNA_LOG_LEVEL_DEBUG + if (retval) + DLEYNA_LOG_DEBUG("Removing queue <%s,%s>", queue_id->source, + queue_id->sink); +#endif - prv_cancel(queue_id, task_queue); + return retval; } static void prv_cancel_all_queues(dleyna_task_processor_t *processor) { DLEYNA_LOG_DEBUG("Enter"); - g_hash_table_foreach(processor->task_queues, prv_cancel_cb, NULL); + g_hash_table_foreach_remove(processor->task_queues, prv_cancel_cb, + NULL); DLEYNA_LOG_DEBUG("Exit"); } |