diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index f95eb2e03..837b7e024 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,31 @@ +

Enhanced API for asTrapWrite listeners

+ +

External software such as the CA Put Logging module that registers a listener +with the asTrapWrite subsystem was not previously given access to the actual +data being sent by the CA client. In most cases this was not a problem as the +listener can look at the field being modified both before and after the +operation, but if the put processes the record which immediately overwrites the +new value, the client's value cannot be observed.

+ +

This release adds three fields to the asTrapWriteMessage structure that is +passed to the listener routines. These new fields provide the CA data type, the +number of array elements, and a pointer to the source data buffer. This change +is completely backwards compatible with listener code written against the +original API. The new API can be detected at compile-time as follows:

+ +
+#include "asLib.h"
+
+/* ... */
+
+#ifdef asTrapWriteWithData
+    /* Enhanced API */
+#endif
+
+

Back-ported the tapfiles build target from 3.15

This GNUmake target runs the same tests as the runtests target, but diff --git a/src/as/asLib.h b/src/as/asLib.h index b3da2f836..2a420a23b 100644 --- a/src/as/asLib.h +++ b/src/as/asLib.h @@ -30,25 +30,38 @@ typedef enum{ } asClientStatus; typedef void (*ASCLIENTCALLBACK) (ASCLIENTPVT,asClientStatus); + /* The following routines are macros with the following syntax long asCheckGet(ASCLIENTPVT asClientPvt); long asCheckPut(ASCLIENTPVT asClientPvt); */ -#define asCheckGet(asClientPvt)\ - (asActive \ - ? ((asClientPvt)->access>=asREAD ? TRUE : FALSE)\ - : TRUE) -#define asCheckPut(asClientPvt)\ - (asActive \ - ? ((asClientPvt)->access>=asWRITE ? TRUE : FALSE)\ - : TRUE) -#define asTrapWriteBefore(asClientPvt,user,host,addr) \ - (((asActive) && (asClientPvt)->trapMask) \ - ? asTrapWriteBeforeWrite((user),(host),(addr)) \ - : 0) +#define asCheckGet(asClientPvt) \ + (!asActive || ((asClientPvt)->access >= asREAD)) +#define asCheckPut(asClientPvt) \ + (!asActive || ((asClientPvt)->access >= asWRITE)) + +/* More convenience macros +void *asTrapWriteWithData(ASCLIENTPVT asClientPvt, + const char *userid, const char *hostid, void *addr, + int dbrType, int no_elements, void *data); +void asTrapWriteAfter(ASCLIENTPVT asClientPvt); +*/ +#define asTrapWriteWithData(asClientPvt, user, host, addr, type, count, data) \ + ((asActive && (asClientPvt)->trapMask) \ + ? asTrapWriteBeforeWithData((user), (host), (addr), (type), (count), (data)) \ + : 0) +#define asTrapWriteAfter(pvt) \ + if (pvt) asTrapWriteAfterWrite(pvt) + +/* This macro is for backwards compatibility, upgrade any code + calling it to use asTrapWriteWithData() instead ASAP: +void *asTrapWriteBefore(ASCLIENTPVT asClientPvt, + const char *userid, const char *hostid, void *addr); +*/ +#define asTrapWriteBefore(asClientPvt, user, host, addr) \ + asTrapWriteWithData(asClientPvt, user, host, addr, 0, 0, NULL) + -#define asTrapWriteAfter(pvt) if((pvt)) asTrapWriteAfterWrite((pvt)) - epicsShareFunc long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction); epicsShareFunc long epicsShareAPI asInitFile( const char *filename,const char *substitutions); @@ -100,8 +113,9 @@ epicsShareFunc int epicsShareAPI asDumpMemFP(FILE *fp,const char *asgname, epicsShareFunc int epicsShareAPI asDumpHash(void); epicsShareFunc int epicsShareAPI asDumpHashFP(FILE *fp); -epicsShareFunc void * epicsShareAPI asTrapWriteBeforeWrite( - const char *userid,const char *hostid,void *addr); +epicsShareFunc void * epicsShareAPI asTrapWriteBeforeWithData( + const char *userid, const char *hostid, void *addr, + int dbrType, int no_elements, void *data); epicsShareFunc void epicsShareAPI asTrapWriteAfterWrite(void *pvt); diff --git a/src/as/asTrapWrite.c b/src/as/asTrapWrite.c index 7c2536f93..65a77f09f 100644 --- a/src/as/asTrapWrite.c +++ b/src/as/asTrapWrite.c @@ -3,8 +3,7 @@ * 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 +* EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ /*asTrapWrite.c */ @@ -100,47 +99,53 @@ void epicsShareAPI asTrapWriteUnregisterListener(asTrapWriteId id) = (listenerPvt *)ellNext(&plistenerPvt->node); if(plistenerPvt->plistener == plistener) { ellDelete(&pwriteMessage->listenerPvtList,&plistenerPvt->node); - freeListFree(pasTrapWritePvt->freeListListenerPvt,(void *)plistenerPvt); + freeListFree(pasTrapWritePvt->freeListListenerPvt, plistenerPvt); } plistenerPvt = pnext; } pwriteMessage = (writeMessage *)ellNext(&pwriteMessage->node); } ellDelete(&pasTrapWritePvt->listenerList,&plistener->node); - free((void *)plistener); + free(plistener); epicsMutexUnlock(pasTrapWritePvt->lock); } -void * epicsShareAPI asTrapWriteBeforeWrite( - const char *userid,const char *hostid,void *addr) +void * epicsShareAPI asTrapWriteBeforeWithData( + const char *userid, const char *hostid, void *addr, + int dbrType, int no_elements, void *data) { writeMessage *pwriteMessage; listener *plistener; - listenerPvt *plistenerPvt; - if(pasTrapWritePvt==0) return(0); - if(ellCount(&pasTrapWritePvt->listenerList)<=0) return 0; + if (pasTrapWritePvt == 0 || + ellCount(&pasTrapWritePvt->listenerList) <= 0) return 0; + pwriteMessage = (writeMessage *)freeListCalloc( pasTrapWritePvt->freeListWriteMessage); pwriteMessage->message.userid = userid; pwriteMessage->message.hostid = hostid; pwriteMessage->message.serverSpecific = addr; + pwriteMessage->message.dbrType = dbrType; + pwriteMessage->message.no_elements = no_elements; + pwriteMessage->message.data = data; ellInit(&pwriteMessage->listenerPvtList); + epicsMutexMustLock(pasTrapWritePvt->lock); - ellAdd(&pasTrapWritePvt->writeMessageList,&pwriteMessage->node); + ellAdd(&pasTrapWritePvt->writeMessageList, &pwriteMessage->node); plistener = (listener *)ellFirst(&pasTrapWritePvt->listenerList); - while(plistener) { - plistenerPvt = (listenerPvt *)freeListCalloc( + while (plistener) { + listenerPvt *plistenerPvt = (listenerPvt *)freeListCalloc( pasTrapWritePvt->freeListListenerPvt); + plistenerPvt->plistener = plistener; pwriteMessage->message.userPvt = 0; - (*plistener->func)(&pwriteMessage->message,0); + plistener->func(&pwriteMessage->message, 0); plistenerPvt->userPvt = pwriteMessage->message.userPvt; - ellAdd(&pwriteMessage->listenerPvtList,&plistenerPvt->node); + ellAdd(&pwriteMessage->listenerPvtList, &plistenerPvt->node); plistener = (listener *)ellNext(&plistener->node); } epicsMutexUnlock(pasTrapWritePvt->lock); - return((void *)pwriteMessage); + return pwriteMessage; } void epicsShareAPI asTrapWriteAfterWrite(void *pvt) @@ -148,20 +153,22 @@ void epicsShareAPI asTrapWriteAfterWrite(void *pvt) writeMessage *pwriteMessage = (writeMessage *)pvt; listenerPvt *plistenerPvt; - if(pwriteMessage==0 || pasTrapWritePvt==0) return; + if (pwriteMessage == 0 || + pasTrapWritePvt == 0) return; + epicsMutexMustLock(pasTrapWritePvt->lock); plistenerPvt = (listenerPvt *)ellFirst(&pwriteMessage->listenerPvtList); - while(plistenerPvt) { + while (plistenerPvt) { listenerPvt *pnext = (listenerPvt *)ellNext(&plistenerPvt->node); - listener *plistener; - plistener = plistenerPvt->plistener; + listener *plistener = plistenerPvt->plistener; + pwriteMessage->message.userPvt = plistenerPvt->userPvt; - (*plistener->func)(&pwriteMessage->message,1); - ellDelete(&pwriteMessage->listenerPvtList,&plistenerPvt->node); - freeListFree(pasTrapWritePvt->freeListListenerPvt,(void *)plistenerPvt); + plistener->func(&pwriteMessage->message, 1); + ellDelete(&pwriteMessage->listenerPvtList, &plistenerPvt->node); + freeListFree(pasTrapWritePvt->freeListListenerPvt, plistenerPvt); plistenerPvt = pnext; } - ellDelete(&pasTrapWritePvt->writeMessageList,&pwriteMessage->node); - freeListFree(pasTrapWritePvt->freeListWriteMessage,(void *)pwriteMessage); + ellDelete(&pasTrapWritePvt->writeMessageList, &pwriteMessage->node); + freeListFree(pasTrapWritePvt->freeListWriteMessage, pwriteMessage); epicsMutexUnlock(pasTrapWritePvt->lock); } diff --git a/src/as/asTrapWrite.h b/src/as/asTrapWrite.h index ec34c5312..b8033cb94 100644 --- a/src/as/asTrapWrite.h +++ b/src/as/asTrapWrite.h @@ -3,9 +3,8 @@ * 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. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ /*asTrapWrite.h*/ /* Author: Marty Kraimer Date: 07NOV2000 */ @@ -24,6 +23,9 @@ typedef struct asTrapWriteMessage { const char *hostid; void *serverSpecific; void *userPvt; + int dbrType; /* Data type from ca/db_access.h, NOT dbFldTypes.h */ + int no_elements; + void *data; /* Might be NULL if no data is available */ } asTrapWriteMessage; diff --git a/src/rsrv/camessage.c b/src/rsrv/camessage.c index ba83af1b3..4ad28243a 100644 --- a/src/rsrv/camessage.c +++ b/src/rsrv/camessage.c @@ -814,10 +814,10 @@ static int write_action ( caHdrLargeArray *mp, return RSRV_ERROR; } - asWritePvt = asTrapWriteBefore ( pciu->asClientPVT, + asWritePvt = asTrapWriteWithData ( pciu->asClientPVT, pciu->client->pUserName ? pciu->client->pUserName : "", pciu->client->pHostName ? pciu->client->pHostName : "", - (void *) &pciu->addr ); + (void *) &pciu->addr, mp->m_dataType, mp->m_count, pPayload ); dbStatus = db_put_field( &pciu->addr, @@ -1819,11 +1819,12 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload, return RSRV_OK; } - pciu->pPutNotify->asWritePvt = asTrapWriteBefore ( + pciu->pPutNotify->asWritePvt = asTrapWriteWithData ( pciu->asClientPVT, pciu->client->pUserName ? pciu->client->pUserName : "", pciu->client->pHostName ? pciu->client->pHostName : "", - (void *) &pciu->addr ); + (void *) &pciu->addr, mp->m_dataType, mp->m_count, + pciu->pPutNotify->dbPutNotify.pbuffer ); dbPutNotify(&pciu->pPutNotify->dbPutNotify);