Files
sics/task.c
koennecke 86e246416b - Added bridge functions to histmemsec to make it look more like histmem
- Modifed many modules using histmem to work also with histmemsec
- Extended tasker with task names and task groups
- There is a new taskobj which allows to list tasks and to interact with them.
- Task now supports running Tcl functions as tasks
- There is a new experimental sctcomtask module which allows to define communication
  tasks against a scriptcontext. This is a new feature which should facilitate
  writing sequential scripts using asynchronous communication.
- A fix to make spss7 work when there are no switches
- ORION support for single X. TRICS measures crystals hanging down, ORION
  standing up


SKIPPED:
	psi/ease.c
	psi/faverage.c
	psi/jvlprot.c
	psi/make_gen
	psi/pardef.c
	psi/polterwrite.c
	psi/psi.c
	psi/sinq.c
	psi/spss7.c
2012-12-20 11:32:33 +00:00

576 lines
14 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
/*--------------------------------------------------------------------------*/
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;
/*---------------------------------------------------------------------------*/
static long lIDMama = 0L;
#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;
pNew->lID = lIDMama++;
pNew->iStatus = READY;
if(lIDMama < 0){
lIDMama = 0;
}
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;
}
/*-----------------------------------------------------------------------------*/
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,":%ld", it->groupID);
return result;
}
/*------------------------------------------------------------------------------*/
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;
assert(self->iID == TASKERID);
pNext = self->pHead->pNext; /* skip dummy task */
while (pNext != NULL) {
pCurrent = pNext;
pNext = pCurrent->pNext;
if (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;
}