Nucleus
Barry Preemptive and lockless scheduler a1eaf26 (3 years, 1 month ago)
diff --git a/task/scheduler.c b/task/scheduler.c
index d83fe0c..d0fb83f 100644
--- a/task/scheduler.c
+++ b/task/scheduler.c
@@ -37,7 +37,7 @@ scheduler_new(Object *obj)
s->cpu = cpu->self;
s->task = NULL;
for (p = 0; p < PRIORITY_COUNT; p++)
- s->queue[p] = create_list(&taskType, LIST_NORMAL);
+ s->queue[p] = create_list(&taskType, LIST_LOCKLESS);
}
/* Destroy a scheduler object */
@@ -96,31 +96,34 @@ schedule(void)
Task *task = current;
Scheduler *s = cpu->scheduler;
ObjectList *queue = highest_priority_queue(s);
- s->timeslice = 0;
- /* Idle if necessary */
+ /* No schedulable tasks */
if (!queue) {
if (current && current->state == RUNNING)
- return;
+ goto end;
+
+ /* Idle */
current = NULL;
- if (task)
+ if (task) {
+ tasks--;
s->tasks--;
+ }
asm volatile("sti");
while (!(queue = highest_priority_queue(s)))
asm volatile("hlt");
asm volatile("cli");
- if (task)
+ if (task) {
+ tasks++;
s->tasks++;
+ }
current = task;
}
/* Schedule next task */
task = pop_from_start(queue);
task->state = RUNNING;
- if (task == current) {
- exit_critical_section();
- return;
- }
+ if (task == current)
+ goto end;
if (current && current->state == RUNNING) {
current->state = READY;
add(s->queue[current->priority], current);
@@ -128,8 +131,11 @@ schedule(void)
tasks--;
s->tasks--;
}
+end:
+ s->timeslice = task->priority * 10;
exit_critical_section();
- switch_to_task(task);
+ if (task != current)
+ switch_to_task(task);
}
/* Find the scheduler with the least tasks */
@@ -153,7 +159,7 @@ enqueue_task(Task *task)
Scheduler *s = task->scheduler;
if (__builtin_expect(!s, 0))
s = task->scheduler = least_used_scheduler();
- if (s != cpu->scheduler && 0) {
+ if (s != cpu->scheduler) {
send_ipiq(s->cpu->id, (ipiq_func_t) enqueue_task,
task, IPIQ_SYNC);
} else {
@@ -161,6 +167,8 @@ enqueue_task(Task *task)
tasks++;
s->tasks++;
add(s->queue[task->priority], task);
+ if (s->task && s->task->priority < task->priority)
+ s->timeslice = 0;
exit_critical_section();
}
}
@@ -181,8 +189,7 @@ balance_scheduler(void)
s->tasks--;
t = pop_from_start(highest_priority_queue(s));
t->scheduler = NULL;
- send_ipiq(least_used_scheduler()->cpu->id,
- (ipiq_func_t) enqueue_task, t, IPIQ_SYNC);
+ enqueue_task(t);
}
exit_critical_section();
}
diff --git a/task/task.c b/task/task.c
index 3d84436..539026a 100644
--- a/task/task.c
+++ b/task/task.c
@@ -142,8 +142,8 @@ unblock_task(Task *task)
{
lock(task);
task->state = READY;
- enqueue_task(task);
unlock(task);
+ enqueue_task(task);
}
/* Find a task by ID */
diff --git a/task/time.c b/task/time.c
index 654795c..d4d01f0 100644
--- a/task/time.c
+++ b/task/time.c
@@ -25,10 +25,7 @@ timer_handler(struct InterruptFrame *frame)
Scheduler *s = cpu->scheduler;
if (monotonic % 300000 == 0)
balance_scheduler();
- s->timeslice++;
-
- /* Call scheduler */
- if (s->timeslice < (current->priority * 10))
- return;
- schedule();
+ if (s->timeslice == 0)
+ schedule();
+ s->timeslice--;
}