From d9d931610bca1df6ceb9227eacc9ff2c7f89b77a Mon Sep 17 00:00:00 2001 From: arighi Date: Fri, 19 Mar 2010 16:17:59 +0000 Subject: [PATCH] Remove the idle process. We can get rid of the idle process also with the preemptive kernel and perform the idle loop inside proc_schedule(). In this way we can reduce the kernel memory footprint and better optimize memory usage. == avr-kern example == text data bss dec hex filename 24632 238 5713 30583 7777 images/avr-kern.elf text data bss dec hex filename 24498 234 5521 30253 762d images/avr-kern.elf == at91sam7x example == text data bss dec hex filename 42416 184 10120 52720 cdf0 images/at91sam7x.elf text data bss dec hex filename 42228 184 9748 52160 cbc0 images/at91sam7x.elf git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3250 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/cfg/cfg_proc.h | 2 +- bertos/kern/coop.c | 80 ++---------------------------- bertos/kern/idle.c | 84 -------------------------------- bertos/kern/idle.h | 43 ---------------- bertos/kern/preempt.c | 38 +-------------- bertos/kern/proc.c | 63 +++++++++++++++++++++++- bertos/kern/proc.h | 2 - bertos/kern/proc_p.h | 6 ++- examples/at91sam7/at91sam7s.mk | 1 - examples/at91sam7/at91sam7x.mk | 1 - examples/at91sam7/cfg/cfg_proc.h | 4 +- examples/demo/cfg/cfg_proc.h | 2 +- examples/demo/demo.mk | 1 - test/run_tests.sh | 1 - 14 files changed, 74 insertions(+), 254 deletions(-) delete mode 100644 bertos/kern/idle.c delete mode 100644 bertos/kern/idle.h diff --git a/bertos/cfg/cfg_proc.h b/bertos/cfg/cfg_proc.h index cb66e273..4d26b427 100644 --- a/bertos/cfg/cfg_proc.h +++ b/bertos/cfg/cfg_proc.h @@ -71,7 +71,7 @@ * Preemptive process scheduling. * * $WIZ$ type = "boolean" - * $WIZ$ conditional_deps = "timer", "idle" + * $WIZ$ conditional_deps = "timer" */ #define CONFIG_KERN_PREEMPT 0 diff --git a/bertos/kern/coop.c b/bertos/kern/coop.c index c874ca36..1b2e1bb9 100644 --- a/bertos/kern/coop.c +++ b/bertos/kern/coop.c @@ -50,14 +50,6 @@ #include #include -/** - * CPU dependent context switching routines. - * - * Saving and restoring the context on the stack is done by a CPU-dependent - * support routine which usually needs to be written in assembly. - */ -EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp); - /** * Define function prototypes exported outside. * @@ -66,77 +58,11 @@ EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp); void coop_yield(void); void coop_switch(void); -/** - * System scheduler: pass CPU control to the next process in - * the ready queue. - */ -static void coop_schedule(void) -{ - cpu_flags_t flags; - - ATOMIC(LIST_ASSERT_VALID(&proc_ready_list)); - ASSERT_USER_CONTEXT(); - IRQ_ASSERT_ENABLED(); - - /* Poll on the ready queue for the first ready process */ - IRQ_SAVE_DISABLE(flags); - while (!(current_process = (struct Process *)list_remHead(&proc_ready_list))) - { - /* - * Make sure we physically reenable interrupts here, no matter what - * the current task status is. This is important because if we - * are idle-spinning, we must allow interrupts, otherwise no - * process will ever wake up. - * - * During idle-spinning, an interrupt can occur and it may - * modify \p proc_ready_list. To ensure that compiler reload this - * variable every while cycle we call CPU_MEMORY_BARRIER. - * The memory barrier ensure that all variables used in this context - * are reloaded. - * \todo If there was a way to write sig_wait() so that it does not - * disable interrupts while waiting, there would not be any - * reason to do this. - */ - IRQ_ENABLE; - CPU_IDLE; - MEMORY_BARRIER; - IRQ_DISABLE; - } - IRQ_RESTORE(flags); -} - void coop_switch(void) { - /* Remember old process to save its context later */ - Process * const old_process = current_process; - - coop_schedule(); - - /* - * Optimization: don't switch contexts when the active - * process has not changed. - */ - if (current_process != old_process) - { - cpu_stack_t *dummy; - - #if CONFIG_KERN_MONITOR - LOG_INFO("Switch from %p(%s) to %p(%s)\n", - old_process, proc_name(old_process), - current_process, proc_currentName()); - #endif - - /* Save context of old process and switch to new process. If there is no - * old process, we save the old stack pointer into a dummy variable that - * we ignore. In fact, this happens only when the old process has just - * exited. - * TODO: Instead of physically clearing the process at exit time, a zombie - * list should be created. - */ - asm_switch_context(¤t_process->stack, old_process ? &old_process->stack : &dummy); - } + IRQ_ASSERT_ENABLED(); - /* This RET resumes the execution on the new process */ + ATOMIC(proc_schedule()); } /** @@ -145,5 +71,5 @@ void coop_switch(void) void coop_yield(void) { ATOMIC(SCHED_ENQUEUE(current_process)); - proc_switch(); + coop_switch(); } diff --git a/bertos/kern/idle.c b/bertos/kern/idle.c deleted file mode 100644 index 592d17b1..00000000 --- a/bertos/kern/idle.c +++ /dev/null @@ -1,84 +0,0 @@ -/** - * \file - * - * - * \brief Idle loop for preemptive scheduling - * - * \version $Id$ - * \author Bernie Innocenti - */ - -#include "idle.h" -#include "proc.h" - -#include // cpu_relax() -#include -#include // INT_MIN - -#include - -struct Process *idle_proc; - -static PROC_DEFINE_STACK(idle_stack, KERN_MINSTACKSIZE); - -/** - * The idle process - * - * This process never dies and never sleeps. It's also quite lazy, apathic - * and sometimes even a little antisocial. - * - * Having an idle process costs us some stack space, but simplifies the - * interrupt-driven preemption logic because there is always a user - * context to which we can return. - * - * The idle process is not required for cooperative task switching. - */ -static NORETURN void idle(void) -{ - for (;;) - { - CPU_IDLE; - proc_switch(); - } -} - -void idle_init(void) -{ - /* - * Idle will be added to the ProcReadyList, but immediately removed - * after the first cpu_relax() execution. - * - * XXX: it would be better to never add idle_proc to the ProcReadyList, - * e.g., changing the prototype of proc_new() (or introducing a - * proc_new_nostart()) to allow the creation of "sleeping" tasks. - */ - idle_proc = proc_new(idle, NULL, sizeof(idle_stack), idle_stack); - proc_setPri(idle_proc, INT_MIN); -} diff --git a/bertos/kern/idle.h b/bertos/kern/idle.h deleted file mode 100644 index ca2fafc6..00000000 --- a/bertos/kern/idle.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * \file - * - * - * \brief Idle loop for preemptive scheduling - * - * \version $Id$ - * \author Bernie Innocenti - */ -#ifndef KERN_IDLE_H -#define KERN_IDLE_H - -extern struct Process *idle_proc; - -void idle_init(void); -#endif /* KERN_IDLE_H */ diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index 2f44164b..065faed8 100644 --- a/bertos/kern/preempt.c +++ b/bertos/kern/preempt.c @@ -91,7 +91,6 @@ #include #include -#include // idle_proc #include // CPU_IDLE #include // IRQ_DISABLE()... #include @@ -137,39 +136,8 @@ void preempt_init(void); */ static void preempt_schedule(void) { - Process *old_process = current_process; - - IRQ_ASSERT_DISABLED(); - - /* Poll on the ready queue for the first ready process */ - LIST_ASSERT_VALID(&proc_ready_list); - current_process = (Process *)list_remHead(&proc_ready_list); - if (UNLIKELY(!current_process)) - current_process = idle_proc; _proc_quantum = CONFIG_KERN_QUANTUM; - /* - * Optimization: don't switch contexts when the active process has not - * changed. - */ - if (LIKELY(old_process != current_process)) - { - cpu_stack_t *dummy; - - /* - * Save context of old process and switch to new process. If - * there is no old process, we save the old stack pointer into - * a dummy variable that we ignore. In fact, this happens only - * when the old process has just exited. - * - * \todo Instead of physically clearing the process at exit - * time, a zombie list should be created. - */ - asm_switch_context(¤t_process->stack, - old_process ? &old_process->stack : &dummy); - } - - /* This RET resumes the execution on the new process */ - LOG_INFO("resuming %p:%s\n", current_process, proc_currentName()); + proc_schedule(); } /** @@ -196,8 +164,7 @@ void preempt_preempt(void) /* Perform the kernel preemption */ LOG_INFO("preempting %p:%s\n", current_process, proc_currentName()); /* We are inside a IRQ context, so ATOMIC is not needed here */ - if (current_process != idle_proc) - SCHED_ENQUEUE(current_process); + SCHED_ENQUEUE(current_process); preempt_schedule(); } @@ -239,6 +206,5 @@ void preempt_yield(void) void preempt_init(void) { - idle_init(); MOD_INIT(preempt); } diff --git a/bertos/kern/proc.c b/bertos/kern/proc.c index c422e729..623c1d3f 100644 --- a/bertos/kern/proc.c +++ b/bertos/kern/proc.c @@ -62,6 +62,14 @@ #define PROC_SIZE_WORDS (ROUND_UP2(sizeof(Process), sizeof(cpu_stack_t)) / sizeof(cpu_stack_t)) +/** + * CPU dependent context switching routines. + * + * Saving and restoring the context on the stack is done by a CPU-dependent + * support routine which usually needs to be written in assembly. + */ +EXTERN_C void asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **save_sp); + /* * The scheduer tracks ready processes by enqueuing them in the * ready list. @@ -139,8 +147,6 @@ void proc_init(void) monitor_init(); monitor_add(current_process, "main"); #endif - proc_schedInit(); - MOD_INIT(proc); } @@ -430,3 +436,56 @@ iptr_t proc_currentUserData(void) { return current_process->user_data; } + +/** + * Call the scheduler and eventually replace the current running process. + */ +void proc_schedule(void) +{ + Process *old_process = current_process; + + IRQ_ASSERT_DISABLED(); + + /* Poll on the ready queue for the first ready process */ + LIST_ASSERT_VALID(&proc_ready_list); + while (!(current_process = (struct Process *)list_remHead(&proc_ready_list))) + { + /* + * Make sure we physically reenable interrupts here, no matter what + * the current task status is. This is important because if we + * are idle-spinning, we must allow interrupts, otherwise no + * process will ever wake up. + * + * During idle-spinning, an interrupt can occur and it may + * modify \p proc_ready_list. To ensure that compiler reload this + * variable every while cycle we call CPU_MEMORY_BARRIER. + * The memory barrier ensure that all variables used in this context + * are reloaded. + * \todo If there was a way to write sig_wait() so that it does not + * disable interrupts while waiting, there would not be any + * reason to do this. + */ + IRQ_ENABLE; + CPU_IDLE; + MEMORY_BARRIER; + IRQ_DISABLE; + } + /* + * Optimization: don't switch contexts when the active process has not + * changed. + */ + if (LIKELY(current_process != old_process)) { + cpu_stack_t *dummy; + + /* + * Save context of old process and switch to new process. If + * there is no old process, we save the old stack pointer into + * a dummy variable that we ignore. In fact, this happens only + * when the old process has just exited. + */ + asm_switch_context(¤t_process->stack, + old_process ? &old_process->stack : &dummy); + } + /* This RET resumes the execution on the new process */ + LOG_INFO("resuming %p:%s\n", current_process, proc_currentName()); +} diff --git a/bertos/kern/proc.h b/bertos/kern/proc.h index 842566b9..390099da 100644 --- a/bertos/kern/proc.h +++ b/bertos/kern/proc.h @@ -167,7 +167,6 @@ INLINE void __proc_noop(void) * Preemptive scheduler: private methods. */ #define preempt_switch proc_switch - #define preempt_init proc_schedInit #else /** * Co-operative scheduler: public methods. @@ -179,7 +178,6 @@ INLINE void __proc_noop(void) * Co-operative scheduler: private methods. */ #define coop_switch proc_switch - #define proc_schedInit __proc_noop #endif void proc_rename(struct Process *proc, const char *name); diff --git a/bertos/kern/proc_p.h b/bertos/kern/proc_p.h index 5d106242..27d65fe2 100644 --- a/bertos/kern/proc_p.h +++ b/bertos/kern/proc_p.h @@ -49,7 +49,6 @@ #include // IRQ_ASSERT_DISABLED() #include // struct Process -#include // idle_proc /** @@ -71,7 +70,7 @@ extern REGISTER Process *current_process; extern REGISTER List proc_ready_list; #if CONFIG_KERN_PRI - #define prio_next() (LIST_EMPTY(&proc_ready_list) ? idle_proc->link.pri : \ + #define prio_next() (LIST_EMPTY(&proc_ready_list) ? INT_MIN : \ ((PriNode *)LIST_HEAD(&proc_ready_list))->pri) #define prio_curr() (current_process->link.pri) @@ -151,6 +150,9 @@ void proc_entry(void); /* Schedule another process *without* adding the current one to the ready list. */ void proc_switch(void); +/* Low level scheduling routine. */ +void proc_schedule(void); + /* Initialize a scheduler class. */ void proc_schedInit(void); diff --git a/examples/at91sam7/at91sam7s.mk b/examples/at91sam7/at91sam7s.mk index c3beda99..e0ada56b 100644 --- a/examples/at91sam7/at91sam7s.mk +++ b/examples/at91sam7/at91sam7s.mk @@ -30,7 +30,6 @@ at91sam7s_CSRC = \ bertos/kern/proc.c \ bertos/kern/coop.c \ bertos/kern/preempt.c \ - bertos/kern/idle.c \ bertos/kern/proc_test.c \ bertos/kern/monitor.c \ bertos/kern/signal.c \ diff --git a/examples/at91sam7/at91sam7x.mk b/examples/at91sam7/at91sam7x.mk index d5d1871c..77e45791 100644 --- a/examples/at91sam7/at91sam7x.mk +++ b/examples/at91sam7/at91sam7x.mk @@ -31,7 +31,6 @@ at91sam7x_CSRC = \ bertos/kern/proc.c \ bertos/kern/coop.c \ bertos/kern/preempt.c \ - bertos/kern/idle.c \ bertos/kern/proc_test.c \ bertos/kern/monitor.c \ bertos/kern/signal.c \ diff --git a/examples/at91sam7/cfg/cfg_proc.h b/examples/at91sam7/cfg/cfg_proc.h index 076b3231..c59f6715 100644 --- a/examples/at91sam7/cfg/cfg_proc.h +++ b/examples/at91sam7/cfg/cfg_proc.h @@ -65,13 +65,13 @@ * $WIZ$ type = "int" * $WIZ$ min = 0 */ -#define CONFIG_KERN_HEAP_SIZE 16386L +#define CONFIG_KERN_HEAP_SIZE 16384L /** * Preemptive process scheduling. * * $WIZ$ type = "boolean" - * $WIZ$ conditional_deps = "timer", "idle" + * $WIZ$ conditional_deps = "timer" */ #define CONFIG_KERN_PREEMPT 1 diff --git a/examples/demo/cfg/cfg_proc.h b/examples/demo/cfg/cfg_proc.h index 696695d4..cddfcb04 100644 --- a/examples/demo/cfg/cfg_proc.h +++ b/examples/demo/cfg/cfg_proc.h @@ -71,7 +71,7 @@ * Preemptive process scheduling. * * $WIZ$ type = "boolean" - * $WIZ$ conditional_deps = "timer", "idle" + * $WIZ$ conditional_deps = "timer" */ #define CONFIG_KERN_PREEMPT 1 diff --git a/examples/demo/demo.mk b/examples/demo/demo.mk index d74afe13..838b8a94 100644 --- a/examples/demo/demo.mk +++ b/examples/demo/demo.mk @@ -56,7 +56,6 @@ demo_CSRC = \ bertos/mware/resource.c \ bertos/mware/sprintf.c \ bertos/struct/heap.c \ - bertos/kern/idle.c \ bertos/kern/coop.c \ bertos/kern/preempt.c \ bertos/kern/irq.c \ diff --git a/test/run_tests.sh b/test/run_tests.sh index 7c6a9d8c..7150a5cb 100755 --- a/test/run_tests.sh +++ b/test/run_tests.sh @@ -34,7 +34,6 @@ SRC_LIST=" bertos/drv/kdebug.c bertos/drv/timer.c bertos/fs/battfs.c - bertos/kern/idle.c bertos/kern/kfile.c bertos/kern/monitor.c bertos/kern/proc.c -- 2.25.1