Extended asTrapWrite to provide put data

Backwards-compatible enhancement to the asTrapWrite API to provide
listener routines with the data being put by the client.
The asTrapWriteMessage structure is extended with 3 new fields
for data type, element count and a pointer to the source buffer.

Tim Mooney requested this enhancement for his caPutRecorder code,
which doesn't work if the record overwrites the new value within
its process() routine, e.g. when jogging a motor record.
This commit is contained in:
Andrew Johnson
2015-02-16 16:30:52 -06:00
parent 2e4d8b31ff
commit c5ded30684
5 changed files with 96 additions and 47 deletions

View File

@@ -13,6 +13,31 @@
<!-- Insert new items immediately below here ... -->
<h3>Enhanced API for asTrapWrite listeners</h3>
<p>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.</p>
<p>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:</p>
<blockquote><pre>
#include "asLib.h"
/* ... */
#ifdef asTrapWriteWithData
/* Enhanced API */
#endif
</pre></blockquote>
<h3>Back-ported the <q>tapfiles</q> build target from 3.15</h3>
<p>This GNUmake target runs the same tests as the <q>runtests</q> target, but

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);