From cf6017f59fb2ff71423c716ad9d9f60a1b65c7d0 Mon Sep 17 00:00:00 2001 From: bernie Date: Sun, 24 Aug 2008 18:12:49 +0000 Subject: [PATCH] preempt: Implement scheduling priorities git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1680 38d2e660-2303-0410-9eaa-f027e97ec537 --- app/demo/cfg/cfg_kern.h | 10 +++++----- bertos/cfg/cfg_kern.h | 12 ++++++++---- bertos/cpu/frame.h | 2 +- bertos/kern/idle.c | 3 ++- bertos/kern/irq.c | 9 ++++++--- bertos/kern/preempt.c | 11 +++++++++++ bertos/kern/proc.c | 43 +++++++++++++++++++++++++++++++++++++++++ bertos/kern/proc.h | 4 ++++ bertos/kern/proc_p.h | 41 +++++++++++++++++++++++++-------------- 9 files changed, 107 insertions(+), 28 deletions(-) diff --git a/app/demo/cfg/cfg_kern.h b/app/demo/cfg/cfg_kern.h index 8404f75f..1a33d9bf 100644 --- a/app/demo/cfg/cfg_kern.h +++ b/app/demo/cfg/cfg_kern.h @@ -39,7 +39,7 @@ #ifndef CFG_KERN_H #define CFG_KERN_H -#include "cfg/cfg_arch.h" /* ARCH_EMUL */ +#include "cfg/cfg_timer.h" // CONFIG_TIMER_EVENTS /** * Enable the multithreading kernel. @@ -49,25 +49,25 @@ /** * \name Optional kernel features - * * \{ */ /* Module/option Active Dependencies */ #define CONFIG_KERN_SCHED (1) #define CONFIG_KERN_SIGNALS (1 && CONFIG_KERN_SCHED) -#define CONFIG_KERN_TIMER (1) #define CONFIG_KERN_IRQ (1) #define CONFIG_KERN_HEAP (0) #define CONFIG_KERN_SEMAPHORES (0 && CONFIG_KERN_SIGNALS) #define CONFIG_KERN_MONITOR (1 && CONFIG_KERN_SCHED) -#define CONFIG_KERN_PREEMPT (1 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER && CONFIG_KERN_IRQ) +#define CONFIG_KERN_PREEMPT (1 && CONFIG_KERN_SCHED && CONFIG_TIMER_EVENTS && CONFIG_KERN_IRQ) +#define CONFIG_KERN_PRI (1 && CONFIG_KERN_PREEMPT) /*\}*/ + /* OBSOLETE */ #define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT /// [ms] Time sharing quantum (a prime number prevents interference effects) -#define CONFIG_KERN_QUANTUM 50 +#define CONFIG_KERN_QUANTUM 47 /// Module logging level. #define KERN_LOG_LEVEL LOG_LVL_ERR diff --git a/bertos/cfg/cfg_kern.h b/bertos/cfg/cfg_kern.h index 5c5a2eed..1c716c97 100644 --- a/bertos/cfg/cfg_kern.h +++ b/bertos/cfg/cfg_kern.h @@ -49,20 +49,24 @@ /** * \name Optional kernel features - * * \{ */ /* Module/option Active Dependencies */ #define CONFIG_KERN_SCHED (0) #define CONFIG_KERN_SIGNALS (0 && CONFIG_KERN_SCHED) -#define CONFIG_KERN_TIMER (0) #define CONFIG_KERN_IRQ (0) #define CONFIG_KERN_HEAP (0) #define CONFIG_KERN_SEMAPHORES (0 && CONFIG_KERN_SIGNALS) #define CONFIG_KERN_MONITOR (0 && CONFIG_KERN_SCHED) -#define CONFIG_KERN_PREEMPT (0 && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER && CONFIG_KERN_IRQ) +#define CONFIG_KERN_PREEMPT (0 && CONFIG_KERN_SCHED && CONFIG_TIMER_EVENTS && CONFIG_KERN_IRQ) +#define CONFIG_KERN_PRI (0 && CINFIG_KERN_PREEMPT) +/*\}*/ + +// FIXME: move somewhere +#define CONFIG_DEPEND(FEATURE, DEPENDENCIES) STATIC_ASSERT(!(FEATURE) || !!(DEPS)) + +CONFIG_DEPEND(CONFIG_KERN_PRI, CONFIG_KERN_PREEMPT); -/* EXPERIMENTAL */ /* OBSOLETE */ #define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT diff --git a/bertos/cpu/frame.h b/bertos/cpu/frame.h index 0ecfaa49..fe22f8e3 100644 --- a/bertos/cpu/frame.h +++ b/bertos/cpu/frame.h @@ -80,7 +80,7 @@ #define CPU_SAVED_REGS_CNT 1 #define CPU_STACK_GROWS_UPWARD 0 - #define CPU_SP_ON_EMPTY_SLOT 0 + #define CPU_SP_ON_EMPTY_SLOT 1 #elif CPU_DSP56K diff --git a/bertos/kern/idle.c b/bertos/kern/idle.c index ede234c3..2ea379c8 100644 --- a/bertos/kern/idle.c +++ b/bertos/kern/idle.c @@ -66,5 +66,6 @@ static NORETURN void idle(void) void idle_init(void) { - proc_new(idle, NULL, sizeof(idle_stack), idle_stack); + Process *idle_proc = proc_new(idle, NULL, sizeof(idle_stack), idle_stack); + proc_setPri(idle_proc, (int)~0); } diff --git a/bertos/kern/irq.c b/bertos/kern/irq.c index 9b87d69b..c8946319 100644 --- a/bertos/kern/irq.c +++ b/bertos/kern/irq.c @@ -38,6 +38,7 @@ #include #include +#include #include @@ -61,18 +62,20 @@ void irq_entry(int signum) if (old_process != CurrentProcess) { + IRQ_DISABLE; + TRACEMSG("switching from %p:%s to %p:%s", old_process, old_process ? old_process->monitor.name : "---", - CurrentProcess, CurrentProcess->monitor.name); + CurrentProcess, proc_currentName()); if (old_process) swapcontext(&old_process->context, &CurrentProcess->context); else setcontext(&CurrentProcess->context); - // not reached + IRQ_ENABLE; } - //TRACEMSG("keeping %p:%s", CurrentProcess, CurrentProcess->monitor.name); + TRACEMSG("resuming %p:%s", CurrentProcess, CurrentProcess->monitor.name); #endif // CONFIG_KERN_PREEMPT } diff --git a/bertos/kern/preempt.c b/bertos/kern/preempt.c index 95ffbea0..f285d43f 100644 --- a/bertos/kern/preempt.c +++ b/bertos/kern/preempt.c @@ -74,11 +74,22 @@ void proc_preempt_timer(UNUSED_ARG(void *, param)) if (!preempt_forbid_cnt) { IRQ_DISABLE; + + #if CONFIG_KERN_PRI + Process *rival = (Process *)LIST_HEAD(&ProcReadyList); + if (rival && rival->link.pri >= CurrentProcess->link.pri) + { + #endif + TRACEMSG("preempting %p:%s", CurrentProcess, proc_currentName()); #if 0 SCHED_ENQUEUE(CurrentProcess); proc_preempt(); #endif + #if CONFIG_KERN_PRI + } + #endif + IRQ_ENABLE; } diff --git a/bertos/kern/proc.c b/bertos/kern/proc.c index c3d89b43..b49c87f3 100644 --- a/bertos/kern/proc.c +++ b/bertos/kern/proc.c @@ -52,6 +52,11 @@ #include /* memset() */ +// FIXME: move somewhere +#define CONFIG_DEPEND(FEATURE, DEPS) STATIC_ASSERT(!(FEATURE) || !!(DEPS)) + +CONFIG_DEPEND(CONFIG_KERN_PRI, CONFIG_KERN_PREEMPT); + /* * The scheduer tracks ready processes by enqueuing them in the @@ -93,6 +98,10 @@ static void proc_init_struct(Process *proc) #if CONFIG_KERN_HEAP proc->flags = 0; #endif + +#if CONFIG_KERN_PRI + proc->link.pri = 0; +#endif } MOD_DEFINE(proc); @@ -261,6 +270,40 @@ void proc_rename(struct Process *proc, const char *name) #endif } +/** + * Change the scheduling priority of a process. + * + * Process piorities are signed ints, whereas a larger integer value means + * higher scheduling priority. The default priority for new processes is 0. + * The idle process runs with the lowest possible priority: INT_MIN. + * + * A process with a higher priority always preempts lower priority processes. + * Processes of equal priority share the CPU time according to a simple + * round-robin policy. + * + * As a general rule to maximize responsiveness, compute-bound processes + * should be assigned negative priorities and tight, interactive processes + * should be assigned positive priorities. + * + * To avoid interfering with system background activities such as input + * processing, application processes should remain within the range -10 + * and +10. + */ +void proc_setPri(struct Process *proc, int pri) +{ + if (proc->link.pri == pri) + return; + + proc->link.pri = pri; + + if (proc != CurrentProcess) + { + //proc_forbid(); + //TODO: re-enqueue process + //pric_permit(); + } +} + /** * Terminate the current process */ diff --git a/bertos/kern/proc.h b/bertos/kern/proc.h index db681ede..8a18bf74 100644 --- a/bertos/kern/proc.h +++ b/bertos/kern/proc.h @@ -77,6 +77,10 @@ void proc_rename(struct Process *proc, const char *name); const char *proc_name(struct Process *proc); const char *proc_currentName(void); +#if CONFIG_KERN_PRI +void proc_setPri(struct Process *proc, int pri); +#endif + /** * Disable preemptive task switching. * diff --git a/bertos/kern/proc_p.h b/bertos/kern/proc_p.h index 0d6a94f1..2c914d9e 100644 --- a/bertos/kern/proc_p.h +++ b/bertos/kern/proc_p.h @@ -53,7 +53,11 @@ typedef struct Process { +#if CONFIG_KERN_PRI + PriNode link; /**< Link Process into scheduler lists */ +#else Node link; /**< Link Process into scheduler lists */ +#endif cpustack_t *stack; /**< Per-process SP */ iptr_t user_data; /**< Custom data passed to the process */ @@ -105,20 +109,29 @@ extern REGISTER Process *CurrentProcess; */ extern REGISTER List ProcReadyList; - -/** - * Enqueue a task in the ready list. - * - * Always use this macro to instert a process in the ready list, as its - * might vary to implement a different scheduling algorithms. - * - * \note This macro is *NOT* protected against the scheduler. Access to - * this list must be performed with interrupts disabled. - */ -#define SCHED_ENQUEUE(proc) do { \ - LIST_ASSERT_VALID(&ProcReadyList); \ - ADDTAIL(&ProcReadyList, &(proc)->link); \ - } while (0) +#if CONFIG_KERN_PRI + /** + * Enqueue a task in the ready list. + * + * Always use this macro to instert a process in the ready list, as its + * might vary to implement a different scheduling algorithms. + * + * \note This macro is *NOT* protected against the scheduler. Access to + * this list must be performed with interrupts disabled. + */ + #define SCHED_ENQUEUE(proc) do { \ + LIST_ASSERT_VALID(&ProcReadyList); \ + LIST_ENQUEUE(&ProcReadyList, &(proc)->link); \ + } while (0) + +#else // !CONFIG_KERN_PRI + + #define SCHED_ENQUEUE(proc) do { \ + LIST_ASSERT_VALID(&ProcReadyList); \ + ADDTAIL(&ProcReadyList, &(proc)->link); \ + } while (0) + +#endif // !CONFIG_KERN_PRI /** Schedule to another process *without* adding the current to the ready list. */ void proc_schedule(void); -- 2.25.1