version 1.2, 2007/11/20 16:07:24 |
version 1.3, 2007/11/23 13:37:43 |
|
|
|
|
#include <libkern/printf.h> |
#include <libkern/printf.h> |
|
|
|
/* #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 */ |
/* config.c gives us tasks that we'll schedule */ |
extern struct u_task config_tasklist[]; |
extern struct u_task config_tasklist[]; |
|
|
/* list of k_tasks */ |
/* list of k_tasks */ |
struct k_task *ktasklist; |
struct k_task *ktasklist; |
|
|
|
/* current running task */ |
|
struct k_task *curktask; |
|
|
/* pcb of running task; we will save context there when enter irq_mode */ |
/* pcb of running task; we will save context there when enter irq_mode */ |
uint32_t *curpcb; |
struct pcb *curpcb; |
|
|
|
/* interrupt frame */ |
|
extern struct pcb *iframep; |
|
|
/* total tasks; used to TID generation */ |
/* total tasks; used to TID generation */ |
uint8_t ntasks; |
uint8_t ntasks; |
|
|
|
|
/* state */ |
/* state */ |
ktaskp->kt_state = TASK_READY; |
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 */ |
/* link current task in previous task's structure */ |
oldktaskp->kt_next = ktaskp; |
oldktaskp->kt_next = ktaskp; |
|
|
|
|
/* make this list circularly linked (e.g point list's last->next node into first) */ |
/* make this list circularly linked (e.g point list's last->next node into first) */ |
ktaskp->kt_next = ktasklist; |
ktaskp->kt_next = ktasklist; |
|
|
printf("kern_sched: created %d tasks:", ntasks); |
DPRINTF("kern_sched: created %d tasks:", ntasks); |
|
|
/* print tasks' names */ |
/* print tasks' names */ |
ktaskp = ktasklist + 1; /* skip (first) "idle" task (display it as the end of circularly list) */ |
ktaskp = ktasklist + 1; /* skip (first) "idle" task (display it as the end of circularly list) */ |
do { |
do { |
printf(" %s", ktaskp->kt_utask->ut_name); |
DPRINTF(" %s", ktaskp->kt_utask->ut_name); |
|
|
if (ktaskp->kt_tid == NULL) /* that was an "idle" task */ |
if (ktaskp->kt_tid == NULL) /* that was an "idle" task */ |
break; |
break; |
|
|
ktaskp = ktaskp->kt_next; |
ktaskp = ktaskp->kt_next; |
} while(1); |
} while(1); |
|
|
printf("; HZ=%d\n", HZ); |
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); |
|
|
} |
} |
|
|