Files
pcas/src/libCom/taskwd/taskwd.c
2006-03-30 19:52:35 +00:00

234 lines
6.6 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*************************************************************************\
* Copyright (c) 2002 The University of Chicago, as Operator of Argonne
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* taskwd.c */
/* share/src/db @(#)taskwd.c 1.7 7/11/94 */
/* tasks and subroutines for a general purpose task watchdog */
/*
* Original Author: Marty Kraimer
* Date: 07-18-91
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#define epicsExportSharedSymbols
#include "dbDefs.h"
#include "epicsThread.h"
#include "epicsMutex.h"
#include "errlog.h"
#include "ellLib.h"
#include "errMdef.h"
#include "taskwd.h"
typedef void (*MYFUNCPTR)();
struct task_list {
ELLNODE node;
MYFUNCPTR callback;
void *arg;
union {
epicsThreadId tid;
void *userpvt;
} id;
int suspended;
};
static ELLLIST list;
static ELLLIST anylist;
static epicsMutexId lock;
static epicsMutexId anylock;
static epicsMutexId alloclock;
static epicsThreadId taskwdid=0;
volatile int taskwdOn=TRUE;
struct freeList{
struct freeList *next;
};
static struct freeList *freeHead=NULL;
/* Task delay times (seconds) */
#define TASKWD_DELAY 6.0
/*forward definitions*/
static void taskwdTask(void);
static struct task_list *allocList(void);
static void freeList(struct task_list *pt);
static void taskwdInitPvt(void *);
static void taskwdInitPvt(void *arg)
{
lock = epicsMutexMustCreate();
anylock = epicsMutexMustCreate();
alloclock = epicsMutexMustCreate();
ellInit(&list);
ellInit(&anylist);
taskwdid = epicsThreadCreate(
"taskwd",epicsThreadPriorityLow,
epicsThreadGetStackSize(epicsThreadStackSmall),
(EPICSTHREADFUNC)taskwdTask,0);
}
void epicsShareAPI taskwdInit()
{
static epicsThreadOnceId taskwdOnceFlag = EPICS_THREAD_ONCE_INIT;
void *arg = 0;
epicsThreadOnce(&taskwdOnceFlag,taskwdInitPvt,arg);
}
void epicsShareAPI taskwdInsert(epicsThreadId tid,TASKWDFUNCPRR callback,void *arg)
{
struct task_list *pt;
taskwdInit();
if(tid==0) {
errlogPrintf("taskwdInsert called with null tid\n");
return;
}
epicsMutexMustLock(lock);
pt = allocList();
ellAdd(&list,(void *)pt);
pt->suspended = FALSE;
pt->id.tid = tid;
pt->callback = callback;
pt->arg = arg;
epicsMutexUnlock(lock);
}
void epicsShareAPI taskwdAnyInsert(void *userpvt,TASKWDANYFUNCPRR callback,void *arg)
{
struct task_list *pt;
taskwdInit();
epicsMutexMustLock(anylock);
pt = allocList();
ellAdd(&anylist,(void *)pt);
pt->id.userpvt = userpvt;
pt->callback = callback;
pt->arg = arg;
epicsMutexUnlock(anylock);
}
void epicsShareAPI taskwdRemove(epicsThreadId tid)
{
struct task_list *pt;
char thrName[40];
taskwdInit();
epicsMutexMustLock(lock);
pt = (struct task_list *)ellFirst(&list);
while(pt!=NULL) {
if (tid == pt->id.tid) {
ellDelete(&list,(void *)pt);
freeList(pt);
epicsMutexUnlock(lock);
return;
}
pt = (struct task_list *)ellNext(&pt->node);
}
epicsMutexUnlock(lock);
epicsThreadGetName(tid, thrName, 40);
errlogPrintf("taskwdRemove: Thread %s (%p) not registered!\n",
thrName, tid);
}
void epicsShareAPI taskwdAnyRemove(void *userpvt)
{
struct task_list *pt;
taskwdInit();
epicsMutexMustLock(anylock);
pt = (struct task_list *)ellFirst(&anylist);
while(pt!=NULL) {
if (userpvt == pt->id.userpvt) {
ellDelete(&anylist,(void *)pt);
freeList(pt);
epicsMutexUnlock(anylock);
return;
}
pt = (struct task_list *)ellNext(&pt->node);
}
epicsMutexUnlock(anylock);
errlogPrintf("taskwdAnyRemove: Userpvt %p not registered!\n", userpvt);
}
static void taskwdTask(void)
{
struct task_list *pt,*next;
while(TRUE) {
if(taskwdOn) {
epicsMutexMustLock(lock);
pt = (struct task_list *)ellFirst(&list);
while(pt) {
next = (struct task_list *)ellNext(&pt->node);
if(epicsThreadIsSuspended(pt->id.tid)) {
if(!pt->suspended) {
struct task_list *ptany;
char thrName[40];
pt->suspended = TRUE;
epicsThreadGetName(pt->id.tid, thrName, 40);
errlogPrintf("Thread %s (%p) suspended\n",
thrName, (void *)pt->id.tid);
ptany = (struct task_list *)ellFirst(&anylist);
while(ptany) {
if(ptany->callback) {
TASKWDANYFUNCPRR pcallback = pt->callback;
(pcallback)(ptany->arg,pt->id.tid);
}
ptany = (struct task_list *)ellNext(&ptany->node);
}
if(pt->callback) {
TASKWDFUNCPRR pcallback = pt->callback;
void *arg = pt->arg;
/*Must allow callback to call taskwdRemove*/
epicsMutexUnlock(lock);
(pcallback)(arg);
/*skip rest because we have unlocked*/
break;
}
}
} else {
pt->suspended = FALSE;
}
pt = next;
}
epicsMutexUnlock(lock);
}
epicsThreadSleep(TASKWD_DELAY);
}
}
static struct task_list *allocList(void)
{
struct task_list *pt;
epicsMutexMustLock(alloclock);
if(freeHead) {
pt = (struct task_list *)freeHead;
freeHead = freeHead->next;
} else pt = calloc(1,sizeof(struct task_list));
while (pt==NULL) {
errlogPrintf("Thread taskwd suspending: out of memory\n");
epicsThreadSuspendSelf();
pt = calloc(1,sizeof(struct task_list));
}
epicsMutexUnlock(alloclock);
return(pt);
}
static void freeList(struct task_list *pt)
{
epicsMutexMustLock(alloclock);
((struct freeList *)pt)->next = freeHead;
freeHead = (struct freeList *)pt;
epicsMutexUnlock(alloclock);
}