* Preemptive process scheduling.
*
* $WIZ$ type = "boolean"
- * $WIZ$ conditional_deps = "timer", "idle"
+ * $WIZ$ conditional_deps = "timer"
*/
#define CONFIG_KERN_PREEMPT 0
#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.
*
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());
}
/**
void coop_yield(void)
{
ATOMIC(SCHED_ENQUEUE(current_process));
- proc_switch();
+ coop_switch();
}
+++ /dev/null
-/**
- * \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);
-}
+++ /dev/null
-/**
- * \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 */
#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>
*/
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();
}
/**
/* 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();
}
void preempt_init(void)
{
- idle_init();
MOD_INIT(preempt);
}
#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.
monitor_init();
monitor_add(current_process, "main");
#endif
- proc_schedInit();
-
MOD_INIT(proc);
}
{
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());
+}
* Preemptive scheduler: private methods.
*/
#define preempt_switch proc_switch
- #define preempt_init proc_schedInit
#else
/**
* Co-operative scheduler: public methods.
* 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);
#include <cpu/irq.h> // IRQ_ASSERT_DISABLED()
#include <kern/proc.h> // struct Process
-#include <kern/idle.h> // idle_proc
/**
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)
/* 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);
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 \
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 \
* $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
* Preemptive process scheduling.
*
* $WIZ$ type = "boolean"
- * $WIZ$ conditional_deps = "timer", "idle"
+ * $WIZ$ conditional_deps = "timer"
*/
#define CONFIG_KERN_PREEMPT 1
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 \
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