diff --git a/src/db/callback.c b/src/db/callback.c new file mode 100644 index 000000000..0fa6c6033 --- /dev/null +++ b/src/db/callback.c @@ -0,0 +1,145 @@ +/* callback.c */ +/* share/src/db $Id$ */ + +/* general purpose callback tasks */ +/* + * Original Author: Marty Kraimer + * Date: 07-18-91 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + * .01 12-12-91 mrk moved from dbScan.c to callback.c +*/ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static SEM_ID callbackSem[NUM_CALLBACK_PRIORITIES]; +static int callbackTaskId[NUM_CALLBACK_PRIORITIES]; +volatile int callbackRestart=FALSE; +static volatile CALLBACK *head[NUM_CALLBACK_PRIORITIES]; +static volatile CALLBACK *tail[NUM_CALLBACK_PRIORITIES]; + +/* forward references */ +void wdCallback(); /*callback from taskwd*/ +void start(); /*start or restart a callbackTask*/ + +/*public routines */ +long callbackInit() +{ + int i; + + for(i=0; ipriority; + int lockKey; + + if(priority<0 || priority>(NUM_CALLBACK_PRIORITIES)) { + logMsg("callbackRequest called with invalid priority"); + return(-1); + } + lockKey = intLock(); + pcallback->next = NULL; + tail[priority]->next = pcallback; + if(head[priority]==NULL) head[priority] = pcallback; + intUnlock(lockKey); + if(semGive(callbackSem[priority])!=OK) + logMsg("semGive returned error in callbackRequest\n"); + return(0); +} + +/* General purpose callback task */ +static void callbackTask(int priority) +{ + volatile CALLBACK *pcallback,*next; + int lockKey; + + while(TRUE) { + /* wait for somebody to wake us up */ + if(semTake(callbackSem[priority],WAIT_FOREVER)!=OK ) + logMsg("semTake returned error in callbackRequest\n"); + + while(TRUE) { + lockKey = intLock(); + if((pcallback=head[priority])==NULL) break; + if((head[priority]=pcallback->next)==NULL) tail[priority]=NULL; + intUnlock(lockKey); + (*pcallback->callback)(pcallback); + } + } +} + +static void start(int ind) +{ + char name[100]; + int priority; + + head[ind] = tail[ind] = 0; + if((callbackSem[ind] = semBCreate(SEM_Q_FIFO,SEM_EMPTY))==NULL) + logMsg("semBcreate failed while starting a callback task\n"); + sprintf(name,"%s%2.2d",CALLBACK_NAME,ind); + if(ind==0) priority = CALLBACK_PRI_LOW; + else if(ind==1) priority = CALLBACK_PRI_MEDIUM; + else if(ind==2) priority = CALLBACK_PRI_HIGH; + else { + logMsg("semBcreate failed while starting a callback task\n"); + return; + } + callbackTaskId[ind] = taskSpawn(name,priority, + CALLBACK_OPT,CALLBACK_STACK, + (FUNCPTR)callbackTask,ind); + if(callbackTaskId[ind]==ERROR) { + errMessage(0,"Failed to spawn a callback task"); + return; + } + taskwdInsert(callbackTaskId[ind],wdCallback,(void *)(long)ind); +} + + +static void wdCallback(long ind) +{ + taskwdRemove(callbackTaskId[ind]); + if(!callbackRestart)return; + if(taskDelete(callbackTaskId[ind])!=OK) + logMsg("taskDelete failed while restarting a callback task\n"); + if(semFlush(callbackSem[ind])!=OK) + logMsg("semFlush failed while restarting a callback task\n"); + start(ind); +} diff --git a/src/db/taskwd.c b/src/db/taskwd.c new file mode 100644 index 000000000..93d2defdf --- /dev/null +++ b/src/db/taskwd.c @@ -0,0 +1,175 @@ +/* taskwd.c */ +/* share/src/db $Id$ */ + +/* tasks and subroutines for a general purpose task watchdog */ +/* + * Original Author: Marty Kraimer + * Date: 07-18-91 + * + * Experimental Physics and Industrial Control System (EPICS) + * + * Copyright 1991, the Regents of the University of California, + * and the University of Chicago Board of Governors. + * + * This software was produced under U.S. Government contracts: + * (W-7405-ENG-36) at the Los Alamos National Laboratory, + * and (W-31-109-ENG-38) at Argonne National Laboratory. + * + * Initial development by: + * The Controls and Automation Group (AT-8) + * Ground Test Accelerator + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Co-developed with + * The Controls and Computing Group + * Accelerator Systems Division + * Advanced Photon Source + * Argonne National Laboratory + * + * Modification Log: + * ----------------- + * .01 07-24-91 mrk Replacement for special purpose scan watchdog + */ + + +/* Public routines + * taskwdInit() Initialize task watchdor + * + * taskwdInsert(tid,callback,arg) Insert in lists of tasks to watch + * int tid Task Id + * VOIDFUNCPTR callback Address of callback routine + * void *arg Argument to pass to callback + * + * taskwdRemove(tid) Remove from list of tasks to watch + * + * int tid Task Id + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct task_list { + NODE node; + VOIDFUNCPTR callback; + void *arg; + int tid; + int suspended; +}; + +static LIST list; +static FAST_LOCK lock; +static int taskwdid=0; +volatile int taskwdOn=TRUE; +struct freeList{ + struct freeList *next; +}; +static struct freeList *freeHead=NULL; + +/*forward definitions*/ +void taskwdTask(); +struct task_list *allocList(); +void freeList(struct task_list *); + +void taskwdInit() +{ + FASTLOCKINIT(&lock); + lstInit(&list); + taskwdid = taskSpawn(TASKWD_NAME,TASKWD_PRI, + TASKWD_OPT,TASKWD_STACK,(FUNCPTR )taskwdTask); +} + +void taskwdInsert(int tid,VOIDFUNCPTR callback,void *arg) +{ + struct task_list *pt; + + FASTLOCK(&lock); + pt = allocList(); + lstAdd(&list,(void *)pt); + pt->suspended = FALSE; + pt->tid = tid; + pt->callback = callback; + pt->arg = arg; + FASTUNLOCK(&lock); +} + +void taskwdRemove(int tid) +{ + int i; + struct task_list *pt; + + FASTLOCK(&lock); + (void *)pt = lstFirst(&list); + while(pt!=NULL) { + if (tid == pt->tid) { + lstDelete(&list,(void *)pt); + freeList(pt); + FASTUNLOCK(&lock); + return; + } + (void *)pt = lstNext((void *)pt); + } + FASTUNLOCK(&lock); + errMessage(-1,"taskwdRemove failed"); +} + +static void taskwdTask() +{ + struct task_list *pt,*next; + + while(TRUE) { + if(taskwdOn) { + FASTLOCK(&lock); + (void *)pt = lstFirst(&list); + while(pt!=NULL) { + (void *)next = lstNext((void *)pt); + if(taskIsSuspended(pt->tid)) { + char *pname; + char message[100]; + + pname = taskName(pt->tid); + if(!pt->suspended) { + sprintf(message,"task %d %s suspended",pt->tid,pname); + errMessage(-1,message); + if(pt->callback) (pt->callback)(pt->arg); + } + pt->suspended = TRUE; + } + pt = next; + } + FASTUNLOCK(&lock); + } + taskDelay(TASKWD_DELAY*vxTicksPerSecond); + } +} + + +struct task_list *allocList() +{ + struct task_list *pt; + + if(freeHead) { + (void *)pt = (void *)freeHead; + freeHead = freeHead->next; + } else pt = calloc(1,sizeof(struct task_list *)); + if(pt==NULL) { + errMessage(0,"taskwd failed on call to calloc\n"); + exit(1); + } + return(pt); +} + +void freeList(struct task_list *pt) +{ + + ((struct freeList *)pt)->next = freeHead; + freeHead = (struct freeList *)pt; +}