X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fkern%2Fpreempt.c;h=9af6c0d1b402a973cc144532c15c2f1ae5d15d2f;hb=022b3bd1d64ec490ddd0e8e3d72c0d1405504c31;hp=f068a8a82c24d314d159e84a045422de18b55475;hpb=87302355709b6d5ac0592024b84207ba86baa82e;p=bertos.git diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index f068a8a8..9af6c0d1 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,16 @@ * * \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 +#include // CPU_IDLE +#include +#include + /* * The time sharing scheduler forces a task switch when the current @@ -48,6 +51,8 @@ */ uint16_t Quantum; +Timer preempt_timer; + /** * Disable preemptive task switching. * @@ -78,3 +83,87 @@ void proc_permit(void) /* No need to protect against interrupts here. */ --CurrentProcess->forbid_cnt; } + + +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(); +} + +void preempt_init(void) +{ + MOD_CHECK(irq); + MOD_CHECK(timer); + + irq_register(SIGUSR1, proc_preempt); + + timer_setSoftint(&preempt_timer, proc_preempt_timer, NULL); + timer_setDelay(&preempt_timer, CONFIG_KERN_QUANTUM); + timer_add(&preempt_timer); +}