Files
sics/task.c
Mark Koennecke 722fab935e Fixed a task and a tasdrive issue
There is a rare condition when SICS has frehsly stared up and on the first call
to a coordinated driving, like in TAS, something fails. Then the group has ID 0,
the default and that one is always active. This has been fixed by starting valid
groups at 7, defining 0 ans IDUNDEFINED and checking in isTaskGroupRunning for
IDUNDEFINED

Then there is an issue in tasdrive. I added a call to CheckStatus when starting the
mono. This is necessary for the eiger monochromator as with that one starting is deferred
to the CheckSttaus function. The reason is that in other use cases, the looser might want
to drive a2 and a2w at the same time. This can only correctly be accomodated by deferring
the caclulations to the CheckStatus phase.
2014-04-07 14:02:07 +02:00

620 lines
15 KiB
C

/*------------------------------------------------------------------------
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!
Reworked to have a task name, stop by task name and better listing.
Mark Koennecke, December 2012
----------------------------------------------------------------------------*/
#include <stdlib.h>
#include <assert.h>
#include <time.h>
#include <stdio.h>
#include "fortify.h"
#include "task.h"
#define READY 1
#define WAITING 2
#define YIELDING 3
#define IDUNDEFINED 0L
/*--------------------------------------------------------------------------*/
typedef struct __TaskHead {
long lID;
long groupID;
int iStatus;
long lWait;
char *name;
time_t start_time;
TaskFunc pRun;
SignalFunc pSignal;
void *pData;
TaskKillFunc pKill;
pTaskHead pNext;
pTaskHead pPrevious;
} TaskHead;
typedef struct __TaskMan {
int iID;
int iStop;
pTaskHead pCurrent; /* Think trice before you interfere with this! */
pTaskHead pHead;
} TaskMan;
/*---------------------------------------------------------------------------
The 7 below solves a subtle bug which occurs when a groupID in user code
has been initialized to 0 and starting fails. Then it seems as if this
group keeps running. As there will always be some task running at 0.
----------------------------------------------------------------------------*/
static long lIDMama = 7L;
#define TASKERID 123399
/*---------------------------------------------------------------------------*/
static pTaskHead MakeTaskHead(char *name, 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->name = strdup(name);
pNew->start_time = time(NULL);
pNew->pRun = pTask;
pNew->pSignal = pSignal;
pNew->pData = pData;
pNew->pKill = pKill;
lIDMama++;
pNew->lID = lIDMama;
pNew->iStatus = READY;
pNew->groupID = IDUNDEFINED;
if(lIDMama < 0){
lIDMama = 7;
}
return pNew;
}
/*--------------------------------------------------------------------------*/
static void DeleteTaskHead(pTaskHead self)
{
assert(self);
if (self->pKill) {
if (self->pData) {
self->pKill(self->pData);
}
}
if(self->name != NULL){
free(self->name);
}
/* 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("init",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;
}
/*----------------------- temporary for backwards compatability -------------*/
long TaskRegister(pTaskMan self,TaskFunc pTask, SignalFunc pSignal,
TaskKillFunc pKill, void *pData, int iPriority)
{
return TaskRegisterN(self,"Unknown", pTask, pSignal, pKill, pData, iPriority);
}
/*---------------------------------------------------------------------------*/
long TaskRegisterN(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal,
TaskKillFunc pKill, void *pData, int iPriority)
{
pTaskHead pNew = NULL;
assert(self);
assert(self->iID == TASKERID);
assert(pTask);
pNew = MakeTaskHead(name, 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;
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;
}
/*--------------------------------------------------------------------------*/
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) {
if(pCurrent == self->pCurrent){
/* cannot kill myself */
return;
}
/* unlink */
if (pCurrent->pPrevious != NULL) {
pCurrent->pPrevious->pNext = pCurrent->pNext;
}
if (pCurrent->pNext != NULL) {
pCurrent->pNext->pPrevious = pCurrent->pPrevious;
}
if(pCurrent->name != NULL){
free(pCurrent->name);
}
free(pCurrent);
}
}
return;
}
/*-----------------------------------------------------------------------------*/
int StopTask(pTaskMan self, char *name)
{
int iRet;
pTaskHead pCurrent, pNext;
if (self == NULL) return 0;
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (strcmp(pCurrent->name,name) == 0) {
if(self->pCurrent == pCurrent){
/**
* cannot kill myself
*/
return 0;
}
/* unlink */
if (pCurrent->pPrevious != NULL) {
pCurrent->pPrevious->pNext = pCurrent->pNext;
}
if (pCurrent->pNext != NULL) {
pCurrent->pNext->pPrevious = pCurrent->pPrevious;
}
if(pCurrent->name != NULL){
free(pCurrent->name);
}
free(pCurrent);
}
}
return 1;
}
/*-----------------------------------------------------------------------------*/
int isTaskRunning(pTaskMan self, char *name)
{
int iRet;
pTaskHead pCurrent, pNext;
if (self == NULL) return 0;
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (strcmp(pCurrent->name,name) == 0) {
return 1;
}
}
return 0;
}
/*-----------------------------------------------------------------------------*/
int isTaskIDRunning(pTaskMan self, long lID)
{
int iRet;
pTaskHead pCurrent, pNext;
if (self == NULL) return 0;
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (pCurrent->lID == lID) {
return 1;
}
}
return 0;
}
/*-----------------------------------------------------------------------------*/
pTaskHead TaskIteratorStart(pTaskMan self)
{
if (self == NULL) return NULL;
assert(self->iID == TASKERID);
return self->pHead->pNext; /* skip dummy task */
}
/*-----------------------------------------------------------------------------*/
pTaskHead TaskIteratorNext(pTaskHead it)
{
if(it != NULL){
return it->pNext;
}
return NULL;
}
/*-----------------------------------------------------------------------------*/
char *TaskDescription(pTaskHead it)
{
char *result;
int length;
const struct tm *tm;
if(it == NULL){
return NULL;
}
length = strlen(it->name) + 120;
result = malloc(length*sizeof(char));
if(result == NULL){
return NULL;
}
memset(result,0,length*sizeof(char));
strcpy(result,it->name);
strcat(result,"|");
length = strlen(result);
tm = localtime((const time_t *)&it->start_time);
strftime(result+length,100,"%F-%k-%m-%S",tm);
length = strlen(result);
snprintf(result+length,120-20,"|%ld", it->lID);
length = strlen(result);
snprintf(result+length,120-40,"|%.0ld ", it->groupID);
return result;
}
/*------------------------------------------------------------------------------*/
long GetTaskID(pTaskHead it)
{
return it->lID;
}
/*------------------------------------------------------------------------------*/
long GetGroupID(pTaskHead it)
{
return it->groupID;
}
/*------------------------------------------------------------------------------*/
const char * GetTaskName(pTaskHead it)
{
return (const char*)it->name;
}
/*------------------------------------------------------------------------------*/
long GetTaskGroupID(pTaskMan self)
{
lIDMama++;
return lIDMama;
}
/*-------------------------------------------------------------------------------*/
void AddTaskToGroup(pTaskMan self, long taskID, long groupID)
{
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->lID == taskID) {
pCurrent->groupID = groupID;
return;
}
}
}
/*---------------------------------------------------------------------------------
This simply checks if there are any more tasks with the desired groupID in the
list. If none, then all sub tasks have finished.
-----------------------------------------------------------------------------------*/
int isTaskGroupRunning(pTaskMan self, long groupID)
{
pTaskHead pCurrent, pNext;
if (self == NULL) return 0;
if (groupID == IDUNDEFINED) return 0;
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (pCurrent->groupID != IDUNDEFINED && pCurrent->groupID == groupID) {
return 1;
}
}
return 0;
}
/*------------------------------------------------------------------------------*/
int TaskGroupTask(void *data)
{
pTaskGroupData self = (pTaskGroupData)data;
return isTaskGroupRunning(self->tasker,self->groupID);
}
/*-------------------------------------------------------------------------------*/
int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, long groupID)
{
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->groupID == groupID) {
self->pCurrent->pSignal(self->pCurrent->pData, iSignal, pSigData);
}
IncrTaskPointer(self);
}
return 1;
}