=================================================================== RCS file: /cvs/funnyos/kern/kern_sched.c,v retrieving revision 1.1 retrieving revision 1.3 diff -u -r1.1 -r1.3 --- funnyos/kern/kern_sched.c 2007/11/19 15:54:33 1.1 +++ funnyos/kern/kern_sched.c 2007/11/23 13:37:43 1.3 @@ -1,9 +1,244 @@ /* - * $Id: kern_sched.c,v 1.1 2007/11/19 15:54:33 nbrk Exp $ + * $Id: kern_sched.c,v 1.3 2007/11/23 13:37:43 nbrk Exp $ */ #include #include +#include /* for HZ */ +#include #include +/* #define SCHED_DEBUG */ +/* #define SCHED_REGDEBUG */ + +#ifdef SCHED_DEBUG +#define DPRINTF(x...) do { printf(x); } while (0) +#else +#define DPRINTF(x...) { } +#endif + +#ifdef SCHED_REGDEBUG +#define DRPRINTF(x...) do { printf(x); } while (0) +#else +#define DRPRINTF(x...) { } +#endif + + +/* config.c gives us tasks that we'll schedule */ +extern struct u_task config_tasklist[]; + +/* list of k_tasks */ +struct k_task *ktasklist; + +/* current running task */ +struct k_task *curktask; + +/* pcb of running task; we will save context there when enter irq_mode */ +struct pcb *curpcb; + +/* interrupt frame */ +extern struct pcb *iframep; + +/* total tasks; used to TID generation */ +uint8_t ntasks; + +/* "idle" task exists forever and occupy cpu when there is no other task pretending. */ +const struct u_task idle_utask = {"idle", 0, NULL}; + + +void +sched_init(void) +{ + /* + * Create struct k_task for each u_task that user described in config_tasklist. + */ + struct u_task *utaskp; + struct k_task *ktaskp, *oldktaskp; + + ntasks = 0; + + /* + * Create an "idle" task which always has TID 0. + */ + ktaskp = kmalloc(sizeof(struct k_task)); + + if (ktaskp == NULL) + panic("can't allocate memory for idle task\n"); + + /* link u_task for idle task */ + ktaskp->kt_utask = (struct u_task *)&idle_utask; + + /* TID (always 0) */ + ktaskp->kt_tid = 0; + + /* idle task is always in state READY (or RUNNING, if on processor now) */ + ktaskp->kt_state = TASK_READY; + + /* next task in list isn't up yet (and prev too) */ + ktaskp->kt_next = NULL; + + /* make "idle" task first task in ktasklist, system k_task list */ + ktasklist = ktaskp; + + /* bump ntasks to 1 */ + ntasks = 1; + + /* preserve pointer to this k_task so we can link-in next task */ + oldktaskp = ktaskp; + + /* + * Idle task set up completed. + * Configure all other system tasks, + */ + + /* look through tasklist */ + utaskp = config_tasklist; + while(utaskp->ut_name != NULL) { + + /* try to allocate memory for ktask */ + ktaskp = kmalloc(sizeof(struct k_task)); + + if (ktaskp == NULL) + panic("can't allocate memory for task '%s'\n", utaskp->ut_name); + + /* + * Successfully allocated new ktask. + */ + + /* link u_task */ + ktaskp->kt_utask = utaskp; + + /* set TID (Task Identificator) */ + ktaskp->kt_tid = oldktaskp->kt_tid + 1; + + /* state */ + ktaskp->kt_state = TASK_READY; + + /* set intitial entry point (initial pc) to task_enter */ + ktaskp->kt_pcb.p_pc = (uint32_t)ktaskp->kt_utask->ut_enter; + + /* link current task in previous task's structure */ + oldktaskp->kt_next = ktaskp; + + /* NULLify kt_next of current task */ + ktaskp->kt_next = NULL; + + /* save current ktask for use with next ktask */ + oldktaskp = ktaskp; + + /* bump ntasks */ + ntasks++; + + /* shift to next element in config_tasklist[] */ + utaskp++; + } + + /* make this list circularly linked (e.g point list's last->next node into first) */ + ktaskp->kt_next = ktasklist; + + DPRINTF("kern_sched: created %d tasks:", ntasks); + + /* print tasks' names */ + ktaskp = ktasklist + 1; /* skip (first) "idle" task (display it as the end of circularly list) */ + do { + DPRINTF(" %s", ktaskp->kt_utask->ut_name); + + if (ktaskp->kt_tid == NULL) /* that was an "idle" task */ + break; + + ktaskp = ktaskp->kt_next; + } while(1); + + DPRINTF("; HZ=%d\n", HZ); + + /* + * Run "idle" task in NOSCHED, so it will not schedule after first context siwtch; + */ + ktasklist->kt_state = TASK_NOSCHED; + curktask = ktasklist; /* ktasklist always points to "idle" task */ + + /* point curpcb */ + curpcb = &ktasklist->kt_pcb; +} + + +void +sched_tick(void) +{ + /* + * Schedule next task that will occupy cpu (if any). + * Remember that we are in IRQ_mode here. + */ + + /* + * All we need to do now is: + * - see if context switch is required + * - if so, save iframe into curpcb (save hardware context) + * - select next task to run + * - point curpcb to pcb of new task + * - point curktask to k_task of new task + * - copy curpcb into iframep (so we'll continue in another task when we exit irq_mode) + * - if context switch is not required + * - XXX we will not copy curpcb into iframep? (cause we end up in same task at next irq) + * - anyway, account time, etc.. + */ + + /* XXX use pre-emtive multitasking to simplify things for now! */ + + /* save hardware state of interrupted task */ + *curpcb = *iframep; + + /* "suspend" interrupted task */ + if(curktask->kt_state == TASK_RUNNING) /* XXX ugly hack to skip "idle" which is NOSCHED */ + curktask->kt_state = TASK_READY; + + DPRINTF("sched_tick: task tid=%d (\"%s\") suspended\n", curktask->kt_tid, curktask->kt_utask->ut_name); + DRPRINTF("r0=0x%x\n", iframep->p_r0); + DRPRINTF("r1=0x%x\n", iframep->p_r1); + DRPRINTF("r2=0x%x\n", iframep->p_r2); + DRPRINTF("r3=0x%x\n", iframep->p_r3); + DRPRINTF("r4=0x%x\n", iframep->p_r4); + DRPRINTF("r5=0x%x\n", iframep->p_r5); + DRPRINTF("r6=0x%x\n", iframep->p_r6); + DRPRINTF("r7=0x%x\n", iframep->p_r7); + DRPRINTF("r8=0x%x\n", iframep->p_r8); + DRPRINTF("r9=0x%x\n", iframep->p_r9); + DRPRINTF("r10=0x%x\n", iframep->p_r10); + DRPRINTF("r11=0x%x\n", iframep->p_r11); + DRPRINTF("r12=0x%x\n", iframep->p_r12); + DRPRINTF("pc=0x%x\n", iframep->p_pc); + + /* round-robin select next task in circlelist */ + curktask = curktask->kt_next; + + /* look for next ready task */ + while(curktask->kt_state != TASK_READY) + curktask = curktask->kt_next; + + /* run selected task */ + curktask->kt_state = TASK_RUNNING; + + /* point curpcb into selected task's pcb */ + curpcb = &curktask->kt_pcb; + + /* restore selected task's hardware context into an IRQ stack */ + *iframep = *curpcb; + + DPRINTF("sched_tick: task tid=%d (\"%s\") resumed\n", curktask->kt_tid, curktask->kt_utask->ut_name); + DRPRINTF("r0=0x%x\n", iframep->p_r0); + DRPRINTF("r1=0x%x\n", iframep->p_r1); + DRPRINTF("r2=0x%x\n", iframep->p_r2); + DRPRINTF("r3=0x%x\n", iframep->p_r3); + DRPRINTF("r4=0x%x\n", iframep->p_r4); + DRPRINTF("r5=0x%x\n", iframep->p_r5); + DRPRINTF("r6=0x%x\n", iframep->p_r6); + DRPRINTF("r7=0x%x\n", iframep->p_r7); + DRPRINTF("r8=0x%x\n", iframep->p_r8); + DRPRINTF("r9=0x%x\n", iframep->p_r9); + DRPRINTF("r10=0x%x\n", iframep->p_r10); + DRPRINTF("r11=0x%x\n", iframep->p_r11); + DRPRINTF("r12=0x%x\n", iframep->p_r12); + DRPRINTF("pc=0x%x\n", iframep->p_pc); + +}