From cfa8814ca45e8bae9b36713bc534ecb581834016 Mon Sep 17 00:00:00 2001 From: bernie Date: Wed, 20 Aug 2008 19:46:33 +0000 Subject: [PATCH] preempt: introduce idle process; timer: use managed irqs for preemption git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1665 38d2e660-2303-0410-9eaa-f027e97ec537 --- bertos/drv/timer.c | 3 +- bertos/drv/timer.h | 3 +- bertos/emul/timer_posix.c | 35 +++++++++-------- bertos/kern/irq.c | 39 +++++++------------ bertos/kern/preempt.c | 82 +++++++++++++++++++++------------------ bertos/kern/signal.c | 4 +- 6 files changed, 84 insertions(+), 82 deletions(-) diff --git a/bertos/drv/timer.c b/bertos/drv/timer.c index f282478a..485cc022 100644 --- a/bertos/drv/timer.c +++ b/bertos/drv/timer.c @@ -54,7 +54,8 @@ * Try the CPU specific one for bare-metal environments. */ #if OS_HOSTED - #include OS_CSOURCE(timer) + //#include OS_CSOURCE(timer) + #include #else #include CPU_CSOURCE(timer) #endif diff --git a/bertos/drv/timer.h b/bertos/drv/timer.h index 41f43f65..6ae1907e 100644 --- a/bertos/drv/timer.h +++ b/bertos/drv/timer.h @@ -51,7 +51,8 @@ * Try the CPU specific one for bare-metal environments. */ #if OS_HOSTED - #include OS_HEADER(timer) + //#include OS_HEADER(timer) + #include #else #include CPU_HEADER(timer) #endif diff --git a/bertos/emul/timer_posix.c b/bertos/emul/timer_posix.c index ede53406..d54c6120 100644 --- a/bertos/emul/timer_posix.c +++ b/bertos/emul/timer_posix.c @@ -29,17 +29,20 @@ * Copyright 2005, 2008 Develer S.r.l. (http://www.develer.com/) * --> * - * \version $Id$ + * \brief Low-level timer module for Qt emulator (implementation). * + * \version $Id$ * \author Bernie Innocenti - * \brief Low-level timer module for Qt emulator (implementation). */ -#include // hptime.t +//#include // hptime.t #include +#include // irq_register() +#if !CONFIG_KERN_IRQ #include // sigaction() -#include // setitimer() #include // memset() +#endif +#include // setitimer() // Forward declaration for the user interrupt server routine. @@ -48,19 +51,19 @@ void timer_isr(int); /// HW dependent timer initialization. static void timer_hw_init(void) { -#if CONFIG_KERN_IRQ - irq_register(SIGALRM, timer_isr); -#else // ! CONFIG_KERN_IRQ - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); + #if CONFIG_KERN_IRQ + irq_register(SIGALRM, (void (*)(void))timer_isr); + #else // ! CONFIG_KERN_IRQ + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); - // Setup interrupt callback - sa.sa_handler = timer_isr; - sigemptyset(&sa.sa_mask); - sigaddset(&sa.sa_mask, SIGALRM); - sa.sa_flags = SA_RESTART; - sigaction(SIGALRM, &sa, NULL); -#endif // CONFIG_KERN_IRQ + // Setup interrupt callback + sa.sa_handler = timer_isr; + sigemptyset(&sa.sa_mask); + sigaddset(&sa.sa_mask, SIGALRM); + sa.sa_flags = SA_RESTART; + sigaction(SIGALRM, &sa, NULL); + #endif // CONFIG_KERN_IRQ // Setup POSIX realtime timer to interrupt every 1/TIMER_TICKS_PER_SEC. static const struct itimerval itv = diff --git a/bertos/kern/irq.c b/bertos/kern/irq.c index 23d19afa..9b87d69b 100644 --- a/bertos/kern/irq.c +++ b/bertos/kern/irq.c @@ -57,29 +57,22 @@ void irq_entry(int signum) irq_handlers[signum](); #if CONFIG_KERN_PREEMPT - if (!CurrentProcess) - { - TRACEMSG("no runnable processes!"); - IRQ_ENABLE; - pause(); - } - else + ASSERT2(CurrentProcess, "no idle proc?"); + + if (old_process != CurrentProcess) { - if (old_process != CurrentProcess) - { - TRACEMSG("switching from %p:%s to %p:%s", - old_process, old_process ? old_process->monitor.name : "-", - CurrentProcess, CurrentProcess->monitor.name); - - if (old_process) - swapcontext(&old_process->context, &CurrentProcess->context); - else - setcontext(&CurrentProcess->context); - - // not reached - } - TRACEMSG("keeping %p:%s", CurrentProcess, CurrentProcess->monitor.name); + TRACEMSG("switching from %p:%s to %p:%s", + old_process, old_process ? old_process->monitor.name : "---", + CurrentProcess, CurrentProcess->monitor.name); + + if (old_process) + swapcontext(&old_process->context, &CurrentProcess->context); + else + setcontext(&CurrentProcess->context); + + // not reached } + //TRACEMSG("keeping %p:%s", CurrentProcess, CurrentProcess->monitor.name); #endif // CONFIG_KERN_PREEMPT } @@ -97,9 +90,7 @@ void irq_init(void) act.sa_flags = SA_RESTART; // | SA_SIGINFO; sigaction(SIGUSR1, &act, NULL); - #if !(ARCH & ARCH_QT) - sigaction(SIGALRM, &act, NULL); - #endif + sigaction(SIGALRM, &act, NULL); MOD_INIT(irq); } diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index 9af6c0d1..7ecd481d 100644 --- a/bertos/kern/preempt.c +++ b/bertos/kern/preempt.c @@ -29,8 +29,7 @@ * Copyright 2008 Bernie Innocenti * --> * - * \brief Simple realtime multitasking scheduler. - * Context switching is only done cooperatively. + * \brief Simple preemptive multitasking scheduler. * * \version $Id: proc.c 1616 2008-08-10 19:41:26Z bernie $ * \author Bernie Innocenti @@ -40,16 +39,12 @@ #include "proc.h" #include +#include #include // CPU_IDLE #include #include -/* - * The time sharing scheduler forces a task switch when the current - * process has exhausted its quantum. - */ -uint16_t Quantum; Timer preempt_timer; @@ -87,48 +82,31 @@ void proc_permit(void) void proc_preempt(void) { - TRACE; + IRQ_DISABLE; - ATOMIC(LIST_ASSERT_VALID(&ProcReadyList)); + LIST_ASSERT_VALID(&ProcReadyList); + CurrentProcess = (struct Process *)list_remHead(&ProcReadyList); + LIST_ASSERT_VALID(&ProcReadyList); + ASSERT2(CurrentProcess, "no idle proc?"); - TRACEMSG("hello1"); - IRQ_DISABLE; - /* Poll on the ready queue for the first ready process */ - while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList))) - { - //TRACEMSG("hello2"); - /* - * 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; - //FIXME: calls Qt stuff from sighandler! CPU_IDLE; - MEMORY_BARRIER; - IRQ_DISABLE; - //TRACEMSG("hello3"); - } IRQ_ENABLE; - TRACEMSG("hello4"); + + TRACEMSG("new proc: %p:%s", CurrentProcess, CurrentProcess ? CurrentProcess->monitor.name : "---"); + monitor_report(); } void proc_preempt_timer(UNUSED_ARG(void *, param)) { IRQ_DISABLE; - if (CurrentProcess) +/* + if (!CurrentProcess->forbid_cnt) { TRACEMSG("preempting %p:%s", CurrentProcess, CurrentProcess->monitor.name); + LIST_ASSERT_VALID(&ProcReadyList); SCHED_ENQUEUE(CurrentProcess); - IRQ_ENABLE; proc_preempt(); } +*/ IRQ_ENABLE; timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM); @@ -145,9 +123,14 @@ void proc_schedule(void) void proc_yield(void) { - ATOMIC(SCHED_ENQUEUE(CurrentProcess)); + TRACE; + ASSERT_IRQ_ENABLED(); + IRQ_DISABLE; + SCHED_ENQUEUE(CurrentProcess); + LIST_ASSERT_VALID(&ProcReadyList); proc_schedule(); + IRQ_ENABLE; } void proc_entry(void (*user_entry)(void)) @@ -156,6 +139,29 @@ void proc_entry(void (*user_entry)(void)) proc_exit(); } + +static cpustack_t idle_stack[CONFIG_PROC_DEFSTACKSIZE / sizeof(cpustack_t)]; + +/* + * The idle process + * + * This process never dies and never sleeps. It's also quite apathic + * and a bit antisocial. + * + * Having an idle process costs some stack space, but simplifies the + * interrupt-driven preemption logic because there is always a user + * context to which we can return. + */ +static NORETURN void idle(void) +{ + for (;;) + { + TRACE; + monitor_report(); + proc_yield(); // FIXME: CPU_IDLE + } +} + void preempt_init(void) { MOD_CHECK(irq); @@ -166,4 +172,6 @@ void preempt_init(void) timer_setSoftint(&preempt_timer, proc_preempt_timer, NULL); timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM); timer_add(&preempt_timer); + + proc_new(idle, NULL, sizeof(idle_stack), idle_stack); } diff --git a/bertos/kern/signal.c b/bertos/kern/signal.c index d7633a14..4333fa79 100644 --- a/bertos/kern/signal.c +++ b/bertos/kern/signal.c @@ -28,7 +28,6 @@ * * Copyright 2004, 2008 Develer S.r.l. (http://www.develer.com/) * Copyright 1999, 2000, 2001 Bernie Innocenti - * * --> * * \brief IPC signals implementation. @@ -96,7 +95,6 @@ * timer_delayTickes(). * * \version $Id$ - * * \author Bernie Innocenti */ @@ -106,7 +104,7 @@ #include #include #include - + #if CONFIG_KERN_SIGNALS -- 2.25.1