X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fkern%2Fpreempt.c;h=339dc09fe089e8e00e7e38b5e77c04a412f22016;hb=19691d6e16c66fa0ed6176efa0d741b0f3e9d7bb;hp=f068a8a82c24d314d159e84a045422de18b55475;hpb=87302355709b6d5ac0592024b84207ba86baa82e;p=bertos.git diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index f068a8a8..339dc09f 100644 --- a/bertos/kern/preempt.c +++ b/bertos/kern/preempt.c @@ -26,8 +26,7 @@ * 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, 2008 Bernie Innocenti + * Copyright 2008 Bernie Innocenti * --> * * \brief Simple realtime multitasking scheduler. @@ -35,12 +34,14 @@ * * \version $Id: proc.c 1616 2008-08-10 19:41:26Z bernie $ * \author Bernie Innocenti - * \author Stefano Fedrigo */ #include "proc_p.h" #include "proc.h" +#include // CPU_IDLE +#include + /* * The time sharing scheduler forces a task switch when the current @@ -48,6 +49,8 @@ */ uint16_t Quantum; +Timer preempt_timer; + /** * Disable preemptive task switching. * @@ -78,3 +81,138 @@ 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)); + + 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"); +} + +void proc_preempt_timer(UNUSED_ARG(void *, param)) +{ + IRQ_DISABLE; + if (CurrentProcess) + { + TRACEMSG("preempting %p:%s", CurrentProcess, CurrentProcess->monitor.name); + SCHED_ENQUEUE(CurrentProcess); + IRQ_ENABLE; + proc_preempt(); + } + IRQ_ENABLE; + + timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM); + timer_add(&preempt_timer); +} + +void proc_schedule(void) +{ + TRACE; + + // Will invoke proc_preempt() in interrupt context + kill(0, SIGUSR1); +} + +void proc_yield(void) +{ + ATOMIC(SCHED_ENQUEUE(CurrentProcess)); + + proc_schedule(); +} + +void proc_entry(void (*user_entry)(void)) +{ + user_entry(); + proc_exit(); +} + +/* signal handler */ +void irq_entry(int signum) +{ + Process * const old_process = CurrentProcess; + + irq_handlers[signum](); + + if (!CurrentProcess) + { + TRACEMSG("no runnable processes!"); + IRQ_ENABLE; + pause(); + } + else + { + 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); + } +} + +void irq_register(int irq, void (*callback)(void)) +{ + irq_handlers[irq] = callback; +} + +void irq_init(void) +{ + struct sigaction act; + act.sa_handler = irq_entry; + sigemptyset(&act.sa_mask); + //sigaddset(&act.sa_mask, irq); + act.sa_flags = SA_RESTART; /* | SA_SIGINFO; */ + + sigaction(SIGUSR1, &act, NULL); + #if !(ARCH & ARCH_QT) + sigaction(SIGALRM, &act, NULL); + #endif +} + +void preempt_init(void) +{ + irq_init(); // FIXME: move before + irq_register(SIGUSR1, proc_preempt); + + timer_setSoftInt(&preempt_timer, proc_preempt_timer, NULL); + timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM); + timer_add(&preempt_timer); +}