From 776de4f5fba35f629770fed5aa5e4740336724d4 Mon Sep 17 00:00:00 2001 From: Mark Ryan Date: Wed, 8 May 2013 12:16:00 +0200 Subject: 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 --- libdleyna/core/task-processor.c | 40 ++++++++++++++++++++++++++++++---------- 1 file 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"); } -- cgit v1.2.1