mirror of https://github.com/thesofproject/sof.git
pipe: fix a infinite loop issue in schedule module
There are two paths to delete a task in shedule list. A task would be deleted when task is completed or cancelled. So it maybe deleted twice. there is a circle in the schedule list after a sequence of append-delete operations. This makes a infinite loop in schedule function Now all of list items are deleted in one place and cancelled when task are complete Signed-off-by: Pan Xiuli <xiuli.pan@linux.intel.com> Signed-off-by: Rander Wang <rander.wang@linux.intel.com> Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
This commit is contained in:
parent
7be08fdbeb
commit
d527b50816
|
@ -1275,7 +1275,12 @@ void pipeline_schedule_copy_idle(struct pipeline *p)
|
|||
|
||||
void pipeline_schedule_cancel(struct pipeline *p)
|
||||
{
|
||||
schedule_task_complete(&p->pipe_task);
|
||||
int err;
|
||||
|
||||
/* cancel and wait for pipeline to complete */
|
||||
err = schedule_task_cancel(&p->pipe_task);
|
||||
if (err < 0)
|
||||
trace_pipe_error("pC0");
|
||||
}
|
||||
|
||||
static void pipeline_task(void *arg)
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <sof/lock.h>
|
||||
#include <sof/list.h>
|
||||
#include <sof/work.h>
|
||||
#include <sof/wait.h>
|
||||
|
||||
struct schedule_data;
|
||||
struct sof;
|
||||
|
@ -56,6 +57,8 @@ struct sof;
|
|||
#define TASK_PRI_MED 0
|
||||
#define TASK_PRI_HIGH -20
|
||||
|
||||
/* maximun task time slice in microseconds */
|
||||
#define SCHEDULE_TASK_MAX_TIME_SLICE 5000
|
||||
|
||||
/* task descriptor */
|
||||
struct task {
|
||||
|
@ -73,6 +76,7 @@ struct task {
|
|||
|
||||
/* runtime duration in scheduling clock base */
|
||||
uint64_t max_rtime; /* max time taken to run */
|
||||
completion_t complete;
|
||||
};
|
||||
|
||||
struct schedule_data **arch_schedule_get(void);
|
||||
|
@ -83,6 +87,8 @@ void schedule_task(struct task *task, uint64_t start, uint64_t deadline);
|
|||
|
||||
void schedule_task_idle(struct task *task, uint64_t deadline);
|
||||
|
||||
int schedule_task_cancel(struct task *task);
|
||||
|
||||
void schedule_task_complete(struct task *task);
|
||||
|
||||
static inline void schedule_task_init(struct task *task, void (*func)(void *),
|
||||
|
|
|
@ -170,9 +170,11 @@ static uint64_t sch_work(void *data, uint64_t delay)
|
|||
*/
|
||||
static struct task *schedule_edf(void)
|
||||
{
|
||||
struct schedule_data *sch = *arch_schedule_get();
|
||||
struct task *task;
|
||||
struct task *future_task = NULL;
|
||||
uint64_t current;
|
||||
uint32_t flags;
|
||||
|
||||
tracev_pipe("edf");
|
||||
|
||||
|
@ -195,7 +197,15 @@ static struct task *schedule_edf(void)
|
|||
} else {
|
||||
/* yes, run current task */
|
||||
task->start = current;
|
||||
|
||||
/* init task for running */
|
||||
wait_init(&task->complete);
|
||||
spin_lock_irq(&sch->lock, flags);
|
||||
task->state = TASK_STATE_RUNNING;
|
||||
list_item_del(&task->list);
|
||||
spin_unlock_irq(&sch->lock, flags);
|
||||
|
||||
/* now run task at correct run level */
|
||||
run_task(task);
|
||||
}
|
||||
|
||||
|
@ -203,9 +213,8 @@ static struct task *schedule_edf(void)
|
|||
return future_task;
|
||||
}
|
||||
|
||||
#if 0 /* FIXME: is this needed ? */
|
||||
/* delete task from scheduler */
|
||||
static int schedule_task_del(struct task *task)
|
||||
/* cancel and delete task from scheduler - won't stop it if already running */
|
||||
int schedule_task_cancel(struct task *task)
|
||||
{
|
||||
struct schedule_data *sch = *arch_schedule_get();
|
||||
uint32_t flags;
|
||||
|
@ -213,24 +222,21 @@ static int schedule_task_del(struct task *task)
|
|||
|
||||
tracev_pipe("del");
|
||||
|
||||
/* add task to list */
|
||||
spin_lock_irq(&sch->lock, flags);
|
||||
|
||||
/* is task already running ? */
|
||||
if (task->state == TASK_STATE_RUNNING) {
|
||||
ret = -EAGAIN;
|
||||
goto out;
|
||||
/* check current task state, delete it if it is queued
|
||||
* if it is already running, nothing we can do about it atm
|
||||
*/
|
||||
if (task->state == TASK_STATE_QUEUED) {
|
||||
/* delete task */
|
||||
task->state = TASK_STATE_CANCEL;
|
||||
list_item_del(&task->list);
|
||||
}
|
||||
|
||||
list_item_del(&task->list);
|
||||
task->state = TASK_STATE_COMPLETED;
|
||||
|
||||
out:
|
||||
spin_unlock_irq(&sch->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static int _schedule_task(struct task *task, uint64_t start, uint64_t deadline)
|
||||
{
|
||||
|
@ -312,9 +318,11 @@ void schedule_task_complete(struct task *task)
|
|||
tracev_pipe("com");
|
||||
|
||||
spin_lock_irq(&sch->lock, flags);
|
||||
list_item_del(&task->list);
|
||||
task->state = TASK_STATE_COMPLETED;
|
||||
spin_unlock_irq(&sch->lock, flags);
|
||||
|
||||
/* tell any waiter that task has completed */
|
||||
wait_completed(&task->complete);
|
||||
}
|
||||
|
||||
static void scheduler_run(void *unused)
|
||||
|
|
Loading…
Reference in New Issue