- 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
576 lines
14 KiB
C
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;
|
|
}
|