Skip to content

Commit d527b50

Browse files
RanderWangxiulipan
authored andcommitted
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>
1 parent 7be08fd commit d527b50

3 files changed

Lines changed: 35 additions & 16 deletions

File tree

src/audio/pipeline.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,7 +1275,12 @@ void pipeline_schedule_copy_idle(struct pipeline *p)
12751275

12761276
void pipeline_schedule_cancel(struct pipeline *p)
12771277
{
1278-
schedule_task_complete(&p->pipe_task);
1278+
int err;
1279+
1280+
/* cancel and wait for pipeline to complete */
1281+
err = schedule_task_cancel(&p->pipe_task);
1282+
if (err < 0)
1283+
trace_pipe_error("pC0");
12791284
}
12801285

12811286
static void pipeline_task(void *arg)

src/include/sof/schedule.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <sof/lock.h>
3939
#include <sof/list.h>
4040
#include <sof/work.h>
41+
#include <sof/wait.h>
4142

4243
struct schedule_data;
4344
struct sof;
@@ -56,6 +57,8 @@ struct sof;
5657
#define TASK_PRI_MED 0
5758
#define TASK_PRI_HIGH -20
5859

60+
/* maximun task time slice in microseconds */
61+
#define SCHEDULE_TASK_MAX_TIME_SLICE 5000
5962

6063
/* task descriptor */
6164
struct task {
@@ -73,6 +76,7 @@ struct task {
7376

7477
/* runtime duration in scheduling clock base */
7578
uint64_t max_rtime; /* max time taken to run */
79+
completion_t complete;
7680
};
7781

7882
struct schedule_data **arch_schedule_get(void);
@@ -83,6 +87,8 @@ void schedule_task(struct task *task, uint64_t start, uint64_t deadline);
8387

8488
void schedule_task_idle(struct task *task, uint64_t deadline);
8589

90+
int schedule_task_cancel(struct task *task);
91+
8692
void schedule_task_complete(struct task *task);
8793

8894
static inline void schedule_task_init(struct task *task, void (*func)(void *),

src/lib/schedule.c

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,11 @@ static uint64_t sch_work(void *data, uint64_t delay)
170170
*/
171171
static struct task *schedule_edf(void)
172172
{
173+
struct schedule_data *sch = *arch_schedule_get();
173174
struct task *task;
174175
struct task *future_task = NULL;
175176
uint64_t current;
177+
uint32_t flags;
176178

177179
tracev_pipe("edf");
178180

@@ -195,42 +197,46 @@ static struct task *schedule_edf(void)
195197
} else {
196198
/* yes, run current task */
197199
task->start = current;
200+
201+
/* init task for running */
202+
wait_init(&task->complete);
203+
spin_lock_irq(&sch->lock, flags);
198204
task->state = TASK_STATE_RUNNING;
205+
list_item_del(&task->list);
206+
spin_unlock_irq(&sch->lock, flags);
207+
208+
/* now run task at correct run level */
199209
run_task(task);
200210
}
201211

202212
/* tell caller about future task */
203213
return future_task;
204214
}
205215

206-
#if 0 /* FIXME: is this needed ? */
207-
/* delete task from scheduler */
208-
static int schedule_task_del(struct task *task)
216+
/* cancel and delete task from scheduler - won't stop it if already running */
217+
int schedule_task_cancel(struct task *task)
209218
{
210219
struct schedule_data *sch = *arch_schedule_get();
211220
uint32_t flags;
212221
int ret = 0;
213222

214223
tracev_pipe("del");
215224

216-
/* add task to list */
217225
spin_lock_irq(&sch->lock, flags);
218226

219-
/* is task already running ? */
220-
if (task->state == TASK_STATE_RUNNING) {
221-
ret = -EAGAIN;
222-
goto out;
227+
/* check current task state, delete it if it is queued
228+
* if it is already running, nothing we can do about it atm
229+
*/
230+
if (task->state == TASK_STATE_QUEUED) {
231+
/* delete task */
232+
task->state = TASK_STATE_CANCEL;
233+
list_item_del(&task->list);
223234
}
224235

225-
list_item_del(&task->list);
226-
task->state = TASK_STATE_COMPLETED;
227-
228-
out:
229236
spin_unlock_irq(&sch->lock, flags);
237+
230238
return ret;
231239
}
232-
#endif
233-
234240

235241
static int _schedule_task(struct task *task, uint64_t start, uint64_t deadline)
236242
{
@@ -312,9 +318,11 @@ void schedule_task_complete(struct task *task)
312318
tracev_pipe("com");
313319

314320
spin_lock_irq(&sch->lock, flags);
315-
list_item_del(&task->list);
316321
task->state = TASK_STATE_COMPLETED;
317322
spin_unlock_irq(&sch->lock, flags);
323+
324+
/* tell any waiter that task has completed */
325+
wait_completed(&task->complete);
318326
}
319327

320328
static void scheduler_run(void *unused)

0 commit comments

Comments
 (0)