Initial revision
This commit is contained in:
348
task.c
Normal file
348
task.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*------------------------------------------------------------------------
|
||||
|
||||
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 <stdlib.h>
|
||||
#include <assert.h>
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 our selves killed. */
|
||||
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;
|
||||
}
|
Reference in New Issue
Block a user