/*------------------------------------------------------------------------ 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) && self->pCurrent != NULL) /* 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; int myStatus = self->pCurrent->iStatus; assert(self); assert(self->iID == TASKERID); /* Do one cycle until we are at the caller, then return to him */ pEnd = self->pCurrent; pEnd->iStatus = WAITING; 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 */ pEnd->iStatus = myStatus; 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; } /*--------------------------------------------------------------------------*/ void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData) { int iRet; pTaskHead pCurrent, pNext; if (self == NULL) return; assert(self->iID == TASKERID); pNext = self->pHead->pNext; /* skip dummy task */ while (pNext != NULL) { pCurrent = pNext; pNext = pCurrent->pNext; if (pCurrent->pRun == pTaskRun && pCurrent->pData == pData) { /* unlink */ if (pCurrent->pPrevious != NULL) { pCurrent->pPrevious->pNext = pCurrent->pNext; } if (pCurrent->pNext != NULL) { pCurrent->pNext->pPrevious = pCurrent->pPrevious; } free(pCurrent); } } return; }