Main Page | Modules | Data Structures | File List | Data Fields | Globals

exec.c

Go to the documentation of this file.
00001 /* BeeOS v0.1. Created: 2004/03/10 Modified: 2004/03/10
00002  * Copyright (C) 2004 Paul Harvey - ROMA, Australia.
00003  * csirac@users.sourceforge.net
00004  */
00005 
00006 /*   This program is free software; you can redistribute it and/or modify
00007  *   it under the terms of the GNU General Public License as published by
00008  *   the Free Software Foundation; either version 2 of the License, or
00009  *   (at your option) any later version.
00010  * 
00011  *   This program is distributed in the hope that it will be useful,
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *   GNU General Public License for more details.
00015  * 
00016  *   You should have received a copy of the GNU General Public License
00017  *   along with this program; if not, write to the Free Software
00018  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00023 #include "../include/beeos.h"
00024 #include "../include/bstring.h"
00025 #include "../include/bmalloc.h"
00026 #define IN_EXEC
00027 #include "../include/exec.h"
00028 #include <stdarg.h>
00029 #include "../include/bprintf.h"
00030 #ifdef HOSTED_BUILD
00031 #   include <stdio.h>
00032 #else
00033 #   include "../include/asm/ports.h"
00034 #   include "../include/ect.h"
00035 #endif
00036 
00037 /* BEGIN GLOBALS OF EVIL */
00038 execbase_t exec;
00039 regs_t tempregs;
00040 /* END GLOBALS OF EVIL */
00041 
00042 void idle_task (void);
00043 void task_dumpinfo (regs_t *regs);
00044 
00045 task_t *create_task(void (*func)(void), schar priority, ushort nextrun, ushort stacksize);
00046 void unlink_time (task_t *pTask);
00047 void unlink_prior (task_t *pTask);
00048 task_t *find_priority_lte(task_t *pTask, schar priority);
00049 task_t *find_nextrun_lte(task_t *pTask, ushort time);
00050 void insert_task_prior(task_t *pPrior, task_t *pTask);
00051 void insert_task_time(task_t *pTime, task_t *pTask);
00052 
00053 __inline__ void context_save2(task_t *pTask);
00054 __inline__ void context_restore2(task_t *pTask);
00055 __inline__ slong now_cmp (ushort a, ushort b, ushort now);
00056 __inline__ task_t *find_imperative_task(task_t *pCurrent);
00057 __inline__ task_t *find_urgent_task(ushort now);
00058 ushort task_select (void);
00059 void isr_exec (void) __attribute__ ((interrupt));
00060 void exec_idle (void);
00061 
00065 void task_dumpinfo (regs_t *regs)
00066 {
00067     bputs("taskdump:\r\n");
00068     /*bprintf(10, "   nextrun: %x.\r\n", (sshort) pTask->nextrun);
00069     bprintf(10, "   stacksize: %x.\r\n", (sshort) pTask->stacksize);
00070     bprintf(10, "   func: %x.\r\n", (sshort) pTask->func);
00071     bprintf(10, "   stack: %x.\r\n", (sshort) pTask->stack);
00072     bprintf(10, "   priority: %x.\r\n", (sshort) pTask->priority);*/
00073     bprintf(10, "   SP: %x.\r\n", regs->SP);
00074     bprintf(10, "   pc: %x.\r\n", regs->PC);
00075     bprintf(10, "   iy: %x.\r\n", regs->IY);
00076     bprintf(10, "   ix: %x.\r\n", regs->IX);
00077     bprintf(10, "   d: %x.\r\n", regs->D);
00078     bprintf(10, "   _ccr: %x.\r\n", regs->CCR);
00079     bprintf(10, "   _tmp: %x.\r\n", regs->_tmp);
00080     bprintf(10, "   _z: %x.\r\n", regs->_z);
00081     bprintf(10, "   _xy: %x.\r\n", regs->_xy);
00082     bprintf(10, "   _d1: %x.\r\n", regs->_d[0]);
00083     bprintf(10, "   _d2: %x.\r\n", regs->_d[1]);
00084     
00085     return;
00086 }
00087 
00104 task_t *create_task (void (*func)(void), schar priority, ushort nextrun, ushort stacksize)
00105 {
00106     uchar i;
00107     task_t *pTask = (task_t *) bremalloc(sizeof(task_t), NULL);
00108     
00109     pTask->func = func;
00110     pTask->priority = priority;
00111     pTask->nextrun = TOUSHORT(TCNT_H) + (ushort) MSEC2TCNT(nextrun);
00112     pTask->stacksize = stacksize;
00113     pTask->stack = (char *) bremalloc(stacksize, NULL);
00114     pTask->regs.SP = TOUSHORT(pTask->stack) + stacksize;
00115     pTask->regs.PC = (ushort) func;
00116     pTask->regs.IY = 0x1918;    /* Non-zero for stack debugging. */
00117     pTask->regs.IX = 0x1716;
00118     pTask->regs.D = 0x1514;
00119     pTask->regs.CCR = 0x13;
00120     pTask->regs._tmp = 0x12;
00121     pTask->regs._z = 0x11;
00122     pTask->regs._xy = 0x10;
00123     for (i = 0; i < GCC_SOFTREGCOUNT; i++) pTask->regs._d[i] = i;
00124     /*bmemset((char *) &(task_ptr->regs), '\0', sizeof(regs_t));*/
00125     
00126     return pTask;
00127 }
00128 
00134 void unlink_time (task_t *pTask)
00135 {   
00136     /* If pTask was the head task, reassign exec.head_time. */
00137     if (NULL == pTask->prev_time) exec.head_time = pTask->next_time;
00138         else pTask->prev_time->next_time = pTask->next_time;
00139     /* If pTask was the tail task, reassign exec.tail_time. */
00140     if (NULL == pTask->next_time) exec.tail_time = pTask->prev_time;
00141         else pTask->next_time->prev_time = pTask->prev_time;
00142     pTask->prev_time = NULL;
00143     pTask->next_time = NULL;
00144             
00145     return;
00146 }
00147 
00153 void unlink_prior (task_t *pTask)
00154 {
00155     /* If pTask was the head task, reassign exec.head_prior. */
00156     if (NULL == pTask->prev_prior) exec.head_prior = pTask->next_prior;
00157         else pTask->prev_prior->next_prior = pTask->next_prior;
00158     /* If pTask was the tail task, reassign exec.tail_time. */
00159     if (NULL == pTask->next_prior) exec.tail_prior = pTask->prev_prior;
00160         else pTask->next_prior->prev_prior = pTask->prev_prior;
00161     pTask->prev_prior = NULL;
00162     pTask->next_prior = NULL;
00163             
00164     return;
00165 }
00166 
00167 
00175 task_t *find_priority_lte (task_t *pTask, schar priority)
00176 {
00177     bool searching = true;
00178     
00179     while ( (NULL != pTask->next_prior) && (searching) ) {
00180         if (pTask->priority <= priority) searching = false;
00181         else pTask = pTask->next_prior;
00182     }
00183     
00184     return pTask;
00185 }
00186 
00194 task_t *find_nextrun_lte (task_t *pTask, ushort time)
00195 {
00196     bool searching = true;
00197     
00198     while ( (NULL != pTask->next_time) && (searching) ) {
00199         /* if (pTask->nextrun <= time) searching = false; */
00200         if (now_cmp(pTask->nextrun, time, time) <= 0) searching = false;
00201         else pTask = pTask->next_time;
00202     }
00203     
00204     return pTask;
00205 }
00206 
00217 void insert_task_prior (task_t *pPrior, task_t *pTask)
00218 {
00219     if (NULL == pPrior) {   /* Make pTask head_prior. */
00220         pTask->prev_prior = NULL;   /* Not necessary, probably already NULL.. */
00221         pTask->next_prior = exec.head_prior;
00222         if (NULL != exec.head_prior) exec.head_prior->prev_prior = pTask;
00223         exec.head_prior = pTask;
00224     } else {
00225         if (NULL != pPrior->next_prior) pPrior->next_prior->prev_prior = pTask;
00226         else exec.tail_prior = pTask;
00227         pTask->next_prior = pPrior->next_prior;
00228         pTask->prev_prior = pPrior;
00229         pPrior->next_prior = pTask;
00230     }
00231     
00232     return;
00233 }
00234 
00245 void insert_task_time (task_t *pTime, task_t *pTask)
00246 {
00247     if (NULL == pTime) {        /* Make pTask head_time. */
00248         pTask->prev_time = NULL;    /* Not necessary, probably already NULL.. */
00249         pTask->next_time = exec.head_time;
00250         if (NULL != exec.head_time) exec.head_time->prev_time = pTask;
00251         exec.head_time = pTask;
00252     } else {
00253         if (NULL != pTime->next_time) pTime->next_time->prev_time = pTask;
00254         else exec.tail_time = pTask;
00255         pTask->next_time = pTime->next_time;
00256         pTask->prev_time = pTime;
00257         pTime->next_time = pTask;
00258     }
00259 
00260     return;
00261 }
00262 
00277 void addtask (void (*func)(void), schar priority, ushort nextrun, ushort stacksize)
00278 {
00279     task_t *new_task = create_task(func, priority, nextrun, stacksize);
00280     task_t *pPrior, *pTime;
00281     
00282     if (NULL != exec.head_time) {   /* Assume head_time reflects head_prior */ 
00283         pPrior = find_priority_lte(exec.head_prior, priority);  /* NULL state. */
00284         pTime = find_nextrun_lte(exec.head_time, nextrun);
00285     } else {
00286         pPrior = NULL;
00287         pTime = NULL;
00288     }
00289     insert_task_prior(pPrior, new_task);
00290     insert_task_time(pTime, new_task);
00291 
00292     exec.numtasks++;
00293 
00294     return;
00295 }
00296 
00314 void bsleep (ushort sleeptime)
00315 {
00316     task_t *pTime;
00317     
00318     exec.current->nextrun = TOUSHORT(TCNT_H) + (ushort) MSEC2TCNT(sleeptime);
00319     ASM_SEI;    /* Don't want other tasks mangling the list in mid-search. */
00320     unlink_time(exec.current);
00321     pTime = find_nextrun_lte(exec.head_time, exec.current->nextrun);
00322     insert_task_time(pTime, exec.current);
00323     ASM_CLI;
00324     exec.idle = true;
00325     exec.blocked = false;   /* If a blocking task just finished, */
00326                         /* clear flag so isr_exec() can re-enable exec timer. */
00327     ASM_SWI;    /* Trigger an INTR to enter isr_exec() */
00328     
00329     return;
00330 }
00331 
00335 __inline__ void context_save2 (task_t *pTask)
00336 {
00337     bmemcpy((char *)&(pTask->regs),     (char *)&tempregs, sizeof(tempregs));
00338     
00339     return;
00340 }
00341 
00345 __inline__ void context_restore2 (task_t *pTask)
00346 {
00347     bmemcpy((char *)&tempregs, (char *)&(pTask->regs), sizeof(tempregs));   
00348     
00349     return;
00350 }
00351 
00363 __inline__ slong now_cmp (ushort a, ushort b, ushort now)
00364 {
00365     slong A = (slong) a, B = (slong) b;
00366     
00367     if (a < now) A += (slong) 65535;
00368     if (b < now) B += (slong) 65535;
00369     
00370     return A - B;
00371 }
00372 
00387 __inline__ task_t *find_imperative_task (task_t *pCurrent)
00388 {
00389     task_t *pImperative = pCurrent;
00390     bool searching = true;
00391     
00392     while ((NULL != pImperative->next_time) && (searching)) {
00393         pImperative = pImperative->next_time;
00394         if (pImperative->priority > pCurrent->priority) searching = false;
00395     }
00396 
00397     if (!searching) return pImperative;
00398         else return NULL;
00399 }
00400 
00412 __inline__ task_t *find_urgent_task (ushort now)
00413 {
00414     task_t *pUrgent = exec.head_prior;
00415     bool searching = true;
00416     
00417     while ((NULL != pUrgent->next_prior) && (searching)) {
00418         /* if (pUrgent->nextrun <= now) */
00419         if (0 >= now_cmp(pUrgent->nextrun, now, now)) searching = false;
00420             else pUrgent = pUrgent->next_prior;
00421     }
00422     
00423     if (!searching) return pUrgent;
00424         else return NULL;
00425 }
00426 
00472 ushort task_select (void)
00473 {
00474     ushort now = TOUSHORT(TCNT_H);  /* Need to substitute for slower timer... */
00475     ushort nextswitch = 0;          /* Return value */
00476     task_t *lastrun = exec.current; /* Used to check if tempregs needs update */
00477     task_t *pImperative = NULL;     /* Task that needs to intr current task */
00478     
00479     exec.current = exec.head_time;  /* Head of time list, ie. soonest to run. */
00480         /* if (exec.current->nextrun <= now) */     /* Is a task scheduled  */
00481     if (now_cmp(exec.current->nextrun, now, now) <= 0) {    /* right now? */
00482         /* Initially, exec.current is simply head_time. */
00483         /* if (exec.current->next_time->nextrun <= now) {*/ /* Behind schedule? */
00484         if (now_cmp(exec.current->next_time->nextrun, now, now) <= 0) {
00485             /* Here, at least first two tasks @ head_time are behind schedule; */
00486             /* head_time is ignored and instead the highest priority, behind */
00487             /* schedule task shall become the current task. */
00488             exec.current = find_urgent_task(now);
00489         }
00490         /* Now find out which task should interrupt the new current task */
00491         pImperative = find_imperative_task(exec.current);   /* Poss. NULL */
00492         if (NULL != pImperative) nextswitch = pImperative->nextrun;
00493             else exec.blocked = true;   /* Inhibit exec timer; highest pri. run */
00494         if (exec.current != lastrun) {  /* Don't bother saving/loading context */
00495             context_save2(lastrun);     /* if current was already loaded */
00496             context_restore2(exec.current);
00497             if (false != exec.current->sleeping) {
00498                 exec.current->sleeping = false;
00499                 exec.activetasks++;
00500             }
00501         }
00502         exec.idle = false;  /* Purpose unclear ... should reflect activetasks */
00503     } else {        /* This is now idle time; just set the alarm for head_time. */
00504         nextswitch = exec.current->nextrun;
00505         exec.idle = true;   /* Not sure what this does yet... */
00506         context_restore2(exec.idle_task);
00507     }
00508     
00509     return nextswitch;
00510 }
00511 
00520 void isr_exec_stuff (void)
00521 {
00522     TFLG1 |= BIT7;                          /* Clear TC7 interrupt */
00523     if (TFLG2 & ~ECT_TOF) TFLG2 |= ECT_TOF; /* Clear overflow flag if set */
00524     if (exec.blocked) TIE &= ~BIT7; /* If current task is not to be interrupted, */
00525         /* disable exec timer. Only an SWI from bsleep() can invoke exec. */
00526     else TIE |= BIT7;   /* Else re-enable exec timer. */
00527     PORTA ^= 0x01;      /* ... "debug" output */
00528     
00529     return;
00530 }
00531 
00541 void isr_exec (void)
00542 {
00543     ASM_SEI;
00544     CONTEXT_SAVE(); /* MUST be as close as possible to start; preserve stack/regs */
00545 
00546     TOUSHORT(TC7_H) = task_select();    /* Get new task, set isr_exec timer TC7. */
00547     isr_exec_stuff();   /* Extra code should go in this func; lest GCC dare use 
00548     * _d0.._dn softregisters and invalidate CONTEXT_RESTORE/CONTEXT_SAVE. */
00549     CONTEXT_RESTORE();  /* As close as possible to end; preserve stack/regs */
00550     ASM_CLI;
00551     
00552     return;
00553 }
00554 
00561 void execprep (void)
00562 {
00563     bmemset((char *)&exec, 0, sizeof(exec));
00564     exec.idle_task = create_task (exec_idle, -127, 0, 0);
00565     bfree(exec.idle_task->stack);
00566     exec.idle_task->stack = (void *)0x3FFF;
00567     
00568     return;
00569 }
00570 
00577 void exec_idle (void)
00578 {
00579     uchar temp;
00580     
00581     bputs("exec_idle().\r\n");
00582     while (1 == 1) {
00583         if (temp != exec.activetasks) {
00584             bprintf(10, "idle: activetasks=%i, was %i.\r\n", exec.activetasks, temp);
00585             temp = exec.activetasks;
00586         }
00587     }
00588     
00589     return;
00590 }

Generated on Sat Apr 10 17:08:02 2004 for BeeOS by doxygen 1.3.6-20040222