commit 3a86ba96296bead08c90a338524dd3bf504e8942
parent 03d41e2e229a4efb1587956b27a9675c13f34ff5
Author: oblique <psyberbits@gmail.com>
Date: Sat, 27 Oct 2012 00:13:50 +0300
fix a bug in scheduler
Diffstat:
1 file changed, 22 insertions(+), 14 deletions(-)
diff --git a/kernel/sched.c b/kernel/sched.c
@@ -86,19 +86,29 @@ schedule(void)
static void
sched(struct regs *regs)
{
- struct task_struct *prev = current;
-
if (list_empty(&task_list_head))
return;
- if (prev) {
- if (prev->state != TASK_TERMINATE)
- prev->regs = *regs;
-
- if (list_is_last(&prev->list, &task_list_head))
- current = list_first_entry(&task_list_head, struct task_struct, list);
- else
- current = list_entry(prev->list.next, struct task_struct, list);
+ if (current) {
+ struct list_head *iter;
+ struct task_struct *task, *prev;
+
+ if (current->state != TASK_TERMINATE)
+ current->regs = *regs;
+
+ prev = current;
+ list_for_each(iter, &prev->list) {
+ if (iter == &task_list_head)
+ continue;
+ task = list_entry(iter, struct task_struct, list);
+ if (task->state == TASK_RUNNABLE) {
+ current = task;
+ break;
+ }
+ }
+
+ if (iter == &prev->list && prev->state != TASK_RUNNING)
+ current = NULL;
if (prev->state == TASK_TERMINATE) {
spinlock_lock(prev->lock);
@@ -106,10 +116,8 @@ sched(struct regs *regs)
spinlock_unlock(prev->lock);
kfree(prev->stack_alloc);
kfree(prev);
- if (list_empty(&task_list_head))
- current = NULL;
- } else
- current->state = TASK_RUNNABLE;
+ } else if (prev != current)
+ prev->state = TASK_RUNNABLE;
} else
current = list_first_entry(&task_list_head, struct task_struct, list);