diff -u -r ../legOS-0.1.7/include/tm.h ./include/tm.h --- ../legOS-0.1.7/include/tm.h Fri Mar 19 11:34:55 1999 +++ ./include/tm.h Sun Mar 21 13:10:35 1999 @@ -54,6 +54,22 @@ #define DEFAULT_STACK_SIZE 1024 //!< 1k stack has to suffice. +//! +/* priority chain data structure +*/ + +struct _priority_chain { + priority_t priority; // numeric priority level + struct _priority_chain *prev; // higher priority chain + struct _priority_chain *next; // lower priority chain + struct _process_data *cpid; // current process in chain +}; + +//! priority chain data type +/*! a shorthand +*/ +typedef struct _priority_chain priority_chain; + //! process data structure /* */ @@ -61,7 +77,7 @@ size_t *sp_save; //!< saved stack pointer pstate_t pstate; //!< process state - priority_t priority; //!< process priority + struct _priority_chain *priority; //!< priority chain struct _process_data *next; //!< next process in queue struct _process_data *prev; //!< previous process in queue diff -u -r ../legOS-0.1.7/kmain.c ./kmain.c --- ../legOS-0.1.7/kmain.c Fri Mar 19 11:34:55 1999 +++ ./kmain.c Fri Mar 19 21:43:42 1999 @@ -84,10 +84,6 @@ mm_init(); #endif -#ifndef NO_TASK_MANAGEMENT - tm_init(); -#endif - #ifndef NO_DIRECT_IR dir_init(); #endif @@ -119,6 +115,10 @@ do { buttons=button_state(); if(PRESSED(buttons,BUTTON_RUN)) { +#ifndef NO_TASK_MANAGEMENT + tm_init(); +#endif + #ifndef NO_DIRECT_SENSOR ds_init(); #endif diff -u -r ../legOS-0.1.7/tm.c ./tm.c --- ../legOS-0.1.7/tm.c Fri Mar 19 11:34:55 1999 +++ ./tm.c Fri Mar 19 22:02:06 1999 @@ -53,6 +53,8 @@ process_data *cpid=&pd_single; //!< ptr to current process data +priority_chain *priority_head; //!< head of priority chain + process_data *pd_idle; //!< idle proces unsigned nb_tasks; //!< number of tasks @@ -111,13 +113,11 @@ */ size_t *tm_scheduler(size_t *old_sp) { process_data *next; // next process to execute -#ifndef NO_EQUAL_PRIORITIES - process_data *insert; // helper variable -#endif + priority_chain *priority; wakeup_t tmp; #ifndef NO_TASK_VISUALIZATION - static unsigned sequence=0; + static unsigned char sequence=0; if(cpid!=pd_idle) { sequence++; // yeah we're running @@ -132,11 +132,27 @@ } #endif // NO_TASK_VISUALIZATION + priority=cpid->priority; switch(cpid->pstate) { case P_ZOMBIE: // did this one finish? - cpid->prev->next = cpid->next; // remove from - cpid->next->prev = cpid->prev; // queue - + // remove from queue + if(cpid->next!=cpid) + { + // simply unlink the process + priority->cpid = + cpid->next->prev = cpid->prev; + cpid->prev->next = cpid->next; + } else { + // priority chain is empty, remove it + if(priority->prev != NULL) + priority->prev->next = priority->next; + else + priority_head = priority->next; + if(priority->next != NULL) + priority->next->prev = priority->prev; + free(priority); + } + // We're on that stack frame being freed right now, // but nobody can interrupt us anyways. // @@ -147,11 +163,22 @@ // FIXME: exit code? // - if((--nb_tasks)==1) { // only idle process? - systime_set_switcher(RTS_INSTRUCTION); // -> stop switcher, - cpid=&pd_single; // go single tasking. - cpid->pstate=P_RUNNING; - return cpid->sp_save; + switch(--nb_tasks) { + case 1: // only the idle process remains + /* This code is the same as what is in kill() + * except that it does not mess with interrupts + * and we know that there is only one process. + */ + *( (priority_head->cpid->sp_save) + SP_RETURN_OFFSET )= + (size_t) &exit; + // in case it's waiting. + priority_head->cpid->pstate=P_SLEEPING; + break; + case 0: // the last process has been removed + // -> stop switcher, + systime_set_switcher(RTS_INSTRUCTION); + cpid=&pd_single; // go single tasking. + return cpid->sp_save; } #ifndef NO_TASK_VISUALIZATION lcd_digit(nb_tasks); @@ -165,41 +192,33 @@ case P_WAITING: cpid->sp_save=old_sp; - - -#ifndef NO_EQUAL_PRIORITIES - // the scheduler is much faster if all priorities are different - // otherwise, we have to put the old task behind all - // tasks of equal priority to assure they will run. - insert=cpid->next; - if(insert->priority==cpid->priority) { - do - insert=insert->next; - while(insert->priority==cpid->priority); - - // cut cpid out - cpid->prev->next=cpid->next; - cpid->next->prev=cpid->prev; - - // insert before insert - cpid->prev=insert->prev; - cpid->next=insert; - cpid->prev->next=cpid->next->prev=cpid; - } -#endif } - next=pd_idle->next; + // find next process willing to run // - while(next->pstate==P_WAITING) - if( ( tmp=next->wakeup(next->wakeup_data) )!=0) { - next->wakeup_data=tmp; + priority=priority_head; + next=priority->cpid->next; + for(;;) + { + if(next->pstate!=P_WAITING) break; + if( ( tmp = next->wakeup(next->wakeup_data) ) != 0) { + next->wakeup_data = tmp; break; - } else + } + if(next == priority->cpid) + { // if we've scanned the whole chain, + // go to next priority + if(priority->next != NULL) + priority = priority->next; + else + priority = priority_head; + next=priority->cpid->next; + } else { next=next->next; - - cpid=next; // execute next process + } + } + cpid=next->priority->cpid=next; // execute next process cpid->pstate=P_RUNNING; return cpid->sp_save; @@ -255,16 +274,12 @@ // the single tasking context // - pd_single.next=pd_single.prev=&pd_single; pd_single.pstate=P_RUNNING; - pd_single.priority=255; cpid=&pd_single; // the idle process is an institution // - pd_idle=&pd_single; // execi needs pd_idle pd_idle=(process_data*)execi(&tm_idle_task,0,IDLE_STACK_SIZE); - pd_idle->next=pd_idle->prev=pd_idle; systime_set_timeslice(TM_DEFAULT_SLICE); } @@ -293,7 +308,8 @@ */ pid_t execi(int (*code_start)(void),priority_t priority,size_t stack_size) { process_data *pd; - process_data *insert; // where to insert? + priority_chain *pchain, *ppchain; // for traversing priority chain + priority_chain *newpchain; // for allocating new priority chain size_t *sp; // get memory @@ -340,7 +356,6 @@ *(--sp)=0; pd->sp_save=sp; // save sp for tm_switcher - pd->priority=priority; pd->pstate=P_SLEEPING; // task is waiting for execution pd->parent=cpid; // set parent @@ -349,28 +364,69 @@ // task queue manipulation -> lock irqs disable_irqs(); - insert=pd_idle->next; - - if(nb_tasks!=0) { - // idle has 0 priority -> this loop terminates assured - while(insert->priority>priority) - insert=insert->next; - -#ifdef NO_EQUAL_PRIORITIES - // the scheduler is much faster if all priorities are different - if(insert->priority==priority) { - enable_irqs(); + + ppchain=NULL; + for( pchain = priority_head; + pchain != NULL && (pchain->priority) > priority; + ppchain = pchain, pchain = pchain->next + ); + if(pchain==NULL) + { + // add new chain at end + pd->prev=pd->next=pd; + if((newpchain=(priority_chain *) + malloc(sizeof(priority_chain))) + ==NULL) + { free(pd->stack_base); free(pd); + enable_irqs(); return -1; } -#endif + newpchain->priority=priority; + newpchain->prev=ppchain; + newpchain->next=NULL; + newpchain->cpid=pd; + pd->priority=newpchain; + if(ppchain != NULL) + ppchain->next=newpchain; + else + priority_head=newpchain; + } else { + if(pchain->priority==priority) + { + // add process before the current one + pd->prev = pchain->cpid->prev; + pd->next = pchain->cpid; + pd->prev->next = + pchain->cpid->prev = pd; + pd->priority = pchain; + } + else + { + // insert new chain before pchain + pd->prev=pd->next=pd; + if((newpchain=(priority_chain *) + malloc(sizeof(priority_chain))) + ==NULL) + { + free(pd->stack_base); + free(pd); + enable_irqs(); + return -1; + } + newpchain->priority=priority; + newpchain->prev=ppchain; + newpchain->next=pchain; + newpchain->cpid=pd; + pd->priority=newpchain; + if(ppchain != NULL) + ppchain->next=newpchain; + else + priority_head=newpchain; + } } - - pd->prev=insert->prev; - pd->next=insert; - pd->prev->next=pd->next->prev=pd; - + nb_tasks++; enable_irqs();