/** * schedule.c * * Task creation and scheduling * * Exports: * task_t *_current_task; * schedule(); * init_tasks(); * * Imports: * main.c printf(); * video.c console_t _vc[]; */ #include <setjmp.h> /* setjmp(), longjmp() */ #include <string.h> #include "_krnl.h" /* console_t */ #include "bootlog.h" /* klog() */ /** * Imports */ void printf(const char *fmt, ...); extern console_t _vc[]; void task1(void); void task2(void); void task3(void); void task4(void); #define MAX_TASK 16 #define USER_STACK_SIZE 512 /** * jmp_buf (E)IP and (E)SP register names for various environments */ /** * Tinylib (default) * These should work for most compilers - The HybOS * compiler (modified gcc) uses this as the default. * Your mileage may vary. */ #define JMPBUF_IP eip #define JMPBUF_SP esp #define JMPBUF_FLAGS eflags #if 0 /** * TurboC * * These should work with all versions of TurboC's * compiler. */ #define JMPBUF_IP j_ip #define JMPBUF_SP j_sp #define JMPBUF_FLAGS j_flag /** * DJGPP * * These should work with the DJGPP compiler */ #define JMPBUF_IP __eip #define JMPBUF_SP __esp #define JMPBUF_FLAGS __eflags #define JMPBUF_IP __pc #define JMPBUF_SP __sp #define JMPBUF_FLAGS ???????? /** * glibc5 * * I have no idea what the register name is * for JMPBUF_FLAGS. Good luck. */ #define JMPBUF_IP eip #define JMPBUF_SP esp #define JMPBUF_FLAGS eflags #endif /* 0 */ task_t *_curr_task; static task_t _tasks[MAX_TASK]; /** * schedule() * */ void schedule(void) { static unsigned current; /** * If setjmp() returns non-zero it means that we came here through * hyperspace from our call to longjmp() below, so just return */ /** UBU if(setjmp(_curr_task->state) != 0) return; **/ /** * Try to find the next runnable task */ do { current++; if(current >= MAX_TASK) current = 0; _curr_task = _tasks + current; } while(_curr_task->status != TS_RUNNABLE); /** * Jump to the new task */ longjmp(_curr_task->state, 1); } /***************************************************************************** *****************************************************************************/ #define NUM_TASKS 0 /** * init_tasks() * */ void init_tasks(void) { static unsigned char stacks[NUM_TASKS][USER_STACK_SIZE]; /*static unsigned entry[NUM_TASKS] = { 0, (unsigned)task1, (unsigned)task2, (unsigned)task3, (unsigned)task4 };*/ static unsigned entry[NUM_TASKS]; unsigned adr, i; klog("init", "task handler", K_KLOG_PENDING, &_vc[0]); /** * For user taskes, initialize the saved state */ for(i = 1; i < NUM_TASKS; i++) { (void)setjmp(_tasks[i].state); /** * especially the stack pointer */ adr = (unsigned)(stacks[i] + USER_STACK_SIZE); _tasks[i].state[0].JMPBUF_SP = adr; /** * and program counter */ _tasks[i].state[0].JMPBUF_IP = entry[i]; /** * enable interrupts (by setting EFLAGS value) */ _tasks[i].state[0].JMPBUF_FLAGS = 0x200; /** * allocate a virtual console to this task */ _tasks[i].vc = _vc + i; /** * and mark it as runnable */ _tasks[i].status = TS_RUNNABLE; } /** * mark task 0 runnable (idle task) */ _tasks[0].status = TS_RUNNABLE; /** * set _curr_task so schedule() will save state * of task 0 */ _curr_task = _tasks + 0; klog(NULL, NULL, K_KLOG_SUCCESS, &_vc[0]); }