From 744abc36c82978a82b66ec81f5e2ef6f9fb96bce Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 2 Aug 2011 07:07:16 +0200 Subject: [PATCH 1/2] minor optimization on single core systems --- kernel/tasks.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/kernel/tasks.c b/kernel/tasks.c index 48182a9b..bf57dda0 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -52,7 +52,9 @@ static task_t task_table[MAX_TASKS] = { \ static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT; DEFINE_PER_CORE(task_t*, current_task, task_table+0); +#if MAX_CORES > 1 DEFINE_PER_CORE_STATIC(task_t*, old_task, NULL); +#endif /** @brief helper function for the assembly code to determine the current task * @return Pointer to the task_t structure of current task @@ -177,6 +179,7 @@ void NORETURN abort(void) { */ inline static void task_switch_finished(void) { +#if MAX_CORES > 1 uint32_t flags = irq_nested_disable(); // do we already reset the TASK_SWITCH_IN_PROGRESS bit? @@ -187,6 +190,7 @@ inline static void task_switch_finished(void) } irq_nested_enable(flags); +#endif } /** @brief Create a task with a specific entry point @@ -839,10 +843,14 @@ void scheduler(void) if ((task_table[new_id].status == TASK_READY) && !(task_table[new_id].flags & TASK_SWITCH_IN_PROGESS)) { if (curr_task->status == TASK_RUNNING) { curr_task->status = TASK_READY; +#if MAX_CORES > 1 curr_task->flags |= TASK_SWITCH_IN_PROGESS; per_core(old_task) = curr_task; - } else per_core(old_task) = NULL; - +#endif + } +#if MAX_CORES > 1 + else per_core(old_task) = NULL; +#endif task_table[new_id].status = TASK_RUNNING; curr_task = per_core(current_task) = task_table+new_id; @@ -853,8 +861,10 @@ void scheduler(void) // kprintf("task switch %d is in progress\n", new_id); } +#if MAX_CORES > 1 // old task will never rescheduled per_core(old_task) = NULL; +#endif if ((curr_task->status == TASK_RUNNING) || (curr_task->status == TASK_IDLE)) goto get_task_out; From 026d5e264c57a6c1d8db0a36ed6c7398a9522b68 Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Tue, 2 Aug 2011 10:24:17 +0200 Subject: [PATCH 2/2] use table_lock to avoid GPs during a task switch --- include/metalsvm/tasks_types.h | 1 - kernel/tasks.c | 66 ++++++++-------------------------- 2 files changed, 14 insertions(+), 53 deletions(-) diff --git a/include/metalsvm/tasks_types.h b/include/metalsvm/tasks_types.h index c6e835e5..9725454b 100644 --- a/include/metalsvm/tasks_types.h +++ b/include/metalsvm/tasks_types.h @@ -50,7 +50,6 @@ extern "C" { #define TASK_DEFAULT_FLAGS 0 #define TASK_FPU_INIT (1 << 0) #define TASK_FPU_USED (1 << 1) -#define TASK_SWITCH_IN_PROGESS (1 << 2) typedef int (*entry_point_t)(void*); typedef int (STDCALL *internal_entry_point_t)(void*); diff --git a/kernel/tasks.c b/kernel/tasks.c index bf57dda0..6800e662 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -149,7 +149,7 @@ static void NORETURN do_exit(int arg) { curr_task->status = TASK_FINISHED; reschedule(); - kputs("Kernel panic: scheduler found no valid task\n"); + kprintf("Kernel panic: scheduler on core %d found no valid task\n", CORE_ID); while(1) { HALT; } @@ -174,22 +174,13 @@ void NORETURN abort(void) { } /* - * @brief: if the task switch is finished, we reset - * the TASK_SWITCH_IN_PROGRESS bit + * @brief: if the task gets the first time slice, + * the table_lock is hold and have to be released. */ -inline static void task_switch_finished(void) +inline static void start_first_time_slice(void) { #if MAX_CORES > 1 - uint32_t flags = irq_nested_disable(); - - // do we already reset the TASK_SWITCH_IN_PROGRESS bit? - task_t* old = per_core(old_task); - if (old) { - old->flags &= ~TASK_SWITCH_IN_PROGESS; - per_core(old_task) = NULL; - } - - irq_nested_enable(flags); + spinlock_irqsave_unlock(&table_lock); #endif } @@ -314,10 +305,7 @@ int sys_fork(void) // Leave the function without releasing the locks // because the locks are already released // by the parent task! - - // first switch to the new current task - // => signalizes a successful task switch - task_switch_finished(); + start_first_time_slice(); return 0; } @@ -352,9 +340,7 @@ static int STDCALL kernel_entry(void* args) int ret; kernel_args_t* kernel_args = (kernel_args_t*) args; - // first switch to the new current task - // => signalizes a successful task switch - task_switch_finished(); + start_first_time_slice(); if (BUILTIN_EXPECT(!kernel_args, 0)) return -EINVAL; @@ -595,9 +581,7 @@ static int STDCALL user_entry(void* arg) { int ret; - // first switch to the new current task - // => signalizes a successful task switch - task_switch_finished(); + start_first_time_slice(); if (BUILTIN_EXPECT(!arg, 0)) return -EINVAL; @@ -816,11 +800,6 @@ void scheduler(void) unsigned int i; unsigned int new_id; - // let's play it save - // => check if we already signalizes that the previous switch - // is finished - task_switch_finished(); - #if MAX_CORES > 1 spinlock_irqsave_lock(&table_lock); #endif @@ -840,32 +819,16 @@ void scheduler(void) for(i=1, new_id=(curr_task->id + 1) % MAX_TASKS; istatus == TASK_RUNNING) { + if (task_table[new_id].status == TASK_READY) { + if (curr_task->status == TASK_RUNNING) curr_task->status = TASK_READY; -#if MAX_CORES > 1 - curr_task->flags |= TASK_SWITCH_IN_PROGESS; - per_core(old_task) = curr_task; -#endif - } -#if MAX_CORES > 1 - else per_core(old_task) = NULL; -#endif task_table[new_id].status = TASK_RUNNING; curr_task = per_core(current_task) = task_table+new_id; goto get_task_out; } - - //if ((task_table[new_id].status == TASK_READY) && (task_table[new_id].flags & TASK_SWITCH_IN_PROGESS)) - // kprintf("task switch %d is in progress\n", new_id); } -#if MAX_CORES > 1 - // old task will never rescheduled - per_core(old_task) = NULL; -#endif - if ((curr_task->status == TASK_RUNNING) || (curr_task->status == TASK_IDLE)) goto get_task_out; @@ -878,14 +841,13 @@ void scheduler(void) get_task_out: //kprintf("schedule %d on core %d\n", per_core(current_task)->id, smp_id()); + + if (curr_task != orig_task) + switch_task(new_id); + #if MAX_CORES > 1 spinlock_irqsave_unlock(&table_lock); #endif - - if (curr_task != orig_task) { - switch_task(new_id); - task_switch_finished(); - } } void reschedule(void)