summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Ryan <mark.d.ryan@intel.com>2013-05-08 12:16:00 +0200
committerMark Ryan <mark.d.ryan@intel.com>2013-05-08 12:16:00 +0200
commit776de4f5fba35f629770fed5aa5e4740336724d4 (patch)
treebe2a4649144da11afd6f460a3eff8e90f18666d5
parent25d270897da7fad5ea3c8b18a0aa70c470447d14 (diff)
downloaddleyna-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.c40
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");
}