Remove the idle process.
authorarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 19 Mar 2010 16:17:59 +0000 (16:17 +0000)
committerarighi <arighi@38d2e660-2303-0410-9eaa-f027e97ec537>
Fri, 19 Mar 2010 16:17:59 +0000 (16:17 +0000)
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 ==
<before>
   text    data     bss     dec     hex filename
  24632     238    5713   30583    7777 images/avr-kern.elf
<after>
   text    data     bss     dec     hex filename
  24498     234    5521   30253    762d images/avr-kern.elf

== at91sam7x example ==
<before>
   text    data     bss     dec     hex filename
  42416     184   10120   52720    cdf0 images/at91sam7x.elf
<after>
   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

14 files changed:
bertos/cfg/cfg_proc.h
bertos/kern/coop.c
bertos/kern/idle.c [deleted file]
bertos/kern/idle.h [deleted file]
bertos/kern/preempt.c
bertos/kern/proc.c
bertos/kern/proc.h
bertos/kern/proc_p.h
examples/at91sam7/at91sam7s.mk
examples/at91sam7/at91sam7x.mk
examples/at91sam7/cfg/cfg_proc.h
examples/demo/cfg/cfg_proc.h
examples/demo/demo.mk
test/run_tests.sh

index cb66e2735fc9614bca823805ee3c7649c27c964f..4d26b4272cfe1252c8524cb3c0a7a521417a5acd 100644 (file)
@@ -71,7 +71,7 @@
  * Preemptive process scheduling.
  *
  * $WIZ$ type = "boolean"
- * $WIZ$ conditional_deps = "timer", "idle"
+ * $WIZ$ conditional_deps = "timer"
  */
 #define CONFIG_KERN_PREEMPT 0
 
index c874ca36f8bdaac539f3078c4b70efc5fe6e79c5..1b2e1bb9bc42497a193d12e736642f8155b67250 100644 (file)
 #include <cpu/attr.h>
 #include <cpu/frame.h>
 
-/**
- * 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(&current_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 (file)
index 592d17b..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * \file
- * <!--
- * This file is part of BeRTOS.
- *
- * Bertos is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * As a special exception, you may use this file as part of a free software
- * library without restriction.  Specifically, if other files instantiate
- * templates or use macros or inline functions from this file, or you compile
- * this file and link it with other files to produce an executable, this
- * file does not by itself cause the resulting executable to be covered by
- * the GNU General Public License.  This exception does not however
- * invalidate any other reasons why the executable file might be covered by
- * the GNU General Public License.
- *
- * Copyright 2008 Bernie Innocenti <bernie@codewiz.org>
- * -->
- *
- * \brief Idle loop for preemptive scheduling
- *
- * \version $Id$
- * \author Bernie Innocenti <bernie@codewiz.org>
- */
-
-#include "idle.h"
-#include "proc.h"
-
-#include <cpu/power.h> // cpu_relax()
-#include <cfg/module.h>
-#include <cpu/types.h> // INT_MIN
-
-#include <kern/proc_p.h>
-
-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 (file)
index ca2fafc..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * \file
- * <!--
- * This file is part of BeRTOS.
- *
- * Bertos is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- * As a special exception, you may use this file as part of a free software
- * library without restriction.  Specifically, if other files instantiate
- * templates or use macros or inline functions from this file, or you compile
- * this file and link it with other files to produce an executable, this
- * file does not by itself cause the resulting executable to be covered by
- * the GNU General Public License.  This exception does not however
- * invalidate any other reasons why the executable file might be covered by
- * the GNU General Public License.
- *
- * Copyright 2008 Bernie Innocenti <bernie@codewiz.org>
- * -->
- *
- * \brief Idle loop for preemptive scheduling
- *
- * \version $Id$
- * \author Bernie Innocenti <bernie@codewiz.org>
- */
-#ifndef KERN_IDLE_H
-#define KERN_IDLE_H
-
-extern struct Process *idle_proc;
-
-void idle_init(void);
-#endif /* KERN_IDLE_H */
index 2f44164b20174382c48355b08842fe2e314b5e51..065faed88e17823eace2972fcd754927f0326f6e 100644 (file)
@@ -91,7 +91,6 @@
 
 #include <kern/irq.h>
 #include <kern/monitor.h>
-#include <kern/idle.h> // idle_proc
 #include <cpu/frame.h> // CPU_IDLE
 #include <cpu/irq.h>   // IRQ_DISABLE()...
 #include <cfg/log.h>
@@ -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(&current_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);
 }
index c422e729c6912963f51bfcd89f75a7cee269e290..623c1d3fb5d87dba4ceb91b5c35ddcd6f85749c8 100644 (file)
 
 #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(&current_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());
+}
index 842566b9db08cc3a77488b7092c866f9eff12b2e..390099da4b771789c5aa55741526f25284163330 100644 (file)
@@ -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);
index 5d106242de54a482a16f76f46b352fa626174a9f..27d65fe288193a3a78aa579c370fbb43273f1586 100644 (file)
@@ -49,7 +49,6 @@
 #include <cpu/irq.h>          // IRQ_ASSERT_DISABLED()
 
 #include <kern/proc.h>   // struct Process
-#include <kern/idle.h>        // 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);
 
index c3beda99dea210dbb97f66f8356e03b0248dbf03..e0ada56b7576ff11162ad3014a82f5c094cbff8e 100644 (file)
@@ -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 \
index d5d1871c5a34866841abc9a0d3c04afa3d04c85c..77e45791d596b2de9d5c8770055a6beb542f5e71 100644 (file)
@@ -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 \
index 076b3231382760473853f64a5473da6a876458d9..c59f6715cbc8267ee2bc5daebe148343e17c4645 100644 (file)
  * $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
 
index 696695d447e3cffdfe342d8af857e9acb30a3d88..cddfcb048b66181d1e18cb5e73a705fa2ff99e4b 100644 (file)
@@ -71,7 +71,7 @@
  * Preemptive process scheduling.
  *
  * $WIZ$ type = "boolean"
- * $WIZ$ conditional_deps = "timer", "idle"
+ * $WIZ$ conditional_deps = "timer"
  */
 #define CONFIG_KERN_PREEMPT 1
 
index d74afe135cdb9f4e71adb636d9172b6c9a67667e..838b8a948dc53e5018d6b2cbb946d18351982699 100644 (file)
@@ -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 \
index 7c6a9d8cf9946c142de5a388c425d64b4dba4f36..7150a5cb19fac7bbacaba4275c0193ed79858b22 100755 (executable)
@@ -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