Make reference (array/string) updates use a reference type db_field_log.

* Redefine db_field_log to be a union between a "value" type (as before)
  and a "reference" type (pointers to values, dtor for plugin array copies).
* Add db_delete_field_log function that correctly destructs a db_field_log.
This commit is contained in:
Ralph Lange
2012-04-27 13:21:54 -04:00
committed by Michael Davidsaver
parent 4dd42383ef
commit 5ea973151f
4 changed files with 64 additions and 27 deletions

View File

@@ -331,11 +331,11 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
unsigned short *pushort = (unsigned short *)pbuffer;
if(pfl!=NULL) {
*pushort++ = pfl->stat;
*pushort++ = pfl->sevr;
*pushort++ = pfl->u.v.stat;
*pushort++ = pfl->u.v.sevr;
} else {
*pushort++ = pcommon->stat;
*pushort++ = pcommon->sevr;
*pushort++ = pcommon->stat;
*pushort++ = pcommon->sevr;
}
*pushort++ = pcommon->acks;
*pushort++ = pcommon->ackt;
@@ -365,8 +365,8 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;
if(pfl!=NULL) {
*ptime++ = pfl->time.secPastEpoch;
*ptime++ = pfl->time.nsec;
*ptime++ = pfl->u.v.time.secPastEpoch;
*ptime++ = pfl->u.v.time.nsec;
} else {
*ptime++ = pcommon->time.secPastEpoch;
*ptime++ = pcommon->time.nsec;
@@ -818,7 +818,7 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType,
if (pfl != NULL) {
DBADDR localAddr = *paddr; /* Structure copy */
localAddr.pfield = (char *)&pfl->field;
localAddr.pfield = (char *)&pfl->u.v.field;
status = dbFastGetConvertRoutine[field_type][dbrType]
(localAddr.pfield, pbuffer, &localAddr);
} else {
@@ -850,7 +850,7 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType,
} else if (pfl) {
DBADDR localAddr = *paddr; /* Structure copy */
localAddr.pfield = (char *)&pfl->field;
localAddr.pfield = (char *)&pfl->u.v.field;
status = convert(&localAddr, pbuffer, n, no_elements, offset);
} else {
status = convert(paddr, pbuffer, n, no_elements, offset);

View File

@@ -628,25 +628,31 @@ int epicsShareAPI db_post_extra_labor (dbEventCtx ctx)
*/
db_field_log* db_post_single_event_first (struct evSubscrip *pevent)
{
db_field_log *pLog = NULL;
if (pevent->useValque) {
pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
if (pLog) {
struct dbChannel *chan = pevent->chan;
struct dbCommon *prec = dbChannelRecord(chan);
pLog->stat = prec->stat;
pLog->sevr = prec->sevr;
pLog->time = prec->time;
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);;
if (pLog) {
struct dbChannel *chan = pevent->chan;
struct dbCommon *prec = dbChannelRecord(chan);
if (pevent->useValque) {
pLog->isValue = 1;
pLog->u.v.stat = prec->stat;
pLog->u.v.sevr = prec->sevr;
pLog->u.v.time = prec->time;
/*
* use memcpy to avoid a bus error on
* union copy of char in the db at an odd
* address
*/
memcpy(&pLog->field,
memcpy(&pLog->u.v.field,
dbChannelField(chan),
dbChannelElementSize(chan));
} else {
pLog->isValue = 0;
pLog->u.p.stat = &prec->stat;
pLog->u.p.sevr = &prec->sevr;
pLog->u.p.time = &prec->time;
pLog->u.p.field = dbChannelField(chan);
pLog->u.p.freeFld = NULL;
}
}
return pLog;
@@ -698,7 +704,7 @@ void db_post_single_event_final (void *pvt, evSubscrip *pevent, db_field_log *pL
* replace last event if no space is left
*/
if (*pevent->pLastLog) {
freeListFree(dbevFieldLogFreeList, *pevent->pLastLog);
db_delete_field_log(*pevent->pLastLog);
*pevent->pLastLog = pLog;
}
pevent->nreplace++;
@@ -840,7 +846,7 @@ static int event_read ( struct event_que *ev_que )
if ( pevent == &canceledEvent ) {
ev_que->evque[ev_que->getix] = EVENTQEMPTY;
if (ev_que->valque[ev_que->getix]) {
freeListFree(dbevFieldLogFreeList, ev_que->valque[ev_que->getix]);
db_delete_field_log(ev_que->valque[ev_que->getix]);
ev_que->valque[ev_que->getix] = NULL;
}
ev_que->getix = RNGINC ( ev_que->getix );
@@ -909,7 +915,7 @@ static int event_read ( struct event_que *ev_que )
}
}
}
if (pfl) freeListFree (dbevFieldLogFreeList, pfl);
db_delete_field_log(pfl);
}
UNLOCKEVQUE (ev_que)
@@ -1079,3 +1085,16 @@ void epicsShareAPI db_event_flow_ctrl_mode_off (dbEventCtx ctx)
printf("fc off %lu\n", tickGet());
#endif
}
/*
* db_delete_field_log()
*/
void epicsShareAPI db_delete_field_log (db_field_log *pfl)
{
if (pfl) {
/* Free field if reference type field log and dtor is set */
if (!pfl->isValue && pfl->u.p.freeFld) pfl->u.p.freeFld(pfl->u.p.field);
/* Free the field log chunk */
freeListFree(dbevFieldLogFreeList, pfl);
}
}

View File

@@ -74,6 +74,8 @@ epicsShareFunc void epicsShareAPI db_event_enable (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_event_disable (dbEventSubscription es);
epicsShareFunc void epicsShareAPI db_post_single_event_final (void *pvt, struct evSubscrip *pevent, struct db_field_log *pLog);
epicsShareFunc void epicsShareAPI db_delete_field_log (struct db_field_log *pfl);
#define DB_EVENT_OK 0
#define DB_EVENT_ERROR (-1)

View File

@@ -29,7 +29,7 @@ extern "C" {
* will most likely change infrequently.
*
*/
union native_value{
union native_value {
short dbf_int;
short dbf_short;
float dbf_float;
@@ -46,11 +46,27 @@ union native_value{
* structure to log the state of a data base field at the time
* an event is triggered.
*/
struct dbfl_val {
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
epicsTimeStamp time; /* Time stamp */
union native_value field; /* Field value */
};
struct dbfl_ref {
unsigned short *stat; /* Alarm Status */
unsigned short *sevr; /* Alarm Severity */
epicsTimeStamp *time; /* Time stamp */
void (*freeFld)(void*); /* Callback to free a filter-allocated field */
void *field; /* Field value */
};
typedef struct db_field_log {
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
epicsTimeStamp time; /* time stamp */
union native_value field; /* field value */
char isValue; /* is a value (*not* string/array) */
union {
struct dbfl_val v;
struct dbfl_ref p;
} u;
} db_field_log;
#ifdef __cplusplus