Main Page   Modules   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

/projects/cubeos/src_current/kernel/schedule.c

Go to the documentation of this file.
00001 /*  src_experimental/kernel/schedule.c
00002    CubeOS Version 0.4.90 experimental
00003    Copyright (C) 1999,2000 Holger Kenn
00004 
00005    CubeOS is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or any later version.
00009 
00010    CubeOS is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015  */
00016 
00021 #undef SCHED_DEBUG
00022 /* This is my first scheduler */
00023 #include <stddef.h>
00024 #include <stdio.h>
00025 #include <signal.h>
00026 #include <cubeos.h>
00027 #include <sys_var.h>
00028 #include <context.h>
00029 #include <schedule.h>
00030 #include <kerror.h>
00031 #include <malloc.h>
00032 #include <cubereent.h>
00033 #include <list.h>
00034 
00035 
00036 #define MAGIC 0xbabababa;
00037 
00038 int _LIBC_init_reent();
00039 
00040 struct process _KERN_ptable[MAX_PROCESSNUM];    /* The process table */
00041 //int _KERN_deltahead; /* this is the head of the delta list */
00042 
00043 list _KERN_delta;
00044 list _KERN_prio[MAX_PRIONUM+1];
00045 
00050 void _KERN_taskend ()
00051 {
00052         _KERN_ptable[__MYPID].signal |= SIGKILL;
00053         KERN_schedule ();
00054 }
00055 
00060 regptr
00061 _KERN_initcontext (regptr context, short sr, void *sp, void *function)
00062 {
00063         /* initializes context so that it looks like function is just called */
00064 
00065         int i;
00066 
00067         void *stack;
00068 
00069         stack = sp;
00070 
00071         for (i = 0; i < PNREGS; i++)
00072                 (*context).regs[i] = 0;         /* Clear everything, just in case... */
00073 
00074         (*context).regs[POS_SR] = sr;   /* set up SR */
00075 
00076 
00077         (*context).regs[POS_PC] = (unsigned long) function;     /* set up PC */
00078 
00079 /*      The context switch is called in KERN_schedule(). The initial stack setup has to
00080    simulate this origin. The Stack that we're pointing to must look like this:
00081 
00082    *KERN_contextsw()
00083    *KERN_schedule()
00084    *function()
00085  */
00086 
00087         /* Stack Bottom */
00088         writeint (stack, (unsigned int) MAGIC);
00089         stack -= 4;
00090         writeint (stack, (unsigned int) _KERN_taskend);
00091 
00092 
00093         (*context).regs[POS_SSP] = (unsigned long) stack;       /* set up SSP */
00094 
00095 
00096         return context;
00097 }
00098 
00099 
00106 int KERN_create_prio (void *function,int prio)
00107 {                               /* no arguments yet */
00108         int i, j;
00109         short sr;
00110         void *stack;
00111         if ((prio<0)||(prio>MAX_PRIONUM))
00112                 return(-1);
00113 
00114 /* MUTEX! */
00115         disable ();
00116 
00117         /* find empty process slot */
00118         i = 1;
00119         while ((i < MAX_PROCESSNUM) && (_KERN_ptable[i].state != STATE_EMPTY))
00120                 i++;
00121         if (i == MAX_PROCESSNUM) {      /* No processes left. */
00122                 enable ();
00123                 KERN_complain (ERR_EMERG, "process table full");
00124                 /* errno=ERR_NO_MORE_PROCESSES; */
00125                 return (-1);
00126         }
00127         for (j = 0; j < PNREGS; j++)
00128                 _KERN_ptable[i].regs.regs[j] = 0;       /* Zero out Slot i */
00129         /* Slot i is now ready to use */
00130 
00131         stack = (void *) malloc (TASK_INIT_STACKSIZE);  /* Get us a stack */
00132         if (stack == NULL) {
00133                 enable ();
00134                 KERN_complain (ERR_EMERG, "no room for stack");
00135                 return (-1);
00136         }
00137         sr = TASK_INIT_SR;      /* Supervisor state */
00138         _KERN_ptable[i].irq = TASK_INIT_IRQLVL;         /* standard IRQ mask */
00139 
00140         _KERN_ptable[i].stack = stack;  /* for freeing the stack later */
00141 
00142         _KERN_initcontext (&(_KERN_ptable[i].regs), sr, (stack + TASK_INIT_STACKSIZE), function);
00143         _LIBC_init_reent (&_KERN_ptable[i].reent);
00144         _KERN_ptable[i].ppid = getpid ();       /* Parent ID */
00145 
00146         _KERN_ptable[i].state = STATE_READY;
00147         _KERN_ptable[i].signal = 0;
00148         _KERN_ptable[i].next = NO_TASK;         /* old list handling */
00149 
00150         _KERN_ptable[i].time_delta = 0;
00151         _KERN_ptable[i].prio = prio;
00152 
00153 //      _KERN_ptable[i].me.data = &(_KERN_ptable[i]);
00154 //      _KERN_ptable[i].me.len = sizeof (_KERN_ptable[i]);
00155         LIST_insert_tail (&_KERN_prio[prio], &(_KERN_ptable[i].me));
00156 /* MUTEX END */
00157         enable ();
00158         return i;
00159 }
00160 
00166 int KERN_create (void *function)
00167 {                       
00168 KERN_create_prio (function,0);
00169 }
00170 
00175 void KERN_schedule (void)
00176 {
00177         int old, new;
00178 
00179 /* prepare to switch context */
00180 
00181       asm ("move.w %%sr,%0":"=m" (_KERN_context_srsave));
00182         asm ("ori.w #0x0700,%sr");      /* Disable Interrupts */
00183 
00184 
00185         old = getpid ();
00186         if ((_KERN_ptable[old].state != STATE_RUNNING) && (_KERN_ptable[old].state != STATE_SUSPEND)) {
00187                 /* We're not the running task ?!? */
00188               asm ("move.w %0,%%sr": :"m" (_KERN_context_srsave));
00189                 KERN_complain (ERR_PANIC, "scheduler not called from running task");
00190                 return;         // we're in panic, so this will not be called 
00191 
00192         }
00193         if ((_KERN_ptable[old].signal & (1 << SIGKILL))) {
00194                 free (_KERN_ptable[old].stack);
00195                 LIST_delete (&_KERN_ptable[old].me);
00196                 /* removes thread from any queue */
00197                 _KERN_ptable[old].state = STATE_EMPTY;
00198         }
00199 
00200 #ifdef PLRR_SCHEDULER
00201 /* priority-less round robin */
00202         new = old;
00203         while ((new < MAX_PROCESSNUM) && (_KERN_ptable[new].state != STATE_READY))
00204                 new++;
00205         if (new == MAX_PROCESSNUM) {    /* wrap around */
00206                 new = 0;
00207                 while ((new < old) && (_KERN_ptable[new].state != STATE_READY))
00208                         new++;
00209         }
00210 #else
00211 #ifdef RR_SCHEDULER
00212 /* round robin over priorities, */
00213         {
00214                 int prio = MAX_PRIONUM;
00215                 int quit = 0;
00216                 entry *this;
00217 
00218 #ifdef SCHED_DEBUG
00219                 printf("s%d\n",old);
00220                 printf("task = 0x%x\n",(unsigned int)&(_KERN_ptable[old].me));
00221 #endif
00222                 new = old;
00223 
00224 
00225                 while ((!quit) && (prio >= 0)) {
00226                         /* look into process class prio */
00227                         if (LIST_entries (&_KERN_prio[prio]) > 0) {
00228                                 /* there are processes in this class */
00229                                 this = LIST_head (&_KERN_prio[prio]);
00230                                 /* this should give us the next thread to run */
00231                                 /* the rest are sanity checks */
00232                                 while (
00233                                               (this) &&
00234                                               (this->data) &&
00235                                               (((struct process *) (this->data))->state != STATE_READY))
00236                                         this = this->next;
00237                                 if (this)
00238                                         quit = 1;       /* if not, we'll retry one class lower */
00239                         }
00240                         prio--;
00241                 }
00242                 if (quit == 1) {        /* we've found another thread */
00243 #ifdef SCHED_DEBUG
00244                         printf("this = %x\n",(unsigned int) this);
00245 #endif
00246                         new = ((struct process *) (this->data))->pid;
00247 #ifdef SCHED_DEBUG
00248                         printf("n%d\n",new);
00249 #endif
00250                 }
00251 
00252         }
00253 #else
00254       asm ("move.w %0,%%sr": :"m" (_KERN_context_srsave));
00255         KERN_complain (ERR_PANIC, "NO Scheduler defined !");
00256 
00257 #endif
00258 #endif
00259         if ((new <0)
00260             ||(new>MAX_PROCESSNUM)
00261             ||(
00262                (_KERN_ptable[new].state!=STATE_READY)
00263                &&(new!=old))) {
00264                         printf("new=%d\n",new);
00265                         if ((new >0)&&(new<MAX_PROCESSNUM))
00266                                 printf("new.state = %d",_KERN_ptable[new].state);
00267                         KERN_complain (ERR_PANIC, "Scheduler did something stupid !");
00268         }
00269         if (old == new) {       /* Nobody else ready to run */
00270                 if (_KERN_ptable[old].state == STATE_EMPTY) {
00271                         /* We've just killed the last task ?!? */
00272                       asm ("move.w %0,%%sr": :"m" (_KERN_context_srsave));
00273                         KERN_complain (ERR_PANIC, "AIEEE, just killed my last task !");
00274                         while (1);
00275                         return; // we're in panic, so this will not be called 
00276 
00277                 }
00278               asm ("move.w %0,%%sr": :"m" (_KERN_context_srsave));
00279                 return;
00280         }
00281         if (_KERN_ptable[old].state == STATE_RUNNING) {
00282                 _KERN_ptable[old].state = STATE_READY;
00283                 LIST_insert_tail (&_KERN_prio[_KERN_ptable[old].prio], &_KERN_ptable[old].me);
00284                 /* insert old thread into its process class */
00285         }
00286         __MYPID = new;
00287 
00288         _KERN_ptable[new].state = STATE_RUNNING;
00289         LIST_delete (&_KERN_ptable[new].me);
00290         /* remove thread from its process class */
00291 
00292 /*      print("\n\rcontext\n\rStack:");putnum(_KERN_ptable[new].regs.regs[POS_SSP]);print("\n\r");
00293    print("\n\rFramep:");putnum(_KERN_ptable[new].regs.regs[POS_A6]);print("\n\r"); */
00294 
00295         _impure_ptr = &(_KERN_ptable[__MYPID].reent);
00296 
00297         KERN_contextsw (&(_KERN_ptable[old].regs), &(_KERN_ptable[new].regs));
00298 
00299         /* now we're the new task ! */
00300 /*
00301    asm("move.l %%sp,%0":"m=" (stackp): );
00302 
00303    printf("Stack:");putnum(stackp);print("\n\r");
00304    asm("move.l %%fp,%0":"m=" (stackp): );
00305 
00306    printf("Framep:");putnum(stackp);print("\n\r");
00307  */
00308 
00309         return;
00310 
00311 }
00312 
00317 int KERN_schedinit ()
00318 {
00319         int i, j;
00320 
00321 
00322         __MYPID = 0;
00323 
00324 //      _KERN_deltahead=NO_TASK; /* means deltalist is inactive */
00325 
00326         LIST_init (&_KERN_delta);
00327         _KERN_delta.type = LIST_TYPE_SYS;
00328 
00329         for (i = 0; i < MAX_PRIONUM; i++) {
00330                 LIST_init (&_KERN_prio[i]);
00331                 _KERN_prio[i].type = LIST_TYPE_PRIO;
00332         }
00333 
00334         /* empty process slots */
00335         for (i = 0; i < MAX_PROCESSNUM; i++) {
00336                 _KERN_ptable[i].state = STATE_EMPTY;
00337                 for (j = 0; j < PNREGS; j++)
00338                         _KERN_ptable[i].regs.regs[j] = 0;
00339                 _KERN_ptable[i].stack = (void *) 0;
00340                 _KERN_ptable[i].signal = 0;
00341                 _KERN_ptable[i].ppid = 0;
00342                 _KERN_ptable[i].pid = i;
00343                 LIST_makeentry (&_KERN_ptable[i].me);
00344                 _KERN_ptable[i].me.data = &(_KERN_ptable[i]);
00345                 _KERN_ptable[i].me.len = sizeof (_KERN_ptable[i]);
00346         }
00347 
00348         _KERN_ptable[0].state = STATE_RUNNING;
00349         _KERN_ptable[0].prio = 0;
00350         _LIBC_init_reent (&_KERN_ptable[0].reent);
00351         _impure_ptr = &(_KERN_ptable[0].reent);         /* initialise libc reentrance */
00352         return 0;
00353 
00354 }
00355 
00361 int KERN_suspend (int i)
00362 {
00363 // suspend sets task i into suspend mode, 
00364         // if i=-1 it suspends the running task.
00365         // if the running task was suspended, the scheduler is called
00366 
00367 // sanity checks
00368         if ((i < -1) || (i > MAX_PROCESSNUM)){
00369                 printf("cannot suspend %d\n",i);
00370                 return -1;
00371         }
00372         if ((i != -1) && (_KERN_ptable[i].state == STATE_EMPTY)){
00373                 printf("cannot suspend %d: empty\n",i);
00374                 return -1;
00375         }
00376 
00377         if ((i == -1) || (i == __MYPID)) {
00378                 // we're suspending the running task...
00379 
00380                 i = __MYPID;
00381                 // assert( _KERN_ptable[i].state == STATE_RUNNING);
00382                 _KERN_ptable[i].state = STATE_SUSPEND;
00383                 KERN_schedule ();
00384                 // here, the suspended task will continue afer wakeup...
00385         } else {
00386                 // we're suspending some other task.
00387                 // assert( _KERN_ptable[i].state == STATE_READY);
00388                 disable ();     /* don't confuse the scheduler */
00389                 _KERN_ptable[i].state = STATE_SUSPEND;
00390                 if (_KERN_ptable[i].me.list->type == LIST_TYPE_PRIO)
00391                         LIST_delete (&_KERN_ptable[i].me);
00392                 /* if the process is in one of the priority class lists, remove it */
00393                 /* so that the scheduler does not have to worry. */
00394                 enable ();
00395         }
00396 
00397         return 0;
00398 }
00399 
00405 int KERN_wakeup (int i)
00406 {
00407 
00408 // sanity checks
00409         if (i > MAX_PROCESSNUM)
00410                 return -1;
00411         if (_KERN_ptable[i].state != STATE_SUSPEND)
00412                 return -1;
00413 
00414         _KERN_ptable[i].state = STATE_READY;
00415         LIST_delete (&_KERN_ptable[i].me);      /* remove process from any queue */
00416         LIST_insert_head (&_KERN_prio[_KERN_ptable[i].prio], &_KERN_ptable[i].me);
00417 
00418 // KERN_schedule() ???
00419         return 0;
00420 }
00421 
00426 int KERN_delta_handler ()
00427 {
00428         int schedflag = 0;
00429 
00430 //if (_KERN_deltahead==NO_TASK) return (0); /* Delta list is empty */
00431 
00432         if (LIST_entries (&_KERN_delta) == 0)
00433                 return (0);
00434 
00435         ((struct process *) (LIST_head (&_KERN_delta)->data))->time_delta--;
00436 
00437         while ((LIST_entries (&_KERN_delta) > 0) &&
00438                (((struct process *) (LIST_head (&_KERN_delta)->data))->time_delta == 0)) {
00439                 KERN_wakeup (((struct process *) (LIST_head (&_KERN_delta))->data)->pid);
00440                 schedflag = 1;  // we want to reschedule
00441 
00442         }
00443 
00444 /* old code 
00445    _KERN_ptable[_KERN_deltahead].time_delta--;
00446 
00447    while ((_KERN_ptable[_KERN_deltahead].time_delta==0) //
00448    && (_KERN_deltahead!=NO_TASK)) //
00449    {
00450    if (KERN_wakeup(_KERN_deltahead))
00451    {
00452    //           iTTY_outchar('X');
00453    } else {
00454    //           iTTY_outchar('G');
00455    }
00456    schedflag=1; // we want to reschedule 
00457    _KERN_deltahead=_KERN_ptable[_KERN_deltahead].next;
00458    }
00459  */
00460 
00461 
00462         if (schedflag)
00463                 return 1;
00464 
00465         return 0;               /* nothing new */
00466 }

Generated on Thu Feb 20 15:38:44 2003 for cubeOS by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002