X-Git-Url: https://codewiz.org/gitweb?a=blobdiff_plain;f=bertos%2Fkern%2Fpreempt.c;h=7ecd481d0cdf57c6d4c3679fc4ccfa43f5cc794e;hb=cfa8814ca45e8bae9b36713bc534ecb581834016;hp=f068a8a82c24d314d159e84a045422de18b55475;hpb=87302355709b6d5ac0592024b84207ba86baa82e;p=bertos.git diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index f068a8a8..7ecd481d 100644 --- a/bertos/kern/preempt.c +++ b/bertos/kern/preempt.c @@ -26,27 +26,27 @@ * 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. - * 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 - * \author Stefano Fedrigo */ #include "proc_p.h" #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; /** * Disable preemptive task switching. @@ -78,3 +78,100 @@ void proc_permit(void) /* No need to protect against interrupts here. */ --CurrentProcess->forbid_cnt; } + + +void proc_preempt(void) +{ + IRQ_DISABLE; + + LIST_ASSERT_VALID(&ProcReadyList); + CurrentProcess = (struct Process *)list_remHead(&ProcReadyList); + LIST_ASSERT_VALID(&ProcReadyList); + ASSERT2(CurrentProcess, "no idle proc?"); + + IRQ_ENABLE; + + TRACEMSG("new proc: %p:%s", CurrentProcess, CurrentProcess ? CurrentProcess->monitor.name : "---"); + monitor_report(); +} + +void proc_preempt_timer(UNUSED_ARG(void *, param)) +{ + IRQ_DISABLE; +/* + if (!CurrentProcess->forbid_cnt) + { + TRACEMSG("preempting %p:%s", CurrentProcess, CurrentProcess->monitor.name); + LIST_ASSERT_VALID(&ProcReadyList); + SCHED_ENQUEUE(CurrentProcess); + 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) +{ + TRACE; + + ASSERT_IRQ_ENABLED(); + IRQ_DISABLE; + SCHED_ENQUEUE(CurrentProcess); + LIST_ASSERT_VALID(&ProcReadyList); + proc_schedule(); + IRQ_ENABLE; +} + +void proc_entry(void (*user_entry)(void)) +{ + user_entry(); + 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); + 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); + + proc_new(idle, NULL, sizeof(idle_stack), idle_stack); +}