preempt: Implement scheduling priorities
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Sun, 24 Aug 2008 18:12:49 +0000 (18:12 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Sun, 24 Aug 2008 18:12:49 +0000 (18:12 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1680 38d2e660-2303-0410-9eaa-f027e97ec537

app/demo/cfg/cfg_kern.h
bertos/cfg/cfg_kern.h
bertos/cpu/frame.h
bertos/kern/idle.c
bertos/kern/irq.c
bertos/kern/preempt.c
bertos/kern/proc.c
bertos/kern/proc.h
bertos/kern/proc_p.h

index 8404f75f8ed056cad538b23d844500a49cf86c60..1a33d9bf9bd0df977d35affbf15d271845242bb5 100644 (file)
@@ -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.
 
 /**
  * \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
index 5c5a2eed992206689999c1e84a07c767ded674c6..1c716c9712493c88f2c862c8e98a53d991d090e7 100644 (file)
 
 /**
  * \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
index 0ecfaa49297882abb228c93645512a5f233cf1cd..fe22f8e3cba394ea81acd377432cfd30ad3078dd 100644 (file)
@@ -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
 
index ede234c34f4c296738e3da6ab1a8c8049b6853d6..2ea379c8c8c7bb0358b345339c23df4ae26ec210 100644 (file)
@@ -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);
 }
index 9b87d69b25420b03798c027adad670524a1ff65f..c894631950c2ebfe44dcf6b81a30ac92201c48d1 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <cfg/module.h>
 #include <kern/proc_p.h>
+#include <kern/proc.h>
 
 #include <cfg/cfg_kern.h>
 
@@ -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
 }
 
index 95ffbea093234e74834f5067f174fa3b90bfc956..f285d43f5a53c3e3932f3d1d5edca9be072a26d2 100644 (file)
@@ -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;
        }
 
index c3d89b4315d499048b1a859e044dd7c2b6f61305..b49c87f3e0eb666cbf94170b103d6b836ebfb7f5 100644 (file)
 
 #include <string.h>           /* 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
  */
index db681ede2c828535dafad80376004d74f32552b2..8a18bf7447c8fcc623cddefccfb89734ea82c704 100644 (file)
@@ -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.
  *
index 0d6a94f153eed4102f2257defa18ed4f36eff9ce..2c914d9e81698d2645507800c406a205407a412b 100644 (file)
 
 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);