Initial (nonworking) draft of preemptive task switching
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Wed, 13 Aug 2008 14:53:53 +0000 (14:53 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Wed, 13 Aug 2008 14:53:53 +0000 (14:53 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@1639 38d2e660-2303-0410-9eaa-f027e97ec537

app/demo/cfg/cfg_kern.h
app/demo/demo.mk
bertos/cfg/cfg_kern.h
bertos/drv/timer.c
bertos/kern/preempt.c
bertos/kern/proc.c
bertos/kern/proc_p.h

index 91a67cea2bb2e58a7a54af9bb81fd8e441938e8d..8dbd6608bb0f40cf27b0bdc16c63cb3965161231 100644 (file)
@@ -26,8 +26,8 @@
  * 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 Bernie Innocenti <bernie@codewiz.org>
+ * Copyright 2001, 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999, 2000, 2001, 2008 Bernie Innocenti <bernie@codewiz.org>
  * -->
  *
  * \brief Kernel configuration parameters
 #include "cfg/cfg_arch.h"  /* ARCH_EMUL */
 
 /**
- * Multithreading kernel.
+ * Enable the multithreading kernel.
  */
 #define CONFIG_KERNEL 1
 
 /**
- * \name Modules activation
+ * \name Optional kernel features
  *
  * \{
  */
 /*\}*/
 
 /* EXPERIMENTAL */
-#define CONFIG_KERN_PREEMPTIVE  (0    && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER)
+#define CONFIG_KERN_PREEMPT     (1    && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER)
+
+/* OBSOLETE */
+#define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT
 
 /// Time sharing quantum in timer ticks.
 #define CONFIG_KERN_QUANTUM     50
index 20eb2b4eda1d19d3febcdd85b3c475861551382b..941e28a6b76e911a37f9463d894e635e7229e39c 100644 (file)
@@ -51,9 +51,9 @@ demo_CSRC = \
        bertos/mware/observer.c \
        bertos/mware/resource.c \
        bertos/mware/sprintf.c \
-       bertos/kern/coop.c \
        bertos/kern/proc.c \
        bertos/kern/proc_test.c \
+       bertos/kern/preempt.c \
        bertos/kern/sem.c \
        bertos/kern/signal.c \
        bertos/kern/monitor.c \
index f11c2bcc8234d1dfea6cdb7295a8038a3e721530..f54d0f7ed0300c8dd0fa5bd07b31ad60110577ff 100644 (file)
 #include "cfg/cfg_arch.h"  /* ARCH_EMUL */
 
 /**
- * Multithreading kernel.
+ * Enable the multithreading kernel.
  */
 #define CONFIG_KERNEL 0
 
 /**
- * \name Modules activation
+ * \name Optional kernel features
  *
  * \{
  */
 /*\}*/
 
 /* EXPERIMENTAL */
-#define CONFIG_KERN_PREEMPTIVE  (0    && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER)
+#define CONFIG_KERN_PREEMPT     (0    && CONFIG_KERN_SCHED && CONFIG_KERN_TIMER)
+
+/* OBSOLETE */
+#define CONFIG_KERN_PREEMPTIVE CONFIG_KERN_PREEMPT
 
 /// Time sharing quantum in timer ticks.
 #define CONFIG_KERN_QUANTUM     50
index 333d6cd83282ed7886b728b43c68861cbeeb697d..0d78d198aaa3a6bb5690bab53f2ad59e49acb80f 100644 (file)
@@ -74,9 +74,6 @@
 #endif
 
 #if CONFIG_KERNEL
-       #if CONFIG_KERN_PREEMPTIVE
-               #include <hw/switch.h>
-       #endif
        #if CONFIG_KERN_SIGNALS
                #include <kern/signal.h> /* sig_wait(), sig_check() */
                #include <kern/proc.h>   /* proc_current() */
index f068a8a82c24d314d159e84a045422de18b55475..0cbaf7c902dd2d65a03015cecf2b15804853f17e 100644 (file)
 #include "proc_p.h"
 #include "proc.h"
 
+#include <cpu/frame.h> // CPU_IDLE
+
+#include <unistd.h> // XXX alarm()
+
 
 /*
  * The time sharing scheduler forces a task switch when the current
@@ -78,3 +82,105 @@ 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));
+
+       IRQ_DISABLE;
+       /* Poll on the ready queue for the first ready process */
+       while (!(CurrentProcess = (struct Process *)list_remHead(&ProcReadyList)))
+       {
+               /*
+                * 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;
+               CPU_IDLE;
+               MEMORY_BARRIER;
+               IRQ_DISABLE;
+       }
+       IRQ_ENABLE;
+}
+
+void proc_preempt_timer(void)
+{
+       // TODO: check Quantum
+
+       alarm(1);
+       ATOMIC(SCHED_ENQUEUE(CurrentProcess));
+       proc_schedule();
+}
+
+void proc_schedule(void)
+{
+       kill(0, SIGUSR1);
+}
+
+void proc_yield(void)
+{
+       ATOMIC(SCHED_ENQUEUE(CurrentProcess));
+
+       proc_schedule();
+}
+
+/* signal handler */
+void irq_entry(int signum)
+{
+       Process *old_process;
+
+       TRACEMSG("storing %p:%s", CurrentProcess, CurrentProcess->monitor.name);
+       CurrentProcess->leaving = false;
+       getcontext(&CurrentProcess->context);
+       /* We get here in two ways: directly, and after setcontext() below */
+
+       if (CurrentProcess->leaving)
+       {
+               TRACEMSG("leaving to %p:%s", CurrentProcess, CurrentProcess->monitor.name);
+               return;
+       }
+
+       old_process = CurrentProcess;
+
+       irq_handlers[signum]();
+
+       if (old_process != CurrentProcess)
+       {
+               TRACEMSG("launching %p:%s", CurrentProcess, CurrentProcess->monitor.name);
+               CurrentProcess->leaving = true;
+               setcontext(&CurrentProcess->context);
+               /* not reached */
+       }
+
+       TRACEMSG("keeping %p:%s", CurrentProcess, CurrentProcess->monitor.name);
+}
+
+void preempt_init(void)
+{
+       struct sigaction act;
+       act.sa_handler = irq_entry;
+       sigemptyset(&act.sa_mask);
+       sigaddset(&act.sa_mask, SIGUSR1);
+       sigaddset(&act.sa_mask, SIGALRM);
+       act.sa_flags = SA_RESTART; /* | SA_SIGINFO; */
+
+       irq_handlers[SIGUSR1] = proc_preempt;
+       irq_handlers[SIGALRM] = proc_preempt_timer;
+       sigaction(SIGUSR1, &act, NULL);
+       sigaction(SIGALRM, &act, NULL);
+
+       alarm(1);
+}
index 9aa04546c35eb02e5ee425f02914a5c7839a68cb..bce8ac3e8a7fcadfd4eaf4d7073c659bf0813ff6 100644 (file)
@@ -26,9 +26,8 @@
  * 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 Bernie Innocenti <bernie@codewiz.org>
- *
+ * Copyright 2001, 2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 1999, 2000, 2001, 2008 Bernie Innocenti <bernie@codewiz.org>
  * -->
  *
  * \brief Simple realtime multitasking scheduler.
@@ -43,6 +42,7 @@
 #include "proc.h"
 
 #include "cfg/cfg_arch.h"  /* ARCH_EMUL */
+#include "cfg/cfg_kern.h"
 #include <cfg/module.h>
 
 #include <cpu/irq.h>
 
 #include <string.h>           /* memset() */
 
+#if CONFIG_KERN_PREEMPT
+#include "preempt.h"
+#endif
+
 /*
  * The scheduer tracks ready processes by enqueuing them in the
  * ready list.
@@ -117,6 +121,10 @@ void proc_init(void)
        monitor_add(CurrentProcess, "main");
 #endif
 
+#if CONFIG_KERN_PREEMPTIVE
+       preempt_init();
+#endif
+
        MOD_INIT(proc);
 }
 
@@ -164,8 +172,7 @@ struct Process *proc_new_with_name(UNUSED(const char *, name), void (*entry)(voi
 
 #if CONFIG_KERN_MONITOR
        /* Fill-in the stack with a special marker to help debugging */
-#warning size incorrect
-       memset(stack_base, CONFIG_KERN_STACKFILLCODE, stack_size / sizeof(cpustack_t));
+       memset(stack_base, CONFIG_KERN_STACKFILLCODE, stack_size);
 #endif
 
        /* Initialize the process control block */
index 54ba7be187014ac3527c169b8aea1ce735e1dce8..a98f9428aa65f684ad414c4f2a0267c67f0547a1 100644 (file)
 
 #include <struct/list.h>
 
+#if CONFIG_KERN_PREEMPTIVE
+       #include <ucontext.h> // XXX
+#endif
+
 typedef struct Process
 {
        Node         link;        /**< Link Process into scheduler lists */
@@ -60,6 +64,8 @@ typedef struct Process
 
 #if CONFIG_KERN_PREEMPTIVE
        int          forbid_cnt;  /**< Nesting count for proc_forbid()/proc_permit(). */
+       bool         leaving;     /**< XXX: maybe global? */
+       ucontext_t   context;
 #endif
 
 #if CONFIG_KERN_HEAP