A Small Cooperative Multitasking Kernel

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Ivop
Date:
Sun Jul 24 17:15:42 2011 +0000
Commit message:
first release

Changed in this revision

fastlib.lib Show annotated file Show diff for this revision Revisions of this file
kernel.c Show annotated file Show diff for this revision Revisions of this file
kernel.h Show annotated file Show diff for this revision Revisions of this file
main.c Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
tasks-printf-c.h Show annotated file Show diff for this revision Revisions of this file
tasks.c Show annotated file Show diff for this revision Revisions of this file
timer-mbed.c Show annotated file Show diff for this revision Revisions of this file
timer-unix-c.h Show annotated file Show diff for this revision Revisions of this file
timer.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 73b89fc74e9f fastlib.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fastlib.lib	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/Ivop/code/fastlib/#bc492a93e116
diff -r 000000000000 -r 73b89fc74e9f kernel.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel.c	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,59 @@
+/* Opus Una - A Small Cooperative Multitasking Kernel in C
+ *
+ * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl>
+ * This file is licensed under the terms of the GNU Lesser
+ * General Public License, version 3.
+ */
+
+#include "kernel.h"
+#include "timer.h"
+
+void *ou_state;
+unsigned ou_wait, ou_current_task, ou_ticks;
+
+void ou_update_tasks(void) {
+    unsigned i;
+    for (i=0; i<ou_ntasks; i++)
+        if (ou_tasks[i].wait)
+            ou_tasks[i].wait--;
+}
+
+void ou_scheduler(void) {
+    unsigned i, priority, delayed;
+
+    for(;;) {
+        ou_current_task = priority = -1U;
+        delayed = 0;
+        for (i=0; i<ou_ntasks; i++) {
+            if (ou_tasks[i].wait)                continue;      // task is still waiting
+            if (ou_tasks[i].suspended)           continue;      // task is suspended
+            if (ou_tasks[i].priority > priority) continue;      // task has lower priority
+
+            if (ou_tasks[i].priority < priority)
+                goto found_better_candidate;        // higher priority
+            if (ou_tasks[i].delayed > delayed)
+                goto found_better_candidate;        // equal priority, but waited longer
+
+            ou_tasks[i].delayed++;                  // equal priority, but waited shorter
+            continue;
+
+found_better_candidate:
+            if (ou_current_task != -1U)
+                ou_tasks[ou_current_task].delayed++; // previous candidate is worse
+            priority        = ou_tasks[i].priority;
+            delayed         = ou_tasks[i].delayed;
+            ou_current_task = i;
+        }
+        if (ou_current_task == -1U) {      // no runnable task, all are waiting or suspended
+            ou_idle();
+            continue;
+        }
+
+        ou_state = ou_tasks[ou_current_task].state;
+
+        ou_tasks[ou_current_task].function();   // run!
+
+        ou_tasks[ou_current_task].state = ou_state;     // returned values
+        ou_tasks[ou_current_task].wait  = ou_wait;      // ...
+    }
+}
\ No newline at end of file
diff -r 000000000000 -r 73b89fc74e9f kernel.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel.h	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,59 @@
+/* Opus Una - A Small Cooperative Multitasking Kernel in C
+ *
+ * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl>
+ * This file is licensed under the terms of the GNU Lesser
+ * General Public License, version 3.
+ */
+
+#ifndef OU_KERNEL_H
+#define OU_KERNEL_H
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define OU_VERSION      1
+
+#define OU_CONCAT2(x,y) x##y
+#define OU_CONCAT(x,y)  OU_CONCAT2(x,y)
+
+#define OU_TASK(name) static void name(void) { if(ou_state) goto *ou_state; {
+#define OU_ENDTASK    OU_SUSPEND; ou_wait=0; }}
+
+#define OU_WAIT(ticks) { ou_wait = ticks; ou_state = &&OU_CONCAT(L,__LINE__); return; } \
+    OU_CONCAT(L,__LINE__):
+
+#define OU_YIELD    do{ OU_WAIT(0); }while(0)
+#define OU_SUSPEND  do{ ou_tasks[ou_current_task].suspended = 1; OU_WAIT(0); }while(0)
+#define OU_START(t) do{ ou_tasks[t].suspended = 0; OU_WAIT(0); }while(0)
+
+#define OU_GET_TASK_PRIORITY(t)     ou_tasks[t].priority
+#define OU_SET_TASK_PRIORITY(t,p)   ou_tasks[t].priority = p
+
+#define OU_GET_MY_PRIORITY()        OU_GET_TASK_PRIORITY(ou_current_task)
+#define OU_SET_MY_PRIORITY(p)       OU_SET_TASK_PRIORITY(ou_current_task,p)
+
+// Note: Locks only work between tasks, NOT between tasks and interrupt handlers.
+// For that, we need a full-blown mutex
+
+#define OU_LOCK(i)      while(!i) OU_WAIT(1); i=1
+#define OU_UNLOCK(i)    i=0
+
+struct ou_task {
+    void (*function)(void);             // entry point of task
+    volatile unsigned priority,         // 0 is highest, UINT_MAX-1 is lowest
+                      suspended,        // task is suspended (=1)
+                      wait;             // ticks to wait before running again
+    unsigned delayed;                   // # of times scheduling was delayed
+    void *state;                        // current state within function
+};
+
+void ou_update_tasks(void);             // called from timer interrupt
+void ou_scheduler(void);                // main loop
+
+extern struct ou_task ou_tasks[];
+extern void *ou_state;
+extern unsigned ou_wait, ou_current_task, ou_ticks;
+extern const unsigned ou_ntasks;
+
+#endif
diff -r 000000000000 -r 73b89fc74e9f main.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.c	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,10 @@
+#include "kernel.h"
+#include "timer.h"
+#include <stdio.h>
+
+int main(int argc, char **argv) {
+    printf("Opus Una (Working Together) - Version %i\r\n", OU_VERSION);
+    ou_start_timer();
+    ou_scheduler();
+    return 0;
+}
\ No newline at end of file
diff -r 000000000000 -r 73b89fc74e9f mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/63bcd7ba4912
diff -r 000000000000 -r 73b89fc74e9f tasks-printf-c.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tasks-printf-c.h	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,32 @@
+#include "kernel.h"
+#include <stdio.h>
+
+static void task_zero(void);
+static void task_one(void);
+
+struct ou_task ou_tasks[] = {
+    { task_zero, 2, 0, 0, 0, NULL },
+    { task_one,  1, 0, 0, 0, NULL }
+};
+
+const unsigned ou_ntasks = sizeof(ou_tasks)/sizeof(struct ou_task);
+
+OU_TASK(task_zero)
+    OU_WAIT(100);
+    printf("hello\r\n");
+    OU_WAIT(100);
+    printf("world\r\n");
+OU_ENDTASK
+
+OU_TASK(task_one)
+    OU_WAIT(100);
+    printf("goodbye\r\n");
+    OU_WAIT(100);
+    printf("cruel\r\n");
+    OU_WAIT(100);
+    printf("world...\r\n");
+    for(;;) {
+        OU_WAIT(50);
+        printf("loop\r\n");
+    }
+OU_ENDTASK
\ No newline at end of file
diff -r 000000000000 -r 73b89fc74e9f tasks.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tasks.c	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,59 @@
+#include "kernel.h"
+#include <mbed.h>
+
+static void task_zero(void);
+static void task_one(void);
+static void task_two(void);
+static void task_three(void);
+
+struct ou_task ou_tasks[] = {
+    { task_zero,  2, 0, 0, 0, NULL },
+    { task_one,   1, 0, 0, 0, NULL },
+    { task_two,   5, 0, 0, 0, NULL },
+    { task_three, 5, 0, 0, 0, NULL }
+};
+
+const unsigned ou_ntasks = sizeof(ou_tasks)/sizeof(struct ou_task);
+
+
+OU_TASK(task_zero)
+    static DigitalOut led(LED1);
+
+    OU_WAIT(100);
+    led = 1;
+    OU_WAIT(100);
+    led = 0;
+OU_ENDTASK
+
+OU_TASK(task_one)
+    static DigitalOut led(LED2);
+
+    OU_WAIT(100);
+    led = 1;
+    OU_WAIT(100);
+    led = 0;
+    OU_WAIT(100);
+    led = 1;
+    for(;;) {
+        OU_WAIT(50);
+        led = 0;
+        OU_WAIT(50);
+        led = 1;
+    }
+OU_ENDTASK
+
+OU_TASK(task_two)
+    static DigitalOut led(LED3);
+    for(;;) {
+        OU_WAIT(100);
+        led = !led;
+    }
+OU_ENDTASK
+
+OU_TASK(task_three)
+    static DigitalOut led(LED4);
+    for(;;) {
+        OU_WAIT(20);
+        led = !led;
+    }
+OU_ENDTASK
diff -r 000000000000 -r 73b89fc74e9f timer-mbed.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/timer-mbed.c	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,24 @@
+/* Opus Una - A Small Cooperative Multitasking Kernel in C
+ *
+ * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl>
+ * This file is licensed under the terms of the GNU Lesser
+ * General Public License, version 3.
+ */
+
+#include "timer.h"
+#include "kernel.h"
+#include "fastlib/systick.h"
+
+extern "C" void SysTick_Handler(void) __irq {
+    ou_ticks++;
+    ou_update_tasks();
+}
+
+void ou_start_timer(void) {
+    fl_systick_set_reload_value((96000000/100)-1);          // 1/100th of a second (10ms)
+    fl_systick_control(FL_ENABLE, FL_ENABLE, FL_ENABLE);    // timer, irq, use cclk 
+}
+
+void ou_idle(void) {
+    // save power/cpu time/et cetera...
+}
diff -r 000000000000 -r 73b89fc74e9f timer-unix-c.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/timer-unix-c.h	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,41 @@
+/* Opus Una - A Small Cooperative Multitasking Kernel in C
+ *
+ * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl>
+ * This file is licensed under the terms of the GNU Lesser
+ * General Public License, version 3.
+ */
+
+/* Run the kernel as a process on Unix */
+
+#include "timer.h"
+#include "kernel.h"
+
+#include <sys/time.h>
+#include <signal.h>
+#include <string.h>
+#include <unistd.h>
+
+static void timer_sr(int x) {
+    ou_ticks++;
+    ou_update_tasks();
+}
+
+void ou_start_timer(void) {
+    struct itimerval val;
+    struct sigaction act;
+
+    memset(&act, 0, sizeof(act));
+
+    act.sa_handler = timer_sr;
+    sigaction(SIGALRM, &act, NULL);     // signal() is not portable
+
+    val.it_interval.tv_usec = 10000;    // 10ms
+    val.it_interval.tv_sec = 0;
+    val.it_value.tv_usec = 10000;       // 10ms
+    val.it_value.tv_sec = 0; 
+    setitimer(ITIMER_REAL, &val, NULL);
+}
+
+void ou_idle(void) {
+    usleep(5);                  // save power/cpu time/et cetera...
+}
diff -r 000000000000 -r 73b89fc74e9f timer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/timer.h	Sun Jul 24 17:15:42 2011 +0000
@@ -0,0 +1,14 @@
+/* Opus Una - A Small Cooperative Multitasking Kernel in C
+ *
+ * Copyright (C) 2011 by Ivo van Poorten <ivop@euronet.nl>
+ * This file is licensed under the terms of the GNU Lesser
+ * General Public License, version 3.
+ */
+
+#ifndef OU_TIMER_H
+#define OU_TIMER_H
+
+void ou_start_timer(void);
+void ou_idle(void);
+
+#endif