From 056304409764d7605e46d411fb2fa565344d1b0d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 28 Dec 2009 20:37:09 -0600 Subject: [PATCH] Marty Kraimer's changes to support process-get operations. --- src/ioc/db/dbCAC.h | 3 +- src/ioc/db/dbCommon.dbd | 8 +- src/ioc/db/dbNotify.c | 534 +++++++++++++++++------------- src/ioc/db/dbNotify.h | 151 ++++++--- src/ioc/db/dbPutNotifyBlocker.cpp | 48 +-- src/ioc/db/dbPutNotifyBlocker.h | 10 +- src/ioc/db/db_access.c | 66 ++-- src/ioc/db/db_test.c | 43 +-- src/ioc/misc/iocInit.c | 2 +- src/ioc/rsrv/camessage.c | 77 +++-- src/std/dev/Makefile | 6 + src/std/dev/devAiSoftCallback.c | 155 +++++++++ src/std/dev/devBiSoftCallback.c | 155 +++++++++ src/std/dev/devLiSoftCallback.c | 155 +++++++++ src/std/dev/devMbbiSoftCallback.c | 155 +++++++++ src/std/dev/devSiSoftCallback.c | 155 +++++++++ src/std/dev/devSoft.dbd | 6 + 17 files changed, 1354 insertions(+), 375 deletions(-) create mode 100644 src/std/dev/devAiSoftCallback.c create mode 100644 src/std/dev/devBiSoftCallback.c create mode 100644 src/std/dev/devLiSoftCallback.c create mode 100644 src/std/dev/devMbbiSoftCallback.c create mode 100644 src/std/dev/devSiSoftCallback.c diff --git a/src/ioc/db/dbCAC.h b/src/ioc/db/dbCAC.h index 3032023dc..744041280 100644 --- a/src/ioc/db/dbCAC.h +++ b/src/ioc/db/dbCAC.h @@ -55,7 +55,8 @@ #include "db_convert.h" #include "resourceLib.h" -extern "C" void putNotifyCompletion ( putNotify *ppn ); +extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType notifyPutType ); +extern "C" void putNotifyCompletion ( processNotify *ppn ); class dbContext; class dbChannelIO; diff --git a/src/ioc/db/dbCommon.dbd b/src/ioc/db/dbCommon.dbd index d940999e7..981e3b01a 100644 --- a/src/ioc/db/dbCommon.dbd +++ b/src/ioc/db/dbCommon.dbd @@ -171,16 +171,16 @@ extra("struct asgMember *asp") } field(PPN,DBF_NOACCESS) { - prompt("addr of PUTNOTIFY") + prompt("pprocessNotify") special(SPC_NOMOD) interest(4) - extra("struct putNotify *ppn") + extra("struct processNotify *ppn") } field(PPNR,DBF_NOACCESS) { - prompt("pputNotifyRecord") + prompt("pprocessNotifyRecord") special(SPC_NOMOD) interest(4) - extra("struct putNotifyRecord *ppnr") + extra("struct processNotifyRecord *ppnr") } field(SPVT,DBF_NOACCESS) { prompt("Scan Private") diff --git a/src/ioc/db/dbNotify.c b/src/ioc/db/dbNotify.c index 7454129dc..c6403d502 100644 --- a/src/ioc/db/dbNotify.c +++ b/src/ioc/db/dbNotify.c @@ -46,39 +46,39 @@ #include "epicsTime.h" #include "cantProceed.h" -/*putNotify.state values */ +/*notify state values */ typedef enum { - putNotifyNotActive, - putNotifyWaitForRestart, - putNotifyRestartCallbackRequested, - putNotifyRestartInProgress, - putNotifyPutInProgress, - putNotifyUserCallbackRequested, - putNotifyUserCallbackActive -}putNotifyState; + notifyNotActive, + notifyWaitForRestart, + notifyRestartCallbackRequested, + notifyRestartInProgress, + notifyProcessInProgress, + notifyUserCallbackRequested, + notifyUserCallbackActive +}notifyState; /*structure attached to ppnr field of each record*/ -typedef struct putNotifyRecord { +typedef struct processNotifyRecord { ellCheckNode waitNode; - ELLLIST restartList; /*list of putNotifys to restart*/ + ELLLIST restartList; /*list of processNotifys to restart*/ dbCommon *precord; -}putNotifyRecord; +}processNotifyRecord; #define MAGIC 0xfedc0123 -typedef struct putNotifyPvt { +typedef struct notifyPvt { ELLNODE node; /*For free list*/ long magic; short state; CALLBACK callback; - ELLLIST waitList; /*list of records for current putNotify*/ + ELLLIST waitList; /*list of records for current processNotify*/ short cancelWait; short userCallbackWait; epicsEventId cancelEvent; epicsEventId userCallbackEvent; -}putNotifyPvt; +}notifyPvt; -/* putNotify groups can span locksets if links are dynamically modified*/ -/* Thus a global lock is taken while putNotify fields are accessed */ +/* processNotify groups can span locksets if links are dynamically modified*/ +/* Thus a global lock is taken while processNotify fields are accessed */ typedef struct notifyGlobal { epicsMutexId lock; ELLLIST freeList; @@ -87,12 +87,11 @@ typedef struct notifyGlobal { static notifyGlobal *pnotifyGlobal = 0; /*Local routines*/ -static void putNotifyInit(putNotify *ppn); -static void putNotifyCleanup(putNotify *ppn); -static void restartCheck(putNotifyRecord *ppnr); -static void callUser(dbCommon *precord,putNotify *ppn); -static void notifyCallback(CALLBACK *pcallback); -static void putNotifyCommon(putNotify *ppn,dbCommon *precord); +static void notifyInit(processNotify *ppn); +static void notifyCleanup(processNotify *ppn); +static void restartCheck(processNotifyRecord *ppnr); +static void callDone(dbCommon *precord,processNotify *ppn); +static void processNotifyCommon(processNotify *ppn,dbCommon *precord); #define ellSafeAdd(list,listnode) \ { \ @@ -108,176 +107,193 @@ static void putNotifyCommon(putNotify *ppn,dbCommon *precord); (listnode)->isOnList=0; \ } -static void putNotifyInit(putNotify *ppn) +static void notifyInit(processNotify *ppn) { - putNotifyPvt *pputNotifyPvt; + notifyPvt *pnotifyPvt; - pputNotifyPvt = (putNotifyPvt *)ellFirst(&pnotifyGlobal->freeList); - if(pputNotifyPvt) { - ellDelete(&pnotifyGlobal->freeList,&pputNotifyPvt->node); + pnotifyPvt = (notifyPvt *)ellFirst(&pnotifyGlobal->freeList); + if(pnotifyPvt) { + ellDelete(&pnotifyGlobal->freeList,&pnotifyPvt->node); } else { - pputNotifyPvt = dbCalloc(1,sizeof(putNotifyPvt)); - pputNotifyPvt->cancelEvent = epicsEventCreate(epicsEventEmpty); - pputNotifyPvt->userCallbackEvent = epicsEventCreate(epicsEventEmpty); - pputNotifyPvt->magic = MAGIC; - pputNotifyPvt->state = putNotifyNotActive; + pnotifyPvt = dbCalloc(1,sizeof(notifyPvt)); + pnotifyPvt->cancelEvent = epicsEventCreate(epicsEventEmpty); + pnotifyPvt->userCallbackEvent = epicsEventCreate(epicsEventEmpty); + pnotifyPvt->magic = MAGIC; + pnotifyPvt->state = notifyNotActive; } - pputNotifyPvt->state = putNotifyNotActive; - callbackSetCallback(notifyCallback,&pputNotifyPvt->callback); - callbackSetUser(ppn,&pputNotifyPvt->callback); - callbackSetPriority(priorityLow,&pputNotifyPvt->callback); - ellInit(&pputNotifyPvt->waitList); - ppn->status = 0; - pputNotifyPvt->state = putNotifyNotActive; - pputNotifyPvt->cancelWait = pputNotifyPvt->userCallbackWait = 0; - ppn->pputNotifyPvt = pputNotifyPvt; + pnotifyPvt->state = notifyNotActive; + callbackSetCallback(notifyCallback,&pnotifyPvt->callback); + callbackSetUser(ppn,&pnotifyPvt->callback); + callbackSetPriority(priorityLow,&pnotifyPvt->callback); + ellInit(&pnotifyPvt->waitList); + ppn->status = notifyOK; + ppn->wasProcessed = 0; + pnotifyPvt->state = notifyNotActive; + pnotifyPvt->cancelWait = pnotifyPvt->userCallbackWait = 0; + ppn->pnotifyPvt = pnotifyPvt; } -static void putNotifyCleanup(putNotify *ppn) +static void notifyCleanup(processNotify *ppn) { - putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; + notifyPvt *pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; - pputNotifyPvt->state = putNotifyNotActive; - ellAdd(&pnotifyGlobal->freeList,&pputNotifyPvt->node); - ppn->pputNotifyPvt = 0; + pnotifyPvt->state = notifyNotActive; + ellAdd(&pnotifyGlobal->freeList,&pnotifyPvt->node); + ppn->pnotifyPvt = 0; } -static void restartCheck(putNotifyRecord *ppnr) +static void restartCheck(processNotifyRecord *ppnr) { dbCommon *precord = ppnr->precord; - putNotify *pfirst; - putNotifyPvt *pputNotifyPvt; + processNotify *pfirst; + notifyPvt *pnotifyPvt; assert(precord->ppn); - pfirst = (putNotify *)ellFirst(&ppnr->restartList); + pfirst = (processNotify *)ellFirst(&ppnr->restartList); if(!pfirst) { precord->ppn = 0; return; } - pputNotifyPvt = (putNotifyPvt *)pfirst->pputNotifyPvt; - assert(pputNotifyPvt->state==putNotifyWaitForRestart); + pnotifyPvt = (notifyPvt *)pfirst->pnotifyPvt; + assert(pnotifyPvt->state==notifyWaitForRestart); /* remove pfirst from restartList */ ellSafeDelete(&ppnr->restartList,&pfirst->restartNode); /*make pfirst owner of the record*/ precord->ppn = pfirst; /* request callback for pfirst */ - pputNotifyPvt->state = putNotifyRestartCallbackRequested; - callbackRequest(&pputNotifyPvt->callback); + pnotifyPvt->state = notifyRestartCallbackRequested; + callbackRequest(&pnotifyPvt->callback); } -static void callUser(dbCommon *precord,putNotify *ppn) +static void callDone(dbCommon *precord,processNotify *ppn) { - putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; + notifyPvt *pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; epicsMutexUnlock(pnotifyGlobal->lock); - dbScanUnlock(precord); - (*ppn->userCallback)(ppn); - epicsMutexMustLock(pnotifyGlobal->lock); - if(pputNotifyPvt->cancelWait && pputNotifyPvt->userCallbackWait) { - errlogPrintf("%s putNotify: both cancelWait and userCallbackWait true." - "This is illegal\n",precord->name); - pputNotifyPvt->cancelWait = pputNotifyPvt->userCallbackWait = 0; + if (ppn->requestType == processGetRequest || + ppn->requestType == putProcessGetRequest) { + ppn->getCallback(ppn, getFieldType); } - if(!pputNotifyPvt->cancelWait && !pputNotifyPvt->userCallbackWait) { - putNotifyCleanup(ppn); + dbScanUnlock(precord); + ppn->doneCallback(ppn); + epicsMutexMustLock(pnotifyGlobal->lock); + if (pnotifyPvt->cancelWait && pnotifyPvt->userCallbackWait) { + errlogPrintf("%s processNotify: both cancelWait and userCallbackWait true." + "This is illegal\n",precord->name); + pnotifyPvt->cancelWait = pnotifyPvt->userCallbackWait = 0; + } + if (!pnotifyPvt->cancelWait && !pnotifyPvt->userCallbackWait) { + notifyCleanup(ppn); epicsMutexUnlock(pnotifyGlobal->lock); return; } - if(pputNotifyPvt->cancelWait) { - pputNotifyPvt->cancelWait = 0; - epicsEventSignal(pputNotifyPvt->cancelEvent); + if (pnotifyPvt->cancelWait) { + pnotifyPvt->cancelWait = 0; + epicsEventSignal(pnotifyPvt->cancelEvent); epicsMutexUnlock(pnotifyGlobal->lock); return; } - assert(pputNotifyPvt->userCallbackWait); - pputNotifyPvt->userCallbackWait = 0; - epicsEventSignal(pputNotifyPvt->userCallbackEvent); + assert(pnotifyPvt->userCallbackWait); + pnotifyPvt->userCallbackWait = 0; + epicsEventSignal(pnotifyPvt->userCallbackEvent); epicsMutexUnlock(pnotifyGlobal->lock); return; } -static void putNotifyCommon(putNotify *ppn,dbCommon *precord) +static void processNotifyCommon(processNotify *ppn,dbCommon *precord) { - long status=0; - dbFldDes *pfldDes = ppn->paddr->pfldDes; - putNotifyPvt *pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; + dbFldDes *pfldDes=(dbFldDes *)(ppn->paddr->pfldDes); + notifyPvt *pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + int didPut = 0; + int doProcess = 0; - if(precord->ppn && pputNotifyPvt->state!=putNotifyRestartCallbackRequested) - { /*another putNotify owns the record */ - pputNotifyPvt->state = putNotifyWaitForRestart; + if (precord->ppn && pnotifyPvt->state!=notifyRestartCallbackRequested) { + /*another processNotify owns the record */ + pnotifyPvt->state = notifyWaitForRestart; ellSafeAdd(&precord->ppnr->restartList,&ppn->restartNode); epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); return; - } else if(precord->ppn){ - assert(precord->ppn==ppn); - assert(pputNotifyPvt->state==putNotifyRestartCallbackRequested); + } else if (precord->ppn) { + assert(precord->ppn == ppn); + assert(pnotifyPvt->state == notifyRestartCallbackRequested); } - if(precord->pact) { + if (precord->pact) { precord->ppn = ppn; - ellSafeAdd(&pputNotifyPvt->waitList,&precord->ppnr->waitNode); - pputNotifyPvt->state = putNotifyRestartInProgress; + ellSafeAdd(&pnotifyPvt->waitList,&precord->ppnr->waitNode); + pnotifyPvt->state = notifyRestartInProgress; epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); return; } - status=dbPut(ppn->paddr,ppn->dbrType,ppn->pbuffer,ppn->nRequest); - ppn->status = (status==0) ? putNotifyOK : putNotifyError; + if (ppn->requestType == putProcessRequest || + ppn->requestType == putProcessGetRequest) { + /*check for putField disabled*/ + if (precord->disp && ((void *)&precord->disp != ppn->paddr->pfield)) { + ppn->putCallback(ppn, putDisabledType); + } else { + didPut = ppn->putCallback(ppn, putType); + } + } /* Check to see if dbProcess should not be called */ - if(!status /*dont process if dbPut returned error */ - &&((ppn->paddr->pfield==(void *)&precord->proc) /*If PROC call dbProcess*/ - || (pfldDes->process_passive && precord->scan==0))) { + if (didPut && ((ppn->paddr->pfield == (void *)&precord->proc) + || (pfldDes->process_passive && precord->scan==0))) doProcess = 1; + if (!doProcess && ppn->requestType == processGetRequest) { + if (precord->scan == 0) doProcess = 1; + } + if (doProcess) { + ppn->wasProcessed = 1; precord->ppn = ppn; - ellSafeAdd(&pputNotifyPvt->waitList,&precord->ppnr->waitNode); - pputNotifyPvt->state = putNotifyPutInProgress; + ellSafeAdd(&pnotifyPvt->waitList, &precord->ppnr->waitNode); + pnotifyPvt->state = notifyProcessInProgress; epicsMutexUnlock(pnotifyGlobal->lock); dbProcess(precord); dbScanUnlock(precord); return; } - if(pputNotifyPvt->state==putNotifyRestartCallbackRequested) { + if (pnotifyPvt->state == notifyRestartCallbackRequested) { restartCheck(precord->ppnr); } - pputNotifyPvt->state = putNotifyUserCallbackActive; + pnotifyPvt->state = notifyUserCallbackActive; assert(precord->ppn!=ppn); - callUser(precord,ppn); + callDone(precord, ppn); } static void notifyCallback(CALLBACK *pcallback) { - putNotify *ppn=NULL; - dbCommon *precord; - putNotifyPvt *pputNotifyPvt; + processNotify *ppn=NULL; + dbCommon *precord; + notifyPvt *pnotifyPvt; callbackGetUser(ppn,pcallback); - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; precord = ppn->paddr->precord; dbScanLock(precord); epicsMutexMustLock(pnotifyGlobal->lock); assert(precord->ppnr); - assert(pputNotifyPvt->state==putNotifyRestartCallbackRequested - || pputNotifyPvt->state==putNotifyUserCallbackRequested); - assert(ellCount(&pputNotifyPvt->waitList)==0); - if(pputNotifyPvt->cancelWait) { - if(pputNotifyPvt->state==putNotifyRestartCallbackRequested) { + assert(pnotifyPvt->state==notifyRestartCallbackRequested + || pnotifyPvt->state==notifyUserCallbackRequested); + assert(ellCount(&pnotifyPvt->waitList)==0); + if (pnotifyPvt->cancelWait) { + if (pnotifyPvt->state == notifyRestartCallbackRequested) { restartCheck(precord->ppnr); } - epicsEventSignal(pputNotifyPvt->cancelEvent); + epicsEventSignal(pnotifyPvt->cancelEvent); epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); return; } - if(pputNotifyPvt->state==putNotifyRestartCallbackRequested) { - putNotifyCommon(ppn,precord); + if(pnotifyPvt->state == notifyRestartCallbackRequested) { + processNotifyCommon(ppn,precord); return; } /* All done. Clean up and call userCallback */ - pputNotifyPvt->state = putNotifyUserCallbackActive; + pnotifyPvt->state = notifyUserCallbackActive; assert(precord->ppn!=ppn); - callUser(precord,ppn); + callDone(precord, ppn); } -void epicsShareAPI dbPutNotifyInit(void) +void epicsShareAPI dbProcessNotifyInit(void) { if(pnotifyGlobal) return; pnotifyGlobal = dbCalloc(1,sizeof(notifyGlobal)); @@ -285,104 +301,111 @@ void epicsShareAPI dbPutNotifyInit(void) ellInit(&pnotifyGlobal->freeList); } -void epicsShareAPI dbPutNotify(putNotify *ppn) +void epicsShareAPI dbProcessNotify(processNotify *ppn) { dbCommon *precord = ppn->paddr->precord; short dbfType = ppn->paddr->field_type; - long status=0; - putNotifyPvt *pputNotifyPvt; + notifyPvt *pnotifyPvt; assert(precord); - /*check for putField disabled*/ - if(precord->disp) { - if((void *)(&precord->disp) != ppn->paddr->pfield) { - ppn->status = putNotifyPutDisabled; - (*ppn->userCallback)(ppn); - return; - } - } /* Must handle DBF_XXXLINKs as special case. * Only dbPutField will change link fields. * Also the record is not processed as a result */ - if(dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) { - status=dbPutField(ppn->paddr,ppn->dbrType,ppn->pbuffer,ppn->nRequest); - ppn->status = (status==0) ? putNotifyOK : putNotifyError; - (*ppn->userCallback)(ppn); + ppn->status = notifyOK; + ppn->wasProcessed = 0; + if (dbfType>=DBF_INLINK && dbfType<=DBF_FWDLINK) { + if (ppn->requestType == putProcessRequest || + ppn->requestType == putProcessGetRequest) { + /*check for putField disabled*/ + if (precord->disp &&((void *)(&precord->disp) != ppn->paddr->pfield)) { + ppn->putCallback(ppn, putDisabledType); + } else { + ppn->putCallback(ppn, putFieldType); + } + } + if (ppn->requestType == processGetRequest || + ppn->requestType == putProcessGetRequest) { + ppn->getCallback(ppn, getFieldType); + + } + ppn->doneCallback(ppn); return; } dbScanLock(precord); epicsMutexMustLock(pnotifyGlobal->lock); - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; - if(pputNotifyPvt && (pputNotifyPvt->magic!=MAGIC)) { - printf("dbPutNotify:pputNotifyPvt was not initialized\n"); - pputNotifyPvt = 0; + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + if (pnotifyPvt && (pnotifyPvt->magic!=MAGIC)) { + printf("dbPutNotify:pnotifyPvt was not initialized\n"); + pnotifyPvt = 0; } - if(pputNotifyPvt) { - assert(pputNotifyPvt->state==putNotifyUserCallbackActive); - pputNotifyPvt->userCallbackWait = 1; + if (pnotifyPvt) { + assert(pnotifyPvt->state==notifyUserCallbackActive); + pnotifyPvt->userCallbackWait = 1; epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); - epicsEventWait(pputNotifyPvt->userCallbackEvent); + epicsEventWait(pnotifyPvt->userCallbackEvent); dbScanLock(precord); epicsMutexMustLock(pnotifyGlobal->lock); - putNotifyCleanup(ppn); + notifyCleanup(ppn); } - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; - assert(!pputNotifyPvt); - putNotifyInit(ppn); - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; - if(!precord->ppnr) {/* make sure record has a putNotifyRecord*/ - precord->ppnr = dbCalloc(1,sizeof(putNotifyRecord)); + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + assert(!pnotifyPvt); + notifyInit(ppn); + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + if (!precord->ppnr) { + /* make sure record has a processNotifyRecord*/ + precord->ppnr = dbCalloc(1,sizeof(processNotifyRecord)); precord->ppnr->precord = precord; ellInit(&precord->ppnr->restartList); } - putNotifyCommon(ppn,precord); + processNotifyCommon(ppn, precord); } -void epicsShareAPI dbNotifyCancel(putNotify *ppn) +void epicsShareAPI dbNotifyCancel(processNotify *ppn) { dbCommon *precord = ppn->paddr->precord; - putNotifyState state; - putNotifyPvt *pputNotifyPvt; + notifyState state; + notifyPvt *pnotifyPvt; assert(precord); dbScanLock(precord); epicsMutexMustLock(pnotifyGlobal->lock); - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; - if(!pputNotifyPvt || pputNotifyPvt->state==putNotifyNotActive) { + ppn->status = notifyCanceled; + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + if(!pnotifyPvt || pnotifyPvt->state==notifyNotActive) { epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); return; } - state = pputNotifyPvt->state; + state = pnotifyPvt->state; /*If callback is scheduled or active wait for it to complete*/ - if(state==putNotifyUserCallbackRequested - || state==putNotifyRestartCallbackRequested - || state==putNotifyUserCallbackActive) { - pputNotifyPvt->cancelWait = 1; + if(state==notifyUserCallbackRequested + || state==notifyRestartCallbackRequested + || state==notifyUserCallbackActive) { + pnotifyPvt->cancelWait = 1; epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); - epicsEventWait(pputNotifyPvt->cancelEvent); + epicsEventWait(pnotifyPvt->cancelEvent); epicsMutexMustLock(pnotifyGlobal->lock); - putNotifyCleanup(ppn); + notifyCleanup(ppn); epicsMutexUnlock(pnotifyGlobal->lock); return; } switch(state) { - case putNotifyNotActive: break; - case putNotifyWaitForRestart: + case notifyNotActive: break; + case notifyWaitForRestart: assert(precord->ppn); assert(precord->ppn!=ppn); ellSafeDelete(&precord->ppnr->restartList,&ppn->restartNode); break; - case putNotifyRestartInProgress: - case putNotifyPutInProgress: + case notifyRestartInProgress: + case notifyProcessInProgress: { /*Take all records out of wait list */ - putNotifyRecord *ppnrWait; + processNotifyRecord *ppnrWait; - while((ppnrWait = (putNotifyRecord *)ellFirst(&pputNotifyPvt->waitList))){ - ellSafeDelete(&pputNotifyPvt->waitList,&ppnrWait->waitNode); + while((ppnrWait = (processNotifyRecord *)ellFirst(&pnotifyPvt->waitList))){ + ellSafeDelete(&pnotifyPvt->waitList,&ppnrWait->waitNode); restartCheck(ppnrWait); } } @@ -391,36 +414,36 @@ void epicsShareAPI dbNotifyCancel(putNotify *ppn) default: printf("dbNotify: illegal state for notifyCallback\n"); } - pputNotifyPvt->state = putNotifyNotActive; - putNotifyCleanup(ppn); + pnotifyPvt->state = notifyNotActive; + notifyCleanup(ppn); epicsMutexUnlock(pnotifyGlobal->lock); dbScanUnlock(precord); } void epicsShareAPI dbNotifyCompletion(dbCommon *precord) { - putNotify *ppn = precord->ppn; - putNotifyPvt *pputNotifyPvt; + processNotify *ppn = precord->ppn; + notifyPvt *pnotifyPvt; epicsMutexMustLock(pnotifyGlobal->lock); assert(ppn); assert(precord->ppnr); - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; - if(pputNotifyPvt->state!=putNotifyRestartInProgress - && pputNotifyPvt->state!=putNotifyPutInProgress) { + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + if(pnotifyPvt->state!=notifyRestartInProgress + && pnotifyPvt->state!=notifyProcessInProgress) { epicsMutexUnlock(pnotifyGlobal->lock); return; } - ellSafeDelete(&pputNotifyPvt->waitList,&precord->ppnr->waitNode); - if((ellCount(&pputNotifyPvt->waitList)!=0)) { + ellSafeDelete(&pnotifyPvt->waitList,&precord->ppnr->waitNode); + if((ellCount(&pnotifyPvt->waitList)!=0)) { restartCheck(precord->ppnr); - } else if(pputNotifyPvt->state == putNotifyPutInProgress) { - pputNotifyPvt->state = putNotifyUserCallbackRequested; + } else if(pnotifyPvt->state == notifyProcessInProgress) { + pnotifyPvt->state = notifyUserCallbackRequested; restartCheck(precord->ppnr); - callbackRequest(&pputNotifyPvt->callback); - } else if(pputNotifyPvt->state == putNotifyRestartInProgress) { - pputNotifyPvt->state = putNotifyRestartCallbackRequested; - callbackRequest(&pputNotifyPvt->callback); + callbackRequest(&pnotifyPvt->callback); + } else if(pnotifyPvt->state == notifyRestartInProgress) { + pnotifyPvt->state = notifyRestartCallbackRequested; + callbackRequest(&pnotifyPvt->callback); } else { cantProceed("dbNotifyCompletion illegal state"); } @@ -429,52 +452,103 @@ void epicsShareAPI dbNotifyCompletion(dbCommon *precord) void epicsShareAPI dbNotifyAdd(dbCommon *pfrom, dbCommon *pto) { - putNotify *ppn = pfrom->ppn; - putNotifyPvt *pputNotifyPvt; + processNotify *ppn = pfrom->ppn; + notifyPvt *pnotifyPvt; if(pto->pact) return; /*if active it will not be processed*/ epicsMutexMustLock(pnotifyGlobal->lock); - if(!pto->ppnr) {/* make sure record has a putNotifyRecord*/ - pto->ppnr = dbCalloc(1,sizeof(putNotifyRecord)); + if(!pto->ppnr) {/* make sure record has a processNotifyRecord*/ + pto->ppnr = dbCalloc(1,sizeof(processNotifyRecord)); pto->ppnr->precord = pto; ellInit(&pto->ppnr->restartList); } assert(ppn); - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; if(!(pto->ppn) - && (pputNotifyPvt->state==putNotifyPutInProgress) + && (pnotifyPvt->state==notifyProcessInProgress) && (pto!=ppn->paddr->precord)) { - putNotifyPvt *pputNotifyPvt; + notifyPvt *pnotifyPvt; pto->ppn = pfrom->ppn; - pputNotifyPvt = (putNotifyPvt *)pfrom->ppn->pputNotifyPvt; - ellSafeAdd(&pputNotifyPvt->waitList,&pto->ppnr->waitNode); + pnotifyPvt = (notifyPvt *)pfrom->ppn->pnotifyPvt; + ellSafeAdd(&pnotifyPvt->waitList,&pto->ppnr->waitNode); } epicsMutexUnlock(pnotifyGlobal->lock); } typedef struct tpnInfo { epicsEventId callbackDone; - putNotify *ppn; + processNotify *ppn; + char *psavevalue; }tpnInfo; -static void dbtpnCallback(putNotify *ppn) +static int putCallback(processNotify *ppn,notifyPutType type) { + tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt; + int status = 0; + + if(ppn->status==notifyCanceled) return 0; + ppn->status = notifyOK; + switch(type) { + case putDisabledType: + ppn->status = notifyError; + return 0; + case putFieldType: + status = dbPutField(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue,1); + break; + case putType: + status = dbPut(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue,1); + break; + } + if(status!=0) ppn->status = notifyError; + return 1; +} + +static void getCallback(processNotify *ppn,notifyGetType type) { - putNotifyStatus status = ppn->status; + tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt; + int status = 0; + long no_elements = 1; + long options = 0; + + if(ppn->status==notifyCanceled) { + printf("dbtpn:getCallback notifyCanceled\n"); + return; + } + switch(type) { + case getFieldType: + status = dbGetField(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue, + &options,&no_elements,0); + break; + case getType: + status = dbGet(ppn->paddr,DBR_STRING,ptpnInfo->psavevalue, + &options,&no_elements,0); + break; + } + if(status!=0) { + ppn->status = notifyError; + printf("dbtpn:getCallback error\n"); + } else { + printf("dbtpn:getCallback value %s\n",ptpnInfo->psavevalue); + } +} + +static void doneCallback(processNotify *ppn) +{ + notifyStatus status = ppn->status; tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt; if(status==0) printf("dbtpnCallback: success record=%s\n",ppn->paddr->precord->name); else - printf("%s dbtpnCallback putNotify.status %d\n",ppn->paddr->precord->name,(int)status); + printf("%s dbtpnCallback processNotify.status %d\n",ppn->paddr->precord->name,(int)status); epicsEventSignal(ptpnInfo->callbackDone); } static void tpnThread(void *pvt) { tpnInfo *ptpnInfo = (tpnInfo *)pvt; - putNotify *ppn = (putNotify *)ptpnInfo->ppn; + processNotify *ppn = (processNotify *)ptpnInfo->ppn; - dbPutNotify(ppn); + dbProcessNotify(ppn); epicsEventWait(ptpnInfo->callbackDone); dbNotifyCancel(ppn); epicsEventDestroy(ptpnInfo->callbackDone); @@ -488,30 +562,35 @@ long epicsShareAPI dbtpn(char *pname,char *pvalue) long status; tpnInfo *ptpnInfo; DBADDR *pdbaddr=NULL; - putNotify *ppn=NULL; + processNotify *ppn=NULL; char *psavevalue; - int len; + int len = 80; - len = strlen(pvalue); + if(pvalue) len = strlen(pvalue); /*allocate space for value immediately following DBADDR*/ pdbaddr = dbCalloc(1,sizeof(DBADDR) + len+1); psavevalue = (char *)(pdbaddr + 1); - strcpy(psavevalue,pvalue); + if(pvalue) strcpy(psavevalue,pvalue); status = dbNameToAddr(pname,pdbaddr); if(status) { errMessage(status, "dbtpn: dbNameToAddr"); free((void *)pdbaddr); return(-1); } - ppn = dbCalloc(1,sizeof(putNotify)); + ppn = dbCalloc(1,sizeof(processNotify)); + if(pvalue) { + ppn->requestType = putProcessRequest; + } else { + ppn->requestType = processGetRequest; + } ppn->paddr = pdbaddr; - ppn->pbuffer = psavevalue; - ppn->nRequest = 1; - ppn->dbrType = DBR_STRING; - ppn->userCallback = dbtpnCallback; + ppn->putCallback = putCallback; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; ptpnInfo = dbCalloc(1,sizeof(tpnInfo)); ptpnInfo->ppn = ppn; ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty); + ptpnInfo->psavevalue = psavevalue; ppn->usrPvt = ptpnInfo; epicsThreadCreate("dbtpn",epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), @@ -525,49 +604,50 @@ int epicsShareAPI dbNotifyDump(void) dbRecordType *pdbRecordType; dbRecordNode *pdbRecordNode; dbCommon *precord; - putNotify *ppn; - putNotify *ppnRestart; - putNotifyRecord *ppnrWait; + processNotify *ppn; + processNotify *ppnRestart; + processNotifyRecord *ppnr; int itry; - - - for(itry=0; itry<100; itry++) { + + for (itry=0; itry<100; itry++) { lockStatus = epicsMutexTryLock(pnotifyGlobal->lock); if(lockStatus==epicsMutexLockOK) break; epicsThreadSleep(.05); } - for(pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); + for (pdbRecordType = (dbRecordType *)ellFirst(&pdbbase->recordTypeList); pdbRecordType; pdbRecordType = (dbRecordType *)ellNext(&pdbRecordType->node)) { for (pdbRecordNode=(dbRecordNode *)ellFirst(&pdbRecordType->recList); pdbRecordNode; pdbRecordNode = (dbRecordNode *)ellNext(&pdbRecordNode->node)) { - putNotifyPvt *pputNotifyPvt; + notifyPvt *pnotifyPvt; precord = pdbRecordNode->precord; - if (!precord->name[0] || - pdbRecordNode->flags & DBRN_FLAGS_ISALIAS) - continue; - if(!precord->ppn) continue; - if(!precord->ppnr) continue; - if(precord->ppn->paddr->precord != precord) continue; ppn = precord->ppn; - pputNotifyPvt = (putNotifyPvt *)ppn->pputNotifyPvt; - printf("%s state %d ppn %p\n waitList\n", - precord->name,pputNotifyPvt->state,(void*)ppn); - ppnrWait = (putNotifyRecord *)ellFirst(&pputNotifyPvt->waitList); - while(ppnrWait) { - printf(" %s pact %d\n", - ppnrWait->precord->name,ppnrWait->precord->pact); - ppnrWait = (putNotifyRecord *)ellNext(&ppnrWait->waitNode.node); + if (ppn) { + pnotifyPvt = (notifyPvt *)ppn->pnotifyPvt; + printf("%s state %d ppn %p\n waitList\n", + precord->name,pnotifyPvt->state,(void*)ppn); + ppnr = (processNotifyRecord *)ellFirst(&pnotifyPvt->waitList); + while (ppnr) { + printf(" %s pact %d\n", + ppnr->precord->name,ppnr->precord->pact); + ppnr = (processNotifyRecord *)ellNext( + &ppnr->waitNode.node); + } } - printf(" restartList\n"); - ppnRestart = (putNotify *)ellFirst(&precord->ppnr->restartList); - while(ppnRestart) { - printf(" %p\n", (void *)ppnRestart); - ppnRestart = (putNotify *)ellNext(&ppnRestart->restartNode.node); + ppnr = precord->ppnr; + if (ppnr) { + ppnRestart = (processNotify *)ellFirst( + &precord->ppnr->restartList); + if (ppnRestart) printf("%s restartList\n",precord->name); + while (ppnRestart) { + printf(" %s\n",ppnRestart->paddr->precord->name); + ppnRestart = (processNotify *)ellNext( + &ppnRestart->restartNode.node); + } } } } if(lockStatus==epicsMutexLockOK) epicsMutexUnlock(pnotifyGlobal->lock); - return(0); + return 0; } diff --git a/src/ioc/db/dbNotify.h b/src/ioc/db/dbNotify.h index 5c57c0d90..4812368b5 100644 --- a/src/ioc/db/dbNotify.h +++ b/src/ioc/db/dbNotify.h @@ -20,7 +20,7 @@ #ifdef __cplusplus /* for brain dead C++ compilers */ struct dbCommon; - struct putNotify; + struct processNotify; extern "C" { #endif @@ -30,36 +30,54 @@ typedef struct ellCheckNode{ }ellCheckNode; typedef enum { - putNotifyOK, - putNotifyCanceled, - putNotifyError, - putNotifyPutDisabled -}putNotifyStatus; + processRequest, + putProcessRequest, + processGetRequest, + putProcessGetRequest +}notifyRequestType; -typedef struct putNotify{ + +typedef enum { + putDisabledType, + putFieldType, + putType +}notifyPutType; + +typedef enum { + getFieldType, + getType +}notifyGetType; + +typedef enum { + notifyOK, + notifyCanceled, + notifyError, + notifyPutDisabled +}notifyStatus; + +typedef struct processNotify { + /* following fields are for private use by dbNotify implementation */ ellCheckNode restartNode; - /*The following members MUST be set by user*/ - void (*userCallback)(struct putNotify *); + void *pnotifyPvt; /*for private use of dbNotify*/ + /* The following fields are set by dbNotify. */ + notifyStatus status; + int wasProcessed; /* (0,1) => (no,yes) */ + /*The following members are set by user*/ + notifyRequestType requestType; struct dbAddr *paddr; /*dbAddr set by dbNameToAddr*/ - void *pbuffer; /*address of data*/ - long nRequest; /*number of elements to be written*/ - short dbrType; /*database request type*/ - void *usrPvt; /*for private use of user*/ - /*The following is status of request. Set by dbNotify */ - putNotifyStatus status; - void *pputNotifyPvt; /*for private use of putNotify*/ -}putNotify; + int (*putCallback)(struct processNotify *,notifyPutType type); + void (*getCallback)(struct processNotify *,notifyGetType type); + void (*doneCallback)(struct processNotify *); + void *usrPvt; /*for private use of user*/ +}processNotify; -/* dbPutNotify and dbNotifyCancel are the routines called by user*/ -/* The user is normally channel access client or server */ -epicsShareFunc void epicsShareAPI dbPutNotify(putNotify *pputNotify); -epicsShareFunc void epicsShareAPI dbNotifyCancel(putNotify *pputNotify); -/*dbPutNotifyMapType convience function for old database access*/ -epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype); +/* dbProcessNotify and dbNotifyCancel are called by user*/ +epicsShareFunc void epicsShareAPI dbProcessNotify(processNotify *pprocessNotify); +epicsShareFunc void epicsShareAPI dbNotifyCancel(processNotify *pprocessNotify); -/* dbPutNotifyInit called by iocInit */ -epicsShareFunc void epicsShareAPI dbPutNotifyInit(void); +/* dbProcessNotifyInit called by iocInit */ +epicsShareFunc void epicsShareAPI dbProcessNotifyInit(void); /*dbNotifyAdd called by dbScanPassive and dbScanLink*/ epicsShareFunc void epicsShareAPI dbNotifyAdd( @@ -67,29 +85,61 @@ epicsShareFunc void epicsShareAPI dbNotifyAdd( /*dbNotifyCompletion called by recGblFwdLink or dbAccess*/ epicsShareFunc void epicsShareAPI dbNotifyCompletion(struct dbCommon *precord); -/* dbtpn is test routine for put notify */ +/* db_put_process defined here since it requires dbNotify. + * src_type is the old DBR type + * This is called by a dbNotify putCallback that uses oldDbr types + */ +epicsShareFunc int epicsShareAPI db_put_process( + processNotify *processNotify,notifyPutType type, + int src_type,const void *psrc, int no_elements); + +/* dbtpn is test routine for dbNotify putProcessRequest */ epicsShareFunc long epicsShareAPI dbtpn(char *recordname,char *value); + /* dbNotifyDump is an INVASIVE debug utility. Dont use this needlessly*/ epicsShareFunc int epicsShareAPI dbNotifyDump(void); -/* This module provides code to handle put notify. If a put causes a record to - * be processed, then a user supplied callback is called when that record - * and all records processed because of that record complete processing. - * For asynchronous records completion means completion of the asyn phase. +/* This module provides code to handle process notify. + * client code semantics are: + * 1) The client code allocates storage for a processNotify structure. + * This structure can be used for multiple calls to dbProcessNotify. + * The client is responsible for setting the following fields : + * requestType - The type of request. + * paddr - This is typically set via a call to dbNameToAddr. + * putCallback - If requestType is putProcessRequest or putProcessGetRequest + * getCallback - If request is processGetRequest or putProcessGetRequest + * doneCallback - Must be set + * usrPvt - For exclusive use of client. dbNotify does not access this field + * 2) The client calls dbProcessNotify. + * 3) putCallback is called after dbNotify has claimed the record instance + * but before a potential process is requested. + * The putCallback MUST issue the correct put request + * specified by notifyPutType + * 4) getCallback is called after a possible process is complete + * (including asynchronous completion) but before dbNotify has + * released the record. + * The getCallback MUST issue the correct get request + * specified by notifyGetType + * 5) doneCallback is called when dbNotify has released the record. + * The client can issue a new dbProcessNotify request from + * doneCallback or anytime after doneCallback returns. + * 6) The client can call dbNotifyCancel at any time. + * If a dbProcessNotify is active, dbNotifyCancel will not return until + * the dbNotifyRequest is actually canceled. The client must be prepared + * for a callback to be called while dbNotifyCancel is active. * - * User code calls putNotifyInit, putNotifyCleanup, - * dbPutNotify, and dbNotifyCancel. + * dbProcessNotify handles the semantics of record locking and deciding + * if a process request is issued and also calls the client callbacks. * - * The use must allocate storage for "struct putNotify" - * The user MUST set pputNotifyPvt=0 before the first call to dbPutNotify - * and should never modify it again. + * A process request is issued if any of the following is true. + * 1) The requester has issued a processs request and record is passive. + * 2) The requester is doing a put, the record is passive, and either + * a) The field description is process passive. + * b) The field is PROC. + * 3) The requester has requested processGet and the record is passive. * - * After dbPutNotify is called it may not called for the same putNotify - * until the putCallback is complete. The use can call dbNotifyCancel - * to cancel the operation. - * - * The user callback is called when the operation is completed. + * iocInit calls processNotifyInit. * * The other global routines (dbNotifyAdd and dbNotifyCompletion) are called by: * @@ -101,19 +151,16 @@ epicsShareFunc int epicsShareAPI dbNotifyDump(void); * Unless pact is already true. * recGbl * recGblFwdLink calls dbNotifyCompletion - */ - -/* Two fields in dbCommon are used for put notify. - * ppn pointer to putNotify - * If a record is part of a put notify group, - * This field is the address of the associated putNotify. - * As soon as a record completes processing the field is set NULL - * ppnr pointer to putNotifyRecord - * Address of a putNotifyRecord for 1) list node for records - * put notify is waiting to complete, and 2) a list of records - * to restart. * - * See the Application Developer's Guide for implementation rules + * Two fields in dbCommon are used for put notify. + * ppn pointer to processNotify + * If a record is part of a put notify group, + * This field is the address of the associated processNotify. + * As soon as a record completes processing the field is set NULL + * ppnr pointer to processNotifyRecord, which is a private structure + * owned by dbNotify. + * dbNotify is reponsible for this structure. + * */ #ifdef __cplusplus } diff --git a/src/ioc/db/dbPutNotifyBlocker.cpp b/src/ioc/db/dbPutNotifyBlocker.cpp index e91234b67..c47f1da99 100644 --- a/src/ioc/db/dbPutNotifyBlocker.cpp +++ b/src/ioc/db/dbPutNotifyBlocker.cpp @@ -52,7 +52,7 @@ dbPutNotifyBlocker::dbPutNotifyBlocker ( epicsMutex & mutexIn ) : { memset ( & this->pn, '\0', sizeof ( this->pn ) ); memset ( & this->dbrScalarValue, '\0', sizeof ( this->dbrScalarValue ) ); - this->pn.pbuffer = & this->dbrScalarValue; + this->pbuffer = & this->dbrScalarValue; } dbPutNotifyBlocker::~dbPutNotifyBlocker () @@ -64,7 +64,7 @@ void dbPutNotifyBlocker::destructor ( epicsGuard < epicsMutex > & guard ) guard.assertIdenticalMutex ( this->mutex ); this->cancel ( guard ); if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) { - char * pBuf = static_cast < char * > ( this->pn.pbuffer ); + char * pBuf = static_cast < char * > ( this->pbuffer ); delete [] pBuf; } this->~dbPutNotifyBlocker (); @@ -88,17 +88,29 @@ void dbPutNotifyBlocker::expandValueBuf ( guard.assertIdenticalMutex ( this->mutex ); if ( this->maxValueSize < newSize ) { if ( this->maxValueSize > sizeof ( this->dbrScalarValue ) ) { - char * pBuf = static_cast < char * > ( this->pn.pbuffer ); + char * pBuf = static_cast < char * > ( this->pbuffer ); delete [] pBuf; this->maxValueSize = sizeof ( this->dbrScalarValue ); - this->pn.pbuffer = & this->dbrScalarValue; + this->pbuffer = & this->dbrScalarValue; } - this->pn.pbuffer = new char [newSize]; + this->pbuffer = new char [newSize]; this->maxValueSize = newSize; } } -extern "C" void putNotifyCompletion ( putNotify *ppn ) +extern "C" int putNotifyPut ( processNotify *ppn, notifyPutType type ) +{ + if(ppn->status==notifyCanceled) return 0; +/* + * No locking in this method because only a dbNotifyCancel could interrupt + * and it does not return until cancel is done. + */ + dbPutNotifyBlocker * pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt ); + return db_put_process(ppn,type, + pBlocker->dbrType,pBlocker->pbuffer,pBlocker->nRequest); +} + +extern "C" void putNotifyCompletion ( processNotify *ppn ) { dbPutNotifyBlocker * const pBlocker = static_cast < dbPutNotifyBlocker * > ( ppn->usrPvt ); @@ -112,11 +124,11 @@ extern "C" void putNotifyCompletion ( putNotify *ppn ) // unavoidable because its possible that the use callback // might destroy this object. pBlocker->block.signal (); - if ( pBlocker->pn.status != putNotifyOK ) { + if ( pBlocker->pn.status != notifyOK ) { pNtfy->exception ( guard, ECA_PUTFAIL, "put notify unsuccessful", - static_cast < unsigned > (pBlocker->pn.dbrType), - static_cast < unsigned > (pBlocker->pn.nRequest) ); + static_cast < unsigned > (pBlocker->dbrType), + static_cast < unsigned > (pBlocker->nRequest) ); } else { pNtfy->completion ( guard ); @@ -163,25 +175,21 @@ void dbPutNotifyBlocker::initiatePutNotify ( throw cacChannel::badType(); } - int status = dbPutNotifyMapType ( - &this->pn, static_cast ( type ) ); - if ( status ) { - this->pNotify = 0; - throw cacChannel::badType(); - } - - this->pn.nRequest = static_cast < unsigned > ( count ); + this->dbrType = type; + this->nRequest = static_cast < unsigned > ( count ); + this->pn.requestType = putProcessRequest; this->pn.paddr = &addr; - this->pn.userCallback = putNotifyCompletion; + this->pn.putCallback = putNotifyPut; + this->pn.doneCallback = putNotifyCompletion; this->pn.usrPvt = this; unsigned long size = dbr_size_n ( type, count ); this->expandValueBuf ( guard, size ); - memcpy ( this->pn.pbuffer, pValue, size ); + memcpy ( this->pbuffer, pValue, size ); { epicsGuardRelease < epicsMutex > autoRelease ( guard ); - ::dbPutNotify ( &this->pn ); + ::dbProcessNotify ( &this->pn ); } } diff --git a/src/ioc/db/dbPutNotifyBlocker.h b/src/ioc/db/dbPutNotifyBlocker.h index da2cc9fcb..1512977a3 100644 --- a/src/ioc/db/dbPutNotifyBlocker.h +++ b/src/ioc/db/dbPutNotifyBlocker.h @@ -54,7 +54,7 @@ public: epicsPlacementDeleteOperator (( void *, tsFreeList < dbPutNotifyBlocker, 64, epicsMutexNOOP > & )) private: - putNotify pn; + processNotify pn; // // Include a union of all scalar types // including fixed length strings so @@ -75,10 +75,16 @@ private: epicsMutex & mutex; cacWriteNotify * pNotify; unsigned long maxValueSize; + // arguments for db_put_field + void *pbuffer; + long nRequest; + short dbrType; + // end arguments for db_put_field dbSubscriptionIO * isSubscription (); void expandValueBuf ( epicsGuard < epicsMutex > &, unsigned long newSize ); - friend void putNotifyCompletion ( putNotify * ppn ); + friend void putNotifyCompletion ( processNotify * ppn ); + friend int putNotifyPut ( processNotify *ppn, notifyPutType type ); dbPutNotifyBlocker ( const dbPutNotifyBlocker & ); dbPutNotifyBlocker & operator = ( const dbPutNotifyBlocker & ); virtual ~dbPutNotifyBlocker (); diff --git a/src/ioc/db/db_access.c b/src/ioc/db/db_access.c index 5596f1a0e..af7a9b31b 100644 --- a/src/ioc/db/db_access.c +++ b/src/ioc/db/db_access.c @@ -994,39 +994,61 @@ int epicsShareAPI db_put_field(struct dbAddr *paddr, int src_type, } -epicsShareFunc int epicsShareAPI dbPutNotifyMapType (putNotify *ppn, short oldtype) +static int mapOldType (short oldtype) { - switch(oldtype) { - case(oldDBR_STRING): - ppn->dbrType = DBR_STRING; + int dbrType = -1; + + switch (oldtype) { + case oldDBR_STRING: + dbrType = DBR_STRING; break; -/* case(oldDBR_INT): */ - case(oldDBR_SHORT): - ppn->dbrType = DBR_SHORT; +/* case oldDBR_INT: */ + case oldDBR_SHORT: + dbrType = DBR_SHORT; break; - case(oldDBR_FLOAT): - ppn->dbrType = DBR_FLOAT; + case oldDBR_FLOAT: + dbrType = DBR_FLOAT; break; - case(oldDBR_ENUM): - ppn->dbrType = DBR_ENUM; + case oldDBR_ENUM: + dbrType = DBR_ENUM; break; - case(oldDBR_CHAR): - ppn->dbrType = DBR_UCHAR; + case oldDBR_CHAR: + dbrType = DBR_UCHAR; break; - case(oldDBR_LONG): - ppn->dbrType = DBR_LONG; + case oldDBR_LONG: + dbrType = DBR_LONG; break; - case(oldDBR_DOUBLE): - ppn->dbrType = DBR_DOUBLE; + case oldDBR_DOUBLE: + dbrType = DBR_DOUBLE; break; - case(oldDBR_PUT_ACKT): - ppn->dbrType = DBR_PUT_ACKT; + case oldDBR_PUT_ACKT: + dbrType = DBR_PUT_ACKT; break; - case(oldDBR_PUT_ACKS): - ppn->dbrType = DBR_PUT_ACKS; + case oldDBR_PUT_ACKS: + dbrType = DBR_PUT_ACKS; break; default: return -1; } - return 0; + return dbrType; +} + +int epicsShareAPI db_put_process(processNotify *ppn, notifyPutType type, + int src_type, const void *psrc, int no_elements) +{ + int status = 0; + int dbrType = mapOldType(src_type); + switch(type) { + case putDisabledType: + ppn->status = notifyError; + return 0; + case putFieldType: + status = dbPutField(ppn->paddr,dbrType,psrc,no_elements); + break; + case putType: + status = dbPut(ppn->paddr,dbrType,psrc,no_elements); + break; + } + if (status) ppn->status = notifyError; + return 1; } diff --git a/src/ioc/db/db_test.c b/src/ioc/db/db_test.c index 5f44e28ca..8ea2cd66c 100644 --- a/src/ioc/db/db_test.c +++ b/src/ioc/db/db_test.c @@ -637,29 +637,36 @@ static void print_returned(type,count,pbuffer) typedef struct tpnInfo { epicsEventId callbackDone; - putNotify *ppn; + processNotify *ppn; + char *psavevalue; }tpnInfo; -static void tpnCallback(putNotify *ppn) + +static int putCallback(processNotify *ppn,notifyPutType type) { + tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt; + + return db_put_process(ppn,type,DBR_STRING,ptpnInfo->psavevalue,1); +} + +static void doneCallback(processNotify *ppn) { - struct dbAddr *pdbaddr = (struct dbAddr *)ppn->paddr; + notifyStatus status = ppn->status; tpnInfo *ptpnInfo = (tpnInfo *)ppn->usrPvt; - putNotifyStatus status = ppn->status; - char *pname = pdbaddr->precord->name; + char *pname = ppn->paddr->precord->name; if(status==0) - printf("tpnCallback: success record=%s\n",pname); + printf("tpnCallback: success record=%s\n",pname); else - printf("%s tpnCallback status = %d\n",pname,status); + printf("%s tpnCallback processNotify.status %d\n",pname,(int)status); epicsEventSignal(ptpnInfo->callbackDone); } static void tpnThread(void *pvt) { tpnInfo *ptpnInfo = (tpnInfo *)pvt; - putNotify *ppn = (putNotify *)ptpnInfo->ppn; + processNotify *ppn = (processNotify *)ptpnInfo->ppn; - dbPutNotify(ppn); + dbProcessNotify(ppn); epicsEventWait(ptpnInfo->callbackDone); dbNotifyCancel(ppn); epicsEventDestroy(ptpnInfo->callbackDone); @@ -674,7 +681,7 @@ int epicsShareAPI tpn(char *pname,char *pvalue) long status; tpnInfo *ptpnInfo; struct dbAddr *pdbaddr=NULL; - putNotify *ppn=NULL; + processNotify *ppn=NULL; char *psavevalue; int len; @@ -699,20 +706,15 @@ int epicsShareAPI tpn(char *pname,char *pvalue) free((void *)pdbaddr); return(-1); } - ppn = calloc(1,sizeof(putNotify)); - if(!pdbaddr) { + ppn = calloc(1,sizeof(processNotify)); + if(!ppn) { printf("calloc failed\n"); return(-1); } + ppn->requestType = putProcessRequest; ppn->paddr = pdbaddr; - ppn->pbuffer = psavevalue; - ppn->nRequest = 1; - if(dbPutNotifyMapType(ppn,DBR_STRING)) { - printf("dbPutNotifyMapType failed\n"); - printf("calloc failed\n"); - return(-1); - } - ppn->userCallback = tpnCallback; + ppn->putCallback = putCallback; + ppn->doneCallback = doneCallback; ptpnInfo = calloc(1,sizeof(tpnInfo)); if(!ptpnInfo) { printf("calloc failed\n"); @@ -720,6 +722,7 @@ int epicsShareAPI tpn(char *pname,char *pvalue) } ptpnInfo->ppn = ppn; ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty); + ptpnInfo->psavevalue = psavevalue; ppn->usrPvt = ptpnInfo; epicsThreadCreate("tpn",epicsThreadPriorityHigh, epicsThreadGetStackSize(epicsThreadStackMedium), diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 9f9c1a385..b394bec50 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -140,7 +140,7 @@ int iocBuild(void) errlogPrintf("iocBuild: asInit Failed.\n"); return -1; } - dbPutNotifyInit(); + dbProcessNotifyInit(); epicsThreadSleep(.5); initHookAnnounce(initHookAfterScanInit); diff --git a/src/ioc/rsrv/camessage.c b/src/ioc/rsrv/camessage.c index 09015f667..02ed285a1 100644 --- a/src/ioc/rsrv/camessage.c +++ b/src/ioc/rsrv/camessage.c @@ -57,7 +57,7 @@ logBadIdWithFileAndLineno(CLIENT, MP, PPL, __FILE__, __LINE__) */ typedef struct rsrv_put_notify { ELLNODE node; - putNotify dbPutNotify; + processNotify dbPutNotify; caHdrLargeArray msg; /* * Include a union of all scalar types @@ -77,8 +77,13 @@ typedef struct rsrv_put_notify { dbr_long_t longval; dbr_double_t doubleval; } dbrScalarValue; + /* arguments for db_put_field */ + void *pbuffer; + long nRequest; + short dbrType; + /* end arguments for db_put_field */ void * asWritePvt; - unsigned valueSize; /* size of block pointed to by dbPutNotify */ + unsigned valueSize; /* size of block pointed to by pbuffer */ char busy; /* put notify in progress */ char onExtraLaborQueue; } RSRVPUTNOTIFY; @@ -1390,11 +1395,33 @@ static int claim_ciu_action ( caHdrLargeArray *mp, } /* - * write_notify_call_back() - * - * (called by the db call back thread) - */ -static void write_notify_call_back(putNotify *ppn) + * write_notify_put_callback() + * + * (called by the db call back thread) + */ + LOCAL int write_notify_put_callback(processNotify *ppn,notifyPutType type) + { + struct channel_in_use * pciu = (struct channel_in_use *) ppn->usrPvt; + struct rsrv_put_notify *pNotify; + + if(ppn->status==notifyCanceled) return 0; + /* + * No locking in this method because only a dbNotifyCancel could interrupt + * and it does not return until cancel is done. + */ + assert(pciu); + assert(pciu->pPutNotify); + pNotify = pciu->pPutNotify; + return db_put_process(ppn,type, + pNotify->dbrType,pNotify->pbuffer,pNotify->nRequest); + } + + /* + * write_notify_done_callback() + * + * (called by the db call back thread) + */ + LOCAL void write_notify_done_callback(processNotify *ppn) { struct channel_in_use * pciu = (struct channel_in_use *) ppn->usrPvt; struct client * pClient; @@ -1460,7 +1487,7 @@ static void write_notify_reply ( struct client * pClient ) * Map from DB status to CA status * */ - if ( ppnb->dbPutNotify.status != putNotifyOK ) { + if ( ppnb->dbPutNotify.status != notifyOK ) { status = ECA_PUTFAIL; } else{ @@ -1593,14 +1620,17 @@ static struct rsrv_put_notify * pNotify = (RSRVPUTNOTIFY *) freeListCalloc ( rsrvPutNotifyFreeList ); if ( pNotify ) { - pNotify->dbPutNotify.pbuffer = + pNotify->pbuffer = &pNotify->dbrScalarValue; pNotify->valueSize = sizeof (pNotify->dbrScalarValue); pNotify->dbPutNotify.usrPvt = pciu; pNotify->dbPutNotify.paddr = &pciu->addr; - pNotify->dbPutNotify.userCallback = - write_notify_call_back; + pNotify->dbPutNotify.putCallback = + write_notify_put_callback; + pNotify->dbPutNotify.doneCallback = + write_notify_done_callback; + pNotify->dbPutNotify.requestType = putProcessRequest; } } else { @@ -1622,10 +1652,10 @@ static int rsrvExpandPutNotify ( */ if ( pNotify->valueSize > sizeof (pNotify->dbrScalarValue) ) { - free ( pNotify->dbPutNotify.pbuffer ); + free ( pNotify->pbuffer ); } - pNotify->dbPutNotify.pbuffer = casCalloc(1,sizeNeeded); - if ( pNotify->dbPutNotify.pbuffer ) { + pNotify->pbuffer = casCalloc(1,sizeNeeded); + if ( pNotify->pbuffer ) { pNotify->valueSize = sizeNeeded; booleanStatus = TRUE; } @@ -1633,7 +1663,7 @@ static int rsrvExpandPutNotify ( /* * revert back to the embedded union */ - pNotify->dbPutNotify.pbuffer = + pNotify->pbuffer = &pNotify->dbrScalarValue; pNotify->valueSize = sizeof (pNotify->dbrScalarValue); @@ -1694,7 +1724,7 @@ void rsrvFreePutNotify ( client *pClient, if ( pNotify->valueSize > sizeof(pNotify->dbrScalarValue) ) { - free ( pNotify->dbPutNotify.pbuffer ); + free ( pNotify->pbuffer ); } freeListFree ( rsrvPutNotifyFreeList, pNotify ); } @@ -1768,7 +1798,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload, if ( busyTmp ) { log_header("put call back time out", client, - &pciu->pPutNotify->msg, pciu->pPutNotify->dbPutNotify.pbuffer, 0); + &pciu->pPutNotify->msg, pciu->pPutNotify->pbuffer, 0); asTrapWriteAfter ( asWritePvtTmp ); putNotifyErrorReply (client, &pciu->pPutNotify->msg, ECA_PUTCBINPROG); } @@ -1801,10 +1831,10 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload, pciu->pPutNotify->busy = TRUE; pciu->pPutNotify->onExtraLaborQueue = FALSE; pciu->pPutNotify->msg = *mp; - pciu->pPutNotify->dbPutNotify.nRequest = mp->m_count; + pciu->pPutNotify->nRequest = mp->m_count; status = caNetConvert ( - mp->m_dataType, pPayload, pciu->pPutNotify->dbPutNotify.pbuffer, + mp->m_dataType, pPayload, pciu->pPutNotify->pbuffer, FALSE /* net -> host format */, mp->m_count ); if ( status != ECA_NORMAL ) { log_header ("invalid data type", client, mp, pPayload, 0); @@ -1812,12 +1842,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload, return RSRV_ERROR; } - status = dbPutNotifyMapType(&pciu->pPutNotify->dbPutNotify, mp->m_dataType); - if(status){ - putNotifyErrorReply (client, mp, ECA_PUTFAIL); - pciu->pPutNotify->busy = FALSE; - return RSRV_OK; - } + pciu->pPutNotify->dbrType = mp->m_dataType; pciu->pPutNotify->asWritePvt = asTrapWriteBefore ( pciu->asClientPVT, @@ -1825,7 +1850,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload, pciu->client->pHostName ? pciu->client->pHostName : "", (void *) &pciu->addr ); - dbPutNotify(&pciu->pPutNotify->dbPutNotify); + dbProcessNotify(&pciu->pPutNotify->dbPutNotify); return RSRV_OK; } diff --git a/src/std/dev/Makefile b/src/std/dev/Makefile index a118f7057..0e3fac9e2 100644 --- a/src/std/dev/Makefile +++ b/src/std/dev/Makefile @@ -42,6 +42,12 @@ dbRecStd_SRCS += devSoSoft.c dbRecStd_SRCS += devWfSoft.c dbRecStd_SRCS += devGeneralTime.c +dbRecStd_SRCS += devAiSoftCallback.c +dbRecStd_SRCS += devBiSoftCallback.c +dbRecStd_SRCS += devLiSoftCallback.c +dbRecStd_SRCS += devMbbiSoftCallback.c +dbRecStd_SRCS += devSiSoftCallback.c + dbRecStd_SRCS += devAoSoftCallback.c dbRecStd_SRCS += devBoSoftCallback.c dbRecStd_SRCS += devCalcoutSoftCallback.c diff --git a/src/std/dev/devAiSoftCallback.c b/src/std/dev/devAiSoftCallback.c new file mode 100644 index 000000000..560f518e1 --- /dev/null +++ b/src/std/dev/devAiSoftCallback.c @@ -0,0 +1,155 @@ +/*************************************************************************\ +* 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 is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* devAiSoftCallback.c */ +/* + * Author: Marty Kraimer + * Date: 23APR2008 + */ + +#include +#include +#include + +#include "alarm.h" +#include "callback.h" +#include "cantProceed.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "dbNotify.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "aiRecord.h" +#include "epicsExport.h" + +/* Create the dset for devAiSoftCallback */ +static long init_record(); +static long read_ai(); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_ai; + DEVSUPFUN special_linconv; +}devAiSoftCallback={ + 6, + NULL, + NULL, + init_record, + NULL, + read_ai, + NULL}; +epicsExportAddress(dset,devAiSoftCallback); + +typedef struct notifyInfo { + processNotify *ppn; + CALLBACK *pcallback; + double value; + int status; +}notifyInfo; + +static void getCallback(processNotify *ppn,notifyGetType type) +{ + struct aiRecord *pai = (struct aiRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pai->dpvt; + int status = 0; + long no_elements = 1; + long options = 0; + + if(ppn->status==notifyCanceled) { + printf("dbtpn:getCallback notifyCanceled\n"); + return; + } + switch(type) { + case getFieldType: + status = dbGetField(ppn->paddr,DBR_DOUBLE,&pnotifyInfo->value, + &options,&no_elements,0); + break; + case getType: + status = dbGet(ppn->paddr,DBR_DOUBLE,&pnotifyInfo->value, + &options,&no_elements,0); + break; + } + pnotifyInfo->status = status; +} + +static void doneCallback(processNotify *ppn) +{ + struct aiRecord *pai = (struct aiRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pai->dpvt; + + callbackRequestProcessCallback(pnotifyInfo->pcallback,pai->prio,pai); +} + + +static long init_record(struct aiRecord *pai) +{ + DBLINK *plink = &pai->inp; + struct instio *pinstio; + char *pvname; + DBADDR *pdbaddr=NULL; + long status; + notifyInfo *pnotifyInfo; + CALLBACK *pcallback; + processNotify *ppn=NULL; + + if(plink->type!=INST_IO) { + recGblRecordError(S_db_badField,(void *)pai, + "devAiSoftCallback (init_record) Illegal INP field"); + pai->pact=TRUE; + return(S_db_badField); + } + pinstio=(struct instio*)&(plink->value); + pvname = pinstio->string; + pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr), + "devAiSoftCallback::init_record"); + status = dbNameToAddr(pvname,pdbaddr); + if(status) { + recGblRecordError(status,(void *)pai, + "devAiSoftCallback (init_record) linked record not found"); + pai->pact=TRUE; + return(status); + } + pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo), + "devAiSoftCallback::init_record"); + pcallback = callocMustSucceed(1, sizeof(*pcallback), + "devAiSoftCallback::init_record"); + ppn = callocMustSucceed(1, sizeof(*ppn), + "devAiSoftCallback::init_record"); + pnotifyInfo->ppn = ppn; + pnotifyInfo->pcallback = pcallback; + ppn->usrPvt = pai; + ppn->paddr = pdbaddr; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; + ppn->requestType = processGetRequest; + pai->dpvt = pnotifyInfo; + return 0; +} + +static long read_ai(aiRecord *pai) +{ + notifyInfo *pnotifyInfo = (notifyInfo *)pai->dpvt; + + if(pai->pact) { + if(pnotifyInfo->status) { + recGblSetSevr(pai,READ_ALARM,INVALID_ALARM); + return(2); + } + pai->val = pnotifyInfo->value; + pai->udf = FALSE; + return(2); + } + dbProcessNotify(pnotifyInfo->ppn); + pai->pact = TRUE; + return(0); +} diff --git a/src/std/dev/devBiSoftCallback.c b/src/std/dev/devBiSoftCallback.c new file mode 100644 index 000000000..8e6a67432 --- /dev/null +++ b/src/std/dev/devBiSoftCallback.c @@ -0,0 +1,155 @@ +/*************************************************************************\ +* 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 is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* devBiSoftCallback.c */ +/* + * Author: Marty Kraimer + * Date: 23APR2008 + */ + +#include +#include +#include + +#include "alarm.h" +#include "callback.h" +#include "cantProceed.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "dbNotify.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "biRecord.h" +#include "epicsExport.h" + +/* Create the dset for devBiSoftCallback */ +static long init_record(); +static long read_bi(); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_bi; + DEVSUPFUN special_linconv; +}devBiSoftCallback={ + 6, + NULL, + NULL, + init_record, + NULL, + read_bi, + NULL}; +epicsExportAddress(dset,devBiSoftCallback); + +typedef struct notifyInfo { + processNotify *ppn; + CALLBACK *pcallback; + unsigned short value; + int status; +}notifyInfo; + +static void getCallback(processNotify *ppn,notifyGetType type) +{ + struct biRecord *pbi = (struct biRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pbi->dpvt; + int status = 0; + long no_elements = 1; + long options = 0; + + if(ppn->status==notifyCanceled) { + printf("dbtpn:getCallback notifyCanceled\n"); + return; + } + switch(type) { + case getFieldType: + status = dbGetField(ppn->paddr,DBR_USHORT,&pnotifyInfo->value, + &options,&no_elements,0); + break; + case getType: + status = dbGet(ppn->paddr,DBR_USHORT,&pnotifyInfo->value, + &options,&no_elements,0); + break; + } + pnotifyInfo->status = status; +} + +static void doneCallback(processNotify *ppn) +{ + struct biRecord *pbi = (struct biRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pbi->dpvt; + + callbackRequestProcessCallback(pnotifyInfo->pcallback,pbi->prio,pbi); +} + + +static long init_record(struct biRecord *pbi) +{ + DBLINK *plink = &pbi->inp; + struct instio *pinstio; + char *pvname; + DBADDR *pdbaddr=NULL; + long status; + notifyInfo *pnotifyInfo; + CALLBACK *pcallback; + processNotify *ppn=NULL; + + if(plink->type!=INST_IO) { + recGblRecordError(S_db_badField,(void *)pbi, + "devBiSoftCallback (init_record) linked record not found"); + pbi->pact=TRUE; + return(S_db_badField); + } + pinstio=(struct instio*)&(plink->value); + pvname = pinstio->string; + pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr), + "devBiSoftCallback::init_record"); + status = dbNameToAddr(pvname,pdbaddr); + if(status) { + recGblRecordError(status,(void *)pbi, + "devBiSoftCallback (init_record) Illegal INP field"); + pbi->pact=TRUE; + return(status); + } + pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo), + "devBiSoftCallback::init_record"); + pcallback = callocMustSucceed(1, sizeof(*pcallback), + "devBiSoftCallback::init_record"); + ppn = callocMustSucceed(1, sizeof(*ppn), + "devBiSoftCallback::init_record"); + pnotifyInfo->ppn = ppn; + pnotifyInfo->pcallback = pcallback; + ppn->usrPvt = pbi; + ppn->paddr = pdbaddr; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; + ppn->requestType = processGetRequest; + pbi->dpvt = pnotifyInfo; + return 0; +} + +static long read_bi(biRecord *pbi) +{ + notifyInfo *pnotifyInfo = (notifyInfo *)pbi->dpvt; + + if(pbi->pact) { + if(pnotifyInfo->status) { + recGblSetSevr(pbi,READ_ALARM,INVALID_ALARM); + return(2); + } + pbi->val = pnotifyInfo->value; + pbi->udf = FALSE; + return(2); + } + dbProcessNotify(pnotifyInfo->ppn); + pbi->pact = TRUE; + return(0); +} diff --git a/src/std/dev/devLiSoftCallback.c b/src/std/dev/devLiSoftCallback.c new file mode 100644 index 000000000..1cdf21b2e --- /dev/null +++ b/src/std/dev/devLiSoftCallback.c @@ -0,0 +1,155 @@ +/*************************************************************************\ +* 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 is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* devLiSoftCallback.c */ +/* + * Author: Marty Kraimer + * Date: 23APR2008 + */ + +#include +#include +#include + +#include "alarm.h" +#include "callback.h" +#include "cantProceed.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "dbNotify.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "longinRecord.h" +#include "epicsExport.h" + +/* Create the dset for devLiSoftCallback */ +static long init_record(); +static long read_li(); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_li; + DEVSUPFUN special_linconv; +}devLiSoftCallback={ + 6, + NULL, + NULL, + init_record, + NULL, + read_li, + NULL}; +epicsExportAddress(dset,devLiSoftCallback); + +typedef struct notifyInfo { + processNotify *ppn; + CALLBACK *pcallback; + long value; + int status; +}notifyInfo; + +static void getCallback(processNotify *ppn,notifyGetType type) +{ + struct longinRecord *pli = (struct longinRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pli->dpvt; + int status = 0; + long no_elements = 1; + long options = 0; + + if(ppn->status==notifyCanceled) { + printf("dbtpn:getCallback notifyCanceled\n"); + return; + } + switch(type) { + case getFieldType: + status = dbGetField(ppn->paddr,DBR_LONG,&pnotifyInfo->value, + &options,&no_elements,0); + break; + case getType: + status = dbGet(ppn->paddr,DBR_LONG,&pnotifyInfo->value, + &options,&no_elements,0); + break; + } + pnotifyInfo->status = status; +} + +static void doneCallback(processNotify *ppn) +{ + struct longinRecord *pli = (struct longinRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pli->dpvt; + + callbackRequestProcessCallback(pnotifyInfo->pcallback,pli->prio,pli); +} + + +static long init_record(struct longinRecord *pli) +{ + DBLINK *plink = &pli->inp; + struct instio *pinstio; + char *pvname; + DBADDR *pdbaddr=NULL; + long status; + notifyInfo *pnotifyInfo; + CALLBACK *pcallback; + processNotify *ppn=NULL; + + if(plink->type!=INST_IO) { + recGblRecordError(S_db_badField,(void *)pli, + "devLiSoftCallback (init_record) linked record not found"); + pli->pact=TRUE; + return(S_db_badField); + } + pinstio=(struct instio*)&(plink->value); + pvname = pinstio->string; + pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr), + "devLiSoftCallback::init_record"); + status = dbNameToAddr(pvname,pdbaddr); + if(status) { + recGblRecordError(status,(void *)pli, + "devLiSoftCallback (init_record) Illegal INP field"); + pli->pact=TRUE; + return(status); + } + pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo), + "devLiSoftCallback::init_record"); + pcallback = callocMustSucceed(1, sizeof(*pcallback), + "devLiSoftCallback::init_record"); + ppn = callocMustSucceed(1, sizeof(*ppn), + "devLiSoftCallback::init_record"); + pnotifyInfo->ppn = ppn; + pnotifyInfo->pcallback = pcallback; + ppn->usrPvt = pli; + ppn->paddr = pdbaddr; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; + ppn->requestType = processGetRequest; + pli->dpvt = pnotifyInfo; + return 0; +} + +static long read_li(longinRecord *pli) +{ + notifyInfo *pnotifyInfo = (notifyInfo *)pli->dpvt; + + if(pli->pact) { + if(pnotifyInfo->status) { + recGblSetSevr(pli,READ_ALARM,INVALID_ALARM); + return(pnotifyInfo->status); + } + pli->val = pnotifyInfo->value; + pli->udf = FALSE; + return(0); + } + dbProcessNotify(pnotifyInfo->ppn); + pli->pact = TRUE; + return(0); +} diff --git a/src/std/dev/devMbbiSoftCallback.c b/src/std/dev/devMbbiSoftCallback.c new file mode 100644 index 000000000..b0fb1b7e5 --- /dev/null +++ b/src/std/dev/devMbbiSoftCallback.c @@ -0,0 +1,155 @@ +/*************************************************************************\ +* 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 is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* devMbbiSoftCallback.c */ +/* + * Author: Marty Kraimer + * Date: 23APR2008 + */ + +#include +#include +#include + +#include "alarm.h" +#include "callback.h" +#include "cantProceed.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "dbNotify.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "mbbiRecord.h" +#include "epicsExport.h" + +/* Create the dset for devMbbiSoftCallback */ +static long init_record(); +static long read_mbbi(); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_mbbi; + DEVSUPFUN special_linconv; +}devMbbiSoftCallback={ + 6, + NULL, + NULL, + init_record, + NULL, + read_mbbi, + NULL}; +epicsExportAddress(dset,devMbbiSoftCallback); + +typedef struct notifyInfo { + processNotify *ppn; + CALLBACK *pcallback; + unsigned short value; + int status; +}notifyInfo; + +static void getCallback(processNotify *ppn,notifyGetType type) +{ + struct mbbiRecord *pmbbi = (struct mbbiRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pmbbi->dpvt; + int status = 0; + long no_elements = 1; + long options = 0; + + if(ppn->status==notifyCanceled) { + printf("dbtpn:getCallback notifyCanceled\n"); + return; + } + switch(type) { + case getFieldType: + status = dbGetField(ppn->paddr,DBR_USHORT,&pnotifyInfo->value, + &options,&no_elements,0); + break; + case getType: + status = dbGet(ppn->paddr,DBR_USHORT,&pnotifyInfo->value, + &options,&no_elements,0); + break; + } + pnotifyInfo->status = status; +} + +static void doneCallback(processNotify *ppn) +{ + struct mbbiRecord *pmbbi = (struct mbbiRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pmbbi->dpvt; + + callbackRequestProcessCallback(pnotifyInfo->pcallback,pmbbi->prio,pmbbi); +} + + +static long init_record(struct mbbiRecord *pmbbi) +{ + DBLINK *plink = &pmbbi->inp; + struct instio *pinstio; + char *pvname; + DBADDR *pdbaddr=NULL; + long status; + notifyInfo *pnotifyInfo; + CALLBACK *pcallback; + processNotify *ppn=NULL; + + if(plink->type!=INST_IO) { + recGblRecordError(S_db_badField,(void *)pmbbi, + "devMbbiSoftCallback (init_record) linked record not found"); + pmbbi->pact=TRUE; + return(S_db_badField); + } + pinstio=(struct instio*)&(plink->value); + pvname = pinstio->string; + pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr), + "devMbbiSoftCallback::init_record"); + status = dbNameToAddr(pvname,pdbaddr); + if(status) { + recGblRecordError(status,(void *)pmbbi, + "devMbbiSoftCallback (init_record) Illegal INP field"); + pmbbi->pact=TRUE; + return(status); + } + pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo), + "devMbbiSoftCallback::init_record"); + pcallback = callocMustSucceed(1, sizeof(*pcallback), + "devMbbiSoftCallback::init_record"); + ppn = callocMustSucceed(1, sizeof(*ppn), + "devMbbiSoftCallback::init_record"); + pnotifyInfo->ppn = ppn; + pnotifyInfo->pcallback = pcallback; + ppn->usrPvt = pmbbi; + ppn->paddr = pdbaddr; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; + ppn->requestType = processGetRequest; + pmbbi->dpvt = pnotifyInfo; + return 0; +} + +static long read_mbbi(mbbiRecord *pmbbi) +{ + notifyInfo *pnotifyInfo = (notifyInfo *)pmbbi->dpvt; + + if(pmbbi->pact) { + if(pnotifyInfo->status) { + recGblSetSevr(pmbbi,READ_ALARM,INVALID_ALARM); + return(2); + } + pmbbi->val = pnotifyInfo->value; + pmbbi->udf = FALSE; + return(2); + } + dbProcessNotify(pnotifyInfo->ppn); + pmbbi->pact = TRUE; + return(0); +} diff --git a/src/std/dev/devSiSoftCallback.c b/src/std/dev/devSiSoftCallback.c new file mode 100644 index 000000000..bb2d88ce5 --- /dev/null +++ b/src/std/dev/devSiSoftCallback.c @@ -0,0 +1,155 @@ +/*************************************************************************\ +* 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 is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* devSiSoftCallback.c */ +/* + * Author: Marty Kraimer + * Date: 23APR2008 + */ + +#include +#include +#include + +#include "alarm.h" +#include "callback.h" +#include "cantProceed.h" +#include "dbDefs.h" +#include "dbAccess.h" +#include "dbNotify.h" +#include "recGbl.h" +#include "recSup.h" +#include "devSup.h" +#include "link.h" +#include "stringinRecord.h" +#include "epicsExport.h" + +/* Create the dset for devSiSoftCallback */ +static long init_record(); +static long read_stringin(); +struct { + long number; + DEVSUPFUN report; + DEVSUPFUN init; + DEVSUPFUN init_record; + DEVSUPFUN get_ioint_info; + DEVSUPFUN read_stringin; + DEVSUPFUN special_linconv; +}devSiSoftCallback={ + 6, + NULL, + NULL, + init_record, + NULL, + read_stringin, + NULL}; +epicsExportAddress(dset,devSiSoftCallback); + +typedef struct notifyInfo { + processNotify *ppn; + CALLBACK *pcallback; + char value[40]; + int status; +}notifyInfo; + +static void getCallback(processNotify *ppn,notifyGetType type) +{ + struct stringinRecord *pstringin = (struct stringinRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pstringin->dpvt; + int status = 0; + long no_elements = 1; + long options = 0; + + if(ppn->status==notifyCanceled) { + printf("dbtpn:getCallback notifyCanceled\n"); + return; + } + switch(type) { + case getFieldType: + status = dbGetField(ppn->paddr,DBR_STRING,&pnotifyInfo->value, + &options,&no_elements,0); + break; + case getType: + status = dbGet(ppn->paddr,DBR_STRING,&pnotifyInfo->value, + &options,&no_elements,0); + break; + } + pnotifyInfo->status = status; +} + +static void doneCallback(processNotify *ppn) +{ + struct stringinRecord *pstringin = (struct stringinRecord *)ppn->usrPvt; + notifyInfo *pnotifyInfo = (notifyInfo *)pstringin->dpvt; + + callbackRequestProcessCallback(pnotifyInfo->pcallback,pstringin->prio,pstringin); +} + + +static long init_record(struct stringinRecord *pstringin) +{ + DBLINK *plink = &pstringin->inp; + struct instio *pinstio; + char *pvname; + DBADDR *pdbaddr=NULL; + long status; + notifyInfo *pnotifyInfo; + CALLBACK *pcallback; + processNotify *ppn=NULL; + + if(plink->type!=INST_IO) { + recGblRecordError(S_db_badField,(void *)pstringin, + "devSiSoftCallback (init_record) linked record not found"); + pstringin->pact=TRUE; + return(S_db_badField); + } + pinstio=(struct instio*)&(plink->value); + pvname = pinstio->string; + pdbaddr = callocMustSucceed(1, sizeof(*pdbaddr), + "devSiSoftCallback::init_record"); + status = dbNameToAddr(pvname,pdbaddr); + if(status) { + recGblRecordError(status,(void *)pstringin, + "devSiSoftCallback (init_record) Illegal INP field"); + pstringin->pact=TRUE; + return(status); + } + pnotifyInfo = callocMustSucceed(1, sizeof(*pnotifyInfo), + "devSiSoftCallback::init_record"); + pcallback = callocMustSucceed(1, sizeof(*pcallback), + "devSiSoftCallback::init_record"); + ppn = callocMustSucceed(1, sizeof(*ppn), + "devSiSoftCallback::init_record"); + pnotifyInfo->ppn = ppn; + pnotifyInfo->pcallback = pcallback; + ppn->usrPvt = pstringin; + ppn->paddr = pdbaddr; + ppn->getCallback = getCallback; + ppn->doneCallback = doneCallback; + ppn->requestType = processGetRequest; + pstringin->dpvt = pnotifyInfo; + return 0; +} + +static long read_stringin(stringinRecord *pstringin) +{ + notifyInfo *pnotifyInfo = (notifyInfo *)pstringin->dpvt; + + if(pstringin->pact) { + if(pnotifyInfo->status) { + recGblSetSevr(pstringin,READ_ALARM,INVALID_ALARM); + return(pnotifyInfo->status); + } + strcpy(pstringin->val,pnotifyInfo->value); + pstringin->udf = FALSE; + return(0); + } + dbProcessNotify(pnotifyInfo->ppn); + pstringin->pact = TRUE; + return(0); +} diff --git a/src/std/dev/devSoft.dbd b/src/std/dev/devSoft.dbd index 5f90aba86..860a0a500 100644 --- a/src/std/dev/devSoft.dbd +++ b/src/std/dev/devSoft.dbd @@ -27,6 +27,12 @@ device(mbbiDirect,CONSTANT,devMbbiDirectSoftRaw,"Raw Soft Channel") device(mbbo,CONSTANT,devMbboSoftRaw,"Raw Soft Channel") device(mbboDirect,CONSTANT,devMbboDirectSoftRaw,"Raw Soft Channel") +device(ai,INST_IO,devAiSoftCallback,"Async Soft Channel") +device(bi,INST_IO,devBiSoftCallback,"Async Soft Channel") +device(mbbi,INST_IO,devMbbiSoftCallback,"Async Soft Channel") +device(longin,INST_IO,devLiSoftCallback,"Async Soft Channel") +device(stringin,INST_IO,devSiSoftCallback,"Async Soft Channel") + device(ao,CONSTANT,devAoSoftCallback,"Async Soft Channel") device(bo,CONSTANT,devBoSoftCallback,"Async Soft Channel") device(calcout,CONSTANT,devCalcoutSoftCallback,"Async Soft Channel")