From 8cfe12e5b95974d75b98ec964fc7edaf37919f0e Mon Sep 17 00:00:00 2001 From: bernie Date: Wed, 13 Aug 2008 14:53:53 +0000 Subject: [PATCH] Initial (nonworking) draft of preemptive task switching git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1639 38d2e660-2303-0410-9eaa-f027e97ec537 --- app/demo/cfg/cfg_kern.h | 13 +++-- app/demo/demo.mk | 2 +- bertos/cfg/cfg_kern.h | 9 ++-- bertos/drv/timer.c | 3 -- bertos/kern/preempt.c | 106 ++++++++++++++++++++++++++++++++++++++++ bertos/kern/proc.c | 17 +++++-- bertos/kern/proc_p.h | 6 +++ 7 files changed, 139 insertions(+), 17 deletions(-) diff --git a/app/demo/cfg/cfg_kern.h b/app/demo/cfg/cfg_kern.h index 91a67cea..8dbd6608 100644 --- a/app/demo/cfg/cfg_kern.h +++ b/app/demo/cfg/cfg_kern.h @@ -26,8 +26,8 @@ * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. * - * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/) - * Copyright 1999,2000,2001 Bernie Innocenti + * Copyright 2001, 2004 Develer S.r.l. (http://www.develer.com/) + * Copyright 1999, 2000, 2001, 2008 Bernie Innocenti * --> * * \brief Kernel configuration parameters @@ -42,12 +42,12 @@ #include "cfg/cfg_arch.h" /* ARCH_EMUL */ /** - * Multithreading kernel. + * Enable the multithreading kernel. */ #define CONFIG_KERNEL 1 /** - * \name Modules activation + * \name Optional kernel features * * \{ */ @@ -61,7 +61,10 @@ /*\}*/ /* EXPERIMENTAL */ -#define CONFIG_KERN_PREEMPTIVE (0 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER) +#define CONFIG_KERN_PREEMPT (1 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER) + +/* OBSOLETE */ +#define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT /// Time sharing quantum in timer ticks. #define CONFIG_KERN_QUANTUM 50 diff --git a/app/demo/demo.mk b/app/demo/demo.mk index 20eb2b4e..941e28a6 100644 --- a/app/demo/demo.mk +++ b/app/demo/demo.mk @@ -51,9 +51,9 @@ demo_CSRC = \ bertos/mware/observer.c \ bertos/mware/resource.c \ bertos/mware/sprintf.c \ - bertos/kern/coop.c \ bertos/kern/proc.c \ bertos/kern/proc_test.c \ + bertos/kern/preempt.c \ bertos/kern/sem.c \ bertos/kern/signal.c \ bertos/kern/monitor.c \ diff --git a/bertos/cfg/cfg_kern.h b/bertos/cfg/cfg_kern.h index f11c2bcc..f54d0f7e 100644 --- a/bertos/cfg/cfg_kern.h +++ b/bertos/cfg/cfg_kern.h @@ -42,12 +42,12 @@ #include "cfg/cfg_arch.h" /* ARCH_EMUL */ /** - * Multithreading kernel. + * Enable the multithreading kernel. */ #define CONFIG_KERNEL 0 /** - * \name Modules activation + * \name Optional kernel features * * \{ */ @@ -61,7 +61,10 @@ /*\}*/ /* EXPERIMENTAL */ -#define CONFIG_KERN_PREEMPTIVE (0 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER) +#define CONFIG_KERN_PREEMPT (0 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER) + +/* OBSOLETE */ +#define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT /// Time sharing quantum in timer ticks. #define CONFIG_KERN_QUANTUM 50 diff --git a/bertos/drv/timer.c b/bertos/drv/timer.c index 333d6cd8..0d78d198 100644 --- a/bertos/drv/timer.c +++ b/bertos/drv/timer.c @@ -74,9 +74,6 @@ #endif #if CONFIG_KERNEL - #if CONFIG_KERN_PREEMPTIVE - #include - #endif #if CONFIG_KERN_SIGNALS #include /* sig_wait(), sig_check() */ #include /* proc_current() */ diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index f068a8a8..0cbaf7c9 100644 --- a/bertos/kern/preempt.c +++ b/bertos/kern/preempt.c @@ -41,6 +41,10 @@ #include "proc_p.h" #include "proc.h" +#include // CPU_IDLE + +#include // XXX alarm() + /* * The time sharing scheduler forces a task switch when the current @@ -78,3 +82,105 @@ void proc_permit(void) /* No need to protect against interrupts here. */ --CurrentProcess->forbid_cnt; } + +static void (*irq_handlers[100])(void); // FIXME + + +void proc_preempt(void) +{ + TRACE; + + ATOMIC(LIST_ASSERT_VALID(&ProcReadyList)); + + IRQ_DISABLE; + /* Poll on the ready queue for the first ready process */ + while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList))) + { + /* + * 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 ProcReadyList. 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. + */ + IRQ_ENABLE; + CPU_IDLE; + MEMORY_BARRIER; + IRQ_DISABLE; + } + IRQ_ENABLE; +} + +void proc_preempt_timer(void) +{ + // TODO: check Quantum + + alarm(1); + ATOMIC(SCHED_ENQUEUE(CurrentProcess)); + proc_schedule(); +} + +void proc_schedule(void) +{ + kill(0, SIGUSR1); +} + +void proc_yield(void) +{ + ATOMIC(SCHED_ENQUEUE(CurrentProcess)); + + proc_schedule(); +} + +/* signal handler */ +void irq_entry(int signum) +{ + Process *old_process; + + TRACEMSG("storing %p:%s", CurrentProcess, CurrentProcess->monitor.name); + CurrentProcess->leaving = false; + getcontext(&CurrentProcess->context); + /* We get here in two ways: directly, and after setcontext() below */ + + if (CurrentProcess->leaving) + { + TRACEMSG("leaving to %p:%s", CurrentProcess, CurrentProcess->monitor.name); + return; + } + + old_process = CurrentProcess; + + irq_handlers[signum](); + + if (old_process != CurrentProcess) + { + TRACEMSG("launching %p:%s", CurrentProcess, CurrentProcess->monitor.name); + CurrentProcess->leaving = true; + setcontext(&CurrentProcess->context); + /* not reached */ + } + + TRACEMSG("keeping %p:%s", CurrentProcess, CurrentProcess->monitor.name); +} + +void preempt_init(void) +{ + struct sigaction act; + act.sa_handler = irq_entry; + sigemptyset(&act.sa_mask); + sigaddset(&act.sa_mask, SIGUSR1); + sigaddset(&act.sa_mask, SIGALRM); + act.sa_flags = SA_RESTART; /* | SA_SIGINFO; */ + + irq_handlers[SIGUSR1] = proc_preempt; + irq_handlers[SIGALRM] = proc_preempt_timer; + sigaction(SIGUSR1, &act, NULL); + sigaction(SIGALRM, &act, NULL); + + alarm(1); +} diff --git a/bertos/kern/proc.c b/bertos/kern/proc.c index 9aa04546..bce8ac3e 100644 --- a/bertos/kern/proc.c +++ b/bertos/kern/proc.c @@ -26,9 +26,8 @@ * invalidate any other reasons why the executable file might be covered by * the GNU General Public License. * - * Copyright 2001,2004 Develer S.r.l. (http://www.develer.com/) - * Copyright 1999,2000,2001 Bernie Innocenti - * + * Copyright 2001, 2004 Develer S.r.l. (http://www.develer.com/) + * Copyright 1999, 2000, 2001, 2008 Bernie Innocenti * --> * * \brief Simple realtime multitasking scheduler. @@ -43,6 +42,7 @@ #include "proc.h" #include "cfg/cfg_arch.h" /* ARCH_EMUL */ +#include "cfg/cfg_kern.h" #include #include @@ -52,6 +52,10 @@ #include /* memset() */ +#if CONFIG_KERN_PREEMPT +#include "preempt.h" +#endif + /* * The scheduer tracks ready processes by enqueuing them in the * ready list. @@ -117,6 +121,10 @@ void proc_init(void) monitor_add(CurrentProcess, "main"); #endif +#if CONFIG_KERN_PREEMPTIVE + preempt_init(); +#endif + MOD_INIT(proc); } @@ -164,8 +172,7 @@ struct Process *proc_new_with_name(UNUSED(const char *, name), void (*entry)(voi #if CONFIG_KERN_MONITOR /* Fill-in the stack with a special marker to help debugging */ -#warning size incorrect - memset(stack_base, CONFIG_KERN_STACKFILLCODE, stack_size / sizeof(cpustack_t)); + memset(stack_base, CONFIG_KERN_STACKFILLCODE, stack_size); #endif /* Initialize the process control block */ diff --git a/bertos/kern/proc_p.h b/bertos/kern/proc_p.h index 54ba7be1..a98f9428 100644 --- a/bertos/kern/proc_p.h +++ b/bertos/kern/proc_p.h @@ -47,6 +47,10 @@ #include +#if CONFIG_KERN_PREEMPTIVE + #include // XXX +#endif + typedef struct Process { Node link; /**< Link Process into scheduler lists */ @@ -60,6 +64,8 @@ typedef struct Process #if CONFIG_KERN_PREEMPTIVE int forbid_cnt; /**< Nesting count for proc_forbid()/proc_permit(). */ + bool leaving; /**< XXX: maybe global? */ + ucontext_t context; #endif #if CONFIG_KERN_HEAP -- 2.25.1