/*------------------------------------------------------------------------ T A S K E R Implementation of a portable task switcher. Mark Koennecke, September 1997 copyleft, 1997. NO WARRANTIES OF ANY KIND WHATSOEVER TAKEN BY ME OR MY EMPLOYER. YOU ARE AT YOUR OWN! ----------------------------------------------------------------------------*/ #include #include #include "fortify.h" #include "task.h" #define READY 1 #define WAITING 2 #define YIELDING 3 /*--------------------------------------------------------------------------*/ typedef struct __TaskHead { long lID; int iStatus; long lWait; TaskFunc pRun; SignalFunc pSignal; void *pData; TaskKillFunc pKill; pTaskHead pNext; pTaskHead pPrevious; } TaskHead; typedef struct __TaskMan { int iID; int iStop; pTaskHead pCurrent; pTaskHead pHead; } TaskMan; /*---------------------------------------------------------------------------*/ static long lIDMama = 0L; #define TASKERID 123399 /*---------------------------------------------------------------------------*/ static pTaskHead MakeTaskHead(TaskFunc pTask, SignalFunc pSignal, void *pData, TaskKillFunc pKill) { pTaskHead pNew = NULL; pNew = (pTaskHead)malloc(sizeof(TaskHead)); if(!pNew) { return NULL; } memset(pNew,0,sizeof(TaskHead)); pNew->pRun = pTask; pNew->pSignal = pSignal; pNew->pData = pData; pNew->pKill = pKill; pNew->lID = lIDMama++; pNew->iStatus = READY; return pNew; } /*--------------------------------------------------------------------------*/ static void DeleteTaskHead(pTaskHead self) { assert(self); if(self->pKill) { if(self->pData) { self->pKill(self->pData); } } /* unlink */ if(self->pPrevious != NULL) { self->pPrevious->pNext = self->pNext; } if(self->pNext != NULL) { self->pNext->pPrevious = self->pPrevious; } free(self); } /*--------------------------------------------------------------------------*/ static int DummyTask(void *pData) { return 1; } /*--------------------------------------------------------------------------*/ int TaskerInit(pTaskMan *self) { pTaskMan pNew = NULL; pTaskHead pDummyTask = NULL; *self = NULL; /* a new Task manager */ pNew = (pTaskMan)malloc(sizeof(TaskMan)); if(!pNew) { return 0; } memset(pNew, 0, sizeof(TaskMan)); pNew->iID = TASKERID; /* create a dummy task as start point */ pDummyTask = MakeTaskHead(DummyTask,NULL,NULL,NULL); if(!pDummyTask) { free(pNew); return 0; } /* link */ pDummyTask->pNext = NULL; pDummyTask->pPrevious = NULL; pNew->pCurrent = pDummyTask; pNew->pHead = pDummyTask; *self = pNew; return 1; } /*---------------------------------------------------------------------------*/ int TaskerDelete(pTaskMan *pData) { pTaskMan self = *pData; pTaskHead pCurrent, pKill; assert(self); assert(self->iID == TASKERID); pCurrent = self->pHead; while(pCurrent != NULL) { pKill = pCurrent; pCurrent = pCurrent->pNext; DeleteTaskHead(pKill); } free(self); *pData = NULL; return 1; } /*---------------------------------------------------------------------------*/ long TaskRegister(pTaskMan self, TaskFunc pTask, SignalFunc pSignal, TaskKillFunc pKill, void *pData, int iPriority) { pTaskHead pNew = NULL; assert(self); assert(self->iID == TASKERID); assert(pTask); pNew = MakeTaskHead(pTask,pSignal, pData, pKill); if(!pNew) { return -1; } /* link it in */ if(self->pCurrent->pNext) { self->pCurrent->pNext->pPrevious = pNew; } pNew->pPrevious = self->pCurrent; pNew->pNext = self->pCurrent->pNext; self->pCurrent->pNext = pNew; return pNew->lID; } /*-------------------------------------------------------------------------*/ static void IncrTaskPointer(pTaskMan self) { self->pCurrent = self->pCurrent->pNext; if(self->pCurrent == NULL) { self->pCurrent = self->pHead; } } /*-------------------------------------------------------------------------*/ static int TaskExist(pTaskMan self, long lID) { pTaskHead pCur = self->pHead; while(pCur != NULL) { if(pCur->lID == lID) { return 1; } pCur = pCur->pNext; } return 0; } /*--------------------------------------------------------------------------*/ int TaskSchedule(pTaskMan self) { int iRet; pTaskHead pTemp; assert(self); assert(self->iID == TASKERID); /* forever, until stop is called somehow */ while(self->iStop == 0) { if(self->pCurrent->iStatus == READY) { iRet = self->pCurrent->pRun(self->pCurrent->pData); if(iRet != 1) { pTemp = self->pCurrent; IncrTaskPointer(self); DeleteTaskHead(pTemp); } else { IncrTaskPointer(self); } } else { IncrTaskPointer(self); } } return 1; } /*-----------------------------------------------------------------*/ int TaskWait(pTaskMan self, long lID) { int iRet; long lTest; pTaskHead pTemp, pEnd; assert(self); assert(self->iID == TASKERID); /* Cycle until lID is killed. Stop is obeyed as well */ pEnd = self->pCurrent; pEnd->iStatus = WAITING; IncrTaskPointer(self); while(self->iStop == 0) { if((self->pCurrent != pEnd) && (self->pCurrent->iStatus == READY)) /* omit ourselves! */ { iRet = self->pCurrent->pRun(self->pCurrent->pData); if(iRet != 1) { pTemp = self->pCurrent; lTest = pTemp->lID; IncrTaskPointer(self); DeleteTaskHead(pTemp); if(lTest == lID) { goto ente; } } else { IncrTaskPointer(self); } } else { IncrTaskPointer(self); } if(self->pCurrent == self->pHead) { if(!TaskExist(self,lID)) goto ente; } } ente: /* task ended, we need to continue to pEnd before we are done */ while(self->pCurrent != pEnd) { IncrTaskPointer(self); } pEnd->iStatus = READY; return 1; } /*----------------------------------------------------------------*/ int TaskYield(pTaskMan self) { int iRet; long lTest; pTaskHead pTemp, pEnd; assert(self); assert(self->iID == TASKERID); /* Cycle until back at ourselves */ pEnd = self->pCurrent; pEnd->iStatus = WAITING; IncrTaskPointer(self); while((self->iStop == 0) && (self->pCurrent != pEnd)) { if((self->pCurrent != pEnd) && (self->pCurrent->iStatus == READY)) /* omit ourselves! */ { iRet = self->pCurrent->pRun(self->pCurrent->pData); if(iRet != 1) { pTemp = self->pCurrent; lTest = pTemp->lID; IncrTaskPointer(self); DeleteTaskHead(pTemp); } else { IncrTaskPointer(self); } } else { IncrTaskPointer(self); } } pEnd->iStatus = READY; return 1; } /*---------------------------------------------------------------------------*/ int TaskSignal(pTaskMan self, int iSignal, void *pSigData) { pTaskHead pTemp, pEnd; assert(self); assert(self->iID == TASKERID); /* Do one cycle until we are at the caller, then return to him*/ pEnd = self->pCurrent; IncrTaskPointer(self); while(self->pCurrent != pEnd) { if(self->pCurrent->pSignal) { self->pCurrent->pSignal(self->pCurrent->pData, iSignal, pSigData); } IncrTaskPointer(self); } /* finally, tell me about the thingie as well */ if(pEnd->pSignal) { pEnd->pSignal(pEnd->pData, iSignal, pSigData); } return 1; } /*--------------------------------------------------------------------------*/ int TaskStop(pTaskMan self) { assert(self); assert(self->iID == TASKERID); self->iStop = 1; return 1; } /*--------------------------------------------------------------------------*/ int TaskContinue(pTaskMan self) { assert(self); assert(self->iID == TASKERID); self->iStop = 0; return 1; }