Merged trap-write-data branch
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -811,10 +811,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,
|
||||
@@ -1816,11 +1816,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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user