diff --git a/src/ioc/db/dbAccess.c b/src/ioc/db/dbAccess.c index 7fbfcc458..1d224f976 100644 --- a/src/ioc/db/dbAccess.c +++ b/src/ioc/db/dbAccess.c @@ -315,28 +315,36 @@ static void get_alarm(DBADDR *paddr, char **ppbuffer, return; } +/* + * This code relies on *poriginal being aligned and all increments done by the + * blocks only changing the buffer pointer in a way that does not break alignment. + */ static void getOptions(DBADDR *paddr, char **poriginal, long *options, void *pflin) { db_field_log *pfl= (db_field_log *)pflin; struct rset *prset; - short field_type=paddr->field_type; + short field_type; dbCommon *pcommon; char *pbuffer = *poriginal; + if (!pfl || pfl->type == dbfl_type_rec) + field_type = paddr->field_type; + else + field_type = pfl->field_type; prset=dbGetRset(paddr); /* Process options */ pcommon = paddr->precord; if( (*options) & DBR_STATUS ) { unsigned short *pushort = (unsigned short *)pbuffer; - if(pfl!=NULL) { - *pushort++ = pfl->u.v.stat; - *pushort++ = pfl->u.v.sevr; - } else { + if (!pfl || pfl->type == dbfl_type_rec) { *pushort++ = pcommon->stat; *pushort++ = pcommon->sevr; - } + } else { + *pushort++ = pfl->stat; + *pushort++ = pfl->sevr; + } *pushort++ = pcommon->acks; *pushort++ = pcommon->ackt; pbuffer = (char *)pushort; @@ -364,12 +372,12 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options, if( (*options) & DBR_TIME ) { epicsUInt32 *ptime = (epicsUInt32 *)pbuffer; - if(pfl!=NULL) { - *ptime++ = pfl->u.v.time.secPastEpoch; - *ptime++ = pfl->u.v.time.nsec; - } else { - *ptime++ = pcommon->time.secPastEpoch; - *ptime++ = pcommon->time.nsec; + if (!pfl || pfl->type == dbfl_type_rec) { + *ptime++ = pcommon->time.secPastEpoch; + *ptime++ = pcommon->time.nsec; + } else { + *ptime++ = pfl->time.secPastEpoch; + *ptime++ = pfl->time.nsec; } pbuffer = (char *)ptime; } @@ -778,8 +786,8 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType, { char *pbuf = pbuffer; db_field_log *pfl = (db_field_log *)pflin; - short field_type = paddr->field_type; - long no_elements = paddr->no_elements; + short field_type; + long no_elements; long offset; struct rset *prset; long status = 0; @@ -789,6 +797,14 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType, if (nRequest && *nRequest == 0) return 0; + if (!pfl || pfl->type == dbfl_type_rec) { + field_type = paddr->field_type; + no_elements = paddr->no_elements; + } else { + field_type = pfl->field_type; + no_elements = pfl->no_elements; + } + if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) return getLinkValue(paddr, dbrType, pbuf, nRequest); @@ -815,15 +831,18 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType, if (offset == 0 && (!nRequest || no_elements == 1)) { if (nRequest) *nRequest = 1; - if (pfl != NULL) { - DBADDR localAddr = *paddr; /* Structure copy */ - - localAddr.pfield = (char *)&pfl->u.v.field; - status = dbFastGetConvertRoutine[field_type][dbrType] - (localAddr.pfield, pbuffer, &localAddr); - } else { + if (!pfl || pfl->type == dbfl_type_rec) { status = dbFastGetConvertRoutine[field_type][dbrType] (paddr->pfield, pbuffer, paddr); + } else { + DBADDR localAddr = *paddr; /* Structure copy */ + + if (pfl->type == dbfl_type_val) + localAddr.pfield = (char *) &pfl->u.v.field; + else + localAddr.pfield = (char *) pfl->u.r.field; + status = dbFastGetConvertRoutine[field_type][dbrType] + (localAddr.pfield, pbuffer, &localAddr); } } else { long n; @@ -847,13 +866,16 @@ long epicsShareAPI dbGet(DBADDR *paddr, short dbrType, /* convert database field and place it in the buffer */ if (n <= 0) { ;/*do nothing*/ - } else if (pfl) { + } else if (!pfl || pfl->type == dbfl_type_rec) { + status = convert(paddr, pbuffer, n, no_elements, offset); + } else { DBADDR localAddr = *paddr; /* Structure copy */ - localAddr.pfield = (char *)&pfl->u.v.field; + if (pfl->type == dbfl_type_val) + localAddr.pfield = (char *) &pfl->u.v.field; + else + localAddr.pfield = (char *) pfl->u.r.field; status = convert(&localAddr, pbuffer, n, no_elements, offset); - } else { - status = convert(paddr, pbuffer, n, no_elements, offset); } } return status; diff --git a/src/ioc/db/dbEvent.c b/src/ioc/db/dbEvent.c index 6bd27dc35..adea52b9f 100644 --- a/src/ioc/db/dbEvent.c +++ b/src/ioc/db/dbEvent.c @@ -634,10 +634,12 @@ db_field_log* db_post_single_event_first (struct evSubscrip *pevent) 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; + pLog->type = dbfl_type_val; + pLog->stat = prec->stat; + pLog->sevr = prec->sevr; + pLog->time = prec->time; + pLog->field_type = dbChannelFieldType(chan); + pLog->no_elements = dbChannelElements(chan); /* * use memcpy to avoid a bus error on * union copy of char in the db at an odd @@ -647,12 +649,7 @@ db_field_log* db_post_single_event_first (struct evSubscrip *pevent) 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; + pLog->type = dbfl_type_rec; } } return pLog; @@ -677,13 +674,15 @@ void db_post_single_event_final (void *pvt, evSubscrip *pevent, db_field_log *pL LOCKEVQUE (ev_que) /* - * if we have an event on the queue and we are - * not saving the current value (because this is a - * string or an array) then ignore duplicate - * events (saving them without the current valuye - * serves no purpose) + * if we have an event on the queue and both the last + * event on the queue and the current event are emtpy + * (i.e. of type dbfl_type_rec), simply ignore duplicate + * events (saving empty events serves no purpose) */ - if (!pevent->useValque && pevent->npend>0u) { + if (pevent->npend > 0u && + (*pevent->pLastLog)->type == dbfl_type_rec && + pLog->type == dbfl_type_rec) { + db_delete_field_log(pLog); UNLOCKEVQUE (ev_que) return; } @@ -860,9 +859,6 @@ static int event_read ( struct event_que *ev_que ) * communication. (for other types they get whatever happens * to be there upon wakeup) */ - if ( !pevent->useValque ) { - pfl = NULL; - } event_remove ( ev_que, ev_que->getix, EVENTQEMPTY ); ev_que->getix = RNGINC ( ev_que->getix ); @@ -1093,7 +1089,7 @@ 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); + if (pfl->type == dbfl_type_ref && pfl->u.r.dtor) pfl->u.r.dtor(pfl); /* Free the field log chunk */ freeListFree(dbevFieldLogFreeList, pfl); } diff --git a/src/ioc/db/db_field_log.h b/src/ioc/db/db_field_log.h index 8ed545063..a01a21152 100644 --- a/src/ioc/db/db_field_log.h +++ b/src/ioc/db/db_field_log.h @@ -46,26 +46,38 @@ union native_value { * structure to log the state of a data base field at the time * an event is triggered. */ +struct db_field_log; +typedef void (dbfl_freeFunc)(struct db_field_log *pfl); + +/* Types of db_field_log: rec = use record, val = val inside, ref = reference inside */ +typedef enum dbfl_type { + dbfl_type_rec = 0, + dbfl_type_val, + dbfl_type_ref +} dbfl_type; + +#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref") + struct dbfl_val { - unsigned short stat; /* Alarm Status */ - unsigned short sevr; /* Alarm Severity */ - epicsTimeStamp time; /* Time stamp */ - union native_value field; /* Field value */ + 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 */ + dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */ + void *pvt; /* Private pointer */ + void *field; /* Field value */ }; typedef struct db_field_log { - char isValue; /* is a value (*not* string/array) */ + enum dbfl_type type; /* type (union) selector */ + epicsTimeStamp time; /* Time stamp */ + unsigned short stat; /* Alarm Status */ + unsigned short sevr; /* Alarm Severity */ + short field_type; /* DBF type of data */ + long no_elements; /* No of array elements */ union { struct dbfl_val v; - struct dbfl_ref p; + struct dbfl_ref r; } u; } db_field_log; diff --git a/src/ioc/db/test/chfPluginTest.c b/src/ioc/db/test/chfPluginTest.c index 564a81302..043da3cf8 100644 --- a/src/ioc/db/test/chfPluginTest.c +++ b/src/ioc/db/test/chfPluginTest.c @@ -22,12 +22,13 @@ #define e_error 0x00000004 #define e_ok 0x00000008 #define e_open 0x00000010 -#define e_report 0x00000020 -#define e_close 0x00000040 +#define e_reg_pre_cb 0x00000020 +#define e_report 0x00000040 +#define e_close 0x00000080 unsigned int e, c; -#define e_any (e_alloc | e_free | e_error | e_ok | e_open | e_report | e_close) +#define e_any (e_alloc | e_free | e_error | e_ok | e_open | e_reg_pre_cb| e_report | e_close) typedef struct myStruct { int sent1;