From 63cd93107850807403dbc80e32f542eeecb08341 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Mon, 24 Dec 2018 17:34:20 +0800 Subject: [PATCH 1/2] scheduler: add pending_cnt for task to make pending scheduling possible When one instance of a task is queued(queued, pending, running, or preempted), it is possible that another instance of this same task scheduling reqire will come before the previous one is completed. In today's design, this second instance may be dropped(e.g. for pipeline_copy() task) and unexpected error will happen. Here, we add a pending_cnt for the task, accumulate it when needed, and schedule it when the previous one is finished. Signed-off-by: Keyon Jie --- src/arch/xtensa/include/arch/task.h | 2 +- src/include/sof/schedule.h | 4 ++++ src/lib/schedule.c | 34 +++++++++++++++++++---------- 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/arch/xtensa/include/arch/task.h b/src/arch/xtensa/include/arch/task.h index de8ded4f91fb..f25dd2d6317f 100644 --- a/src/arch/xtensa/include/arch/task.h +++ b/src/arch/xtensa/include/arch/task.h @@ -160,7 +160,7 @@ static void _irq_task(void *arg) task = container_of(clist, struct task, irq_list); list_item_del(clist); - if (task->func && task->state == TASK_STATE_PENDING) { + if (task->func) { schedule_task_running(task); run_task = 1; } else { diff --git a/src/include/sof/schedule.h b/src/include/sof/schedule.h index a5609ab1bb55..b6b619ebfbe1 100644 --- a/src/include/sof/schedule.h +++ b/src/include/sof/schedule.h @@ -91,6 +91,8 @@ struct task { /* runtime duration in scheduling clock base */ uint64_t max_rtime; /* max time taken to run */ completion_t complete; + + uint32_t pending_cnt; }; struct schedule_data **arch_schedule_get(void); @@ -111,6 +113,7 @@ static inline void schedule_task_init(struct task *task, void (*func)(void *), void *data) { task->core = 0; + task->pending_cnt = 0; task->state = TASK_STATE_INIT; task->func = func; task->data = data; @@ -119,6 +122,7 @@ static inline void schedule_task_init(struct task *task, void (*func)(void *), static inline void schedule_task_free(struct task *task) { task->state = TASK_STATE_FREE; + task->pending_cnt = 0; task->func = NULL; task->data = NULL; } diff --git a/src/lib/schedule.c b/src/lib/schedule.c index 616c6dd4d43a..faff023db4fd 100644 --- a/src/lib/schedule.c +++ b/src/lib/schedule.c @@ -263,17 +263,17 @@ static int _schedule_task(struct task *task, uint64_t start, uint64_t deadline) spin_lock_irq(&sch->lock, flags); - /* is task already pending ? - not enough MIPS to complete ? */ - if (task->state == TASK_STATE_PENDING) { - trace_schedule("_schedule_task(), task already pending"); - spin_unlock_irq(&sch->lock, flags); - return 0; - } - - /* is task already queued ? - not enough MIPS to complete ? */ - if (task->state == TASK_STATE_QUEUED) { - trace_schedule("_schedule_task(), task already queued"); - spin_unlock_irq(&sch->lock, flags); + /* + * increase pending_cnt, will schedule it after this + * pending one is finished. + */ + if (task->state == TASK_STATE_PENDING || + task->state == TASK_STATE_QUEUED || + task->state == TASK_STATE_RUNNING || + task->state == TASK_STATE_PREEMPTED) { + trace_schedule("task 0x%xalready WIP, schedule it later...", + (uint32_t)(uint32_t *)task); + task->pending_cnt++; return 0; } @@ -292,6 +292,9 @@ static int _schedule_task(struct task *task, uint64_t start, uint64_t deadline) /* calculate deadline - TODO: include MIPS */ task->deadline = task->start + ticks_per_ms * deadline / 1000; + if (task->pending_cnt) + task->pending_cnt--; + /* add task to list */ list_item_append(&task->list, &sch->list); task->state = TASK_STATE_QUEUED; @@ -337,6 +340,8 @@ void schedule_task(struct task *task, uint64_t start, uint64_t deadline) void schedule_task_complete(struct task *task) { struct schedule_data *sch = *arch_schedule_get(); + uint64_t ticks_per_ms; + uint64_t deadline; uint32_t flags; tracev_schedule("schedule_task_complete()"); @@ -367,6 +372,13 @@ void schedule_task_complete(struct task *task) /* tell any waiter that task has completed */ wait_completed(&task->complete); + + /* schedule the same pending task */ + if (task->pending_cnt) { + ticks_per_ms = clock_ms_to_ticks(sch->clock, 1); + deadline = (task->deadline - task->start) * 1000 / ticks_per_ms; + schedule_task(task, 0, deadline); + } } /* Update task state to running */ From b711faba5b773ddacee41a20a8d1e73609e88e57 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Sat, 29 Dec 2018 13:05:52 +0800 Subject: [PATCH 2/2] pipeline: switch schedule_task_idle to schedule_task Signed-off-by: Keyon Jie --- src/audio/pipeline.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/audio/pipeline.c b/src/audio/pipeline.c index 12722031b76e..8d2ae47830d2 100644 --- a/src/audio/pipeline.c +++ b/src/audio/pipeline.c @@ -1271,7 +1271,8 @@ void pipeline_schedule_copy(struct pipeline *p, uint64_t start) * buffers prior to trigger start. */ void pipeline_schedule_copy_idle(struct pipeline *p) { - schedule_task_idle(&p->pipe_task, p->ipc_pipe.deadline); +// schedule_task_idle(&p->pipe_task, p->ipc_pipe.deadline); + schedule_task(&p->pipe_task, 0, p->ipc_pipe.deadline); } void pipeline_schedule_cancel(struct pipeline *p)