From ee7976bf8216cb05335c5fe173dc03525f23ebd1 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 6 Nov 2023 16:49:45 +0100 Subject: [PATCH] schedule: cancel a task before freeing it When a chain DMA stream is the only one running, stopping it currently takes 100ms. The reason is that the chain DMA driver is trying to stop the task directly from the IPC context instead of letting the task exit on its next scheduling event. The IPC thread is indeed trying to wait on a semaphore for the task to exit, but that doesn't work either, because zephyr_domain_unregister() terminates the thread before it signals the semaphore. To fix this we swap the order and signal the semaphore before terminating the thread. Link: https://github.com/thesofproject/sof/issues/8445 Signed-off-by: Guennadi Liakhovetski --- src/schedule/zephyr_ll.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 06608d188873..a91a6c24f5e4 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -57,6 +57,8 @@ static void zephyr_ll_assert_core(const struct zephyr_ll *sch) static void zephyr_ll_task_done(struct zephyr_ll *sch, struct task *task) { + struct zephyr_ll_pdata *pdata = task->priv_data; + list_item_del(&task->list); if (!sch->n_tasks) { @@ -66,6 +68,13 @@ static void zephyr_ll_task_done(struct zephyr_ll *sch, task->state = SOF_TASK_STATE_FREE; + if (pdata->freeing) + /* + * zephyr_ll_task_free() is trying to free this task. Complete + * it and signal the semaphore to let the function proceed + */ + k_sem_give(&pdata->sem); + tr_info(&ll_tr, "task complete %p %pU", task, task->uid); tr_info(&ll_tr, "num_tasks %d total_num_tasks %ld", sch->n_tasks, atomic_read(&sch->ll_domain->total_num_tasks)); @@ -212,15 +221,7 @@ static void zephyr_ll_run(void *data) zephyr_ll_lock(sch, &flags); - if (pdata->freeing) { - /* - * zephyr_ll_task_free() is trying to free this task. - * complete it and signal the semaphore to let the - * function proceed - */ - zephyr_ll_task_done(sch, task); - k_sem_give(&pdata->sem); - } else if (state == SOF_TASK_STATE_COMPLETED) { + if (pdata->freeing || state == SOF_TASK_STATE_COMPLETED) { zephyr_ll_task_done(sch, task); } else { /*