Ivo van Poorten
/
opus-una
A Small Cooperative Multitasking Kernel
Revision 0:73b89fc74e9f, committed 2011-07-24
- Comitter:
- Ivop
- Date:
- Sun Jul 24 17:15:42 2011 +0000
- Commit message:
- first release
Changed in this revision
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