Ben Franksen has proposed merging ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 with ~dirk.zimoch/epics-base:dbChannelForDBLinks as a prerequisite.
Requested reviews:
EPICS Core Developers (epics-core)
For more details, see:
https://code.launchpad.net/~bfrk/epics-base/+git/epics-base/+merge/381464
This is just refactors, no new features yet.
--
Your team EPICS Core Developers is requested to review the proposed merge of ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0.
diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c
index 9b149dd..3709049 100644
--- a/modules/database/src/ioc/db/dbAccess.c
+++ b/modules/database/src/ioc/db/dbAccess.c
@@ -338,7 +338,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
dbCommon *pcommon;
char *pbuffer = *poriginal;
- if (!pfl || pfl->type == dbfl_type_rec)
+ if (!pfl)
field_type = paddr->field_type;
else
field_type = pfl->field_type;
@@ -348,7 +348,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
if( (*options) & DBR_STATUS ) {
unsigned short *pushort = (unsigned short *)pbuffer;
- if (!pfl || pfl->type == dbfl_type_rec) {
+ if (!pfl) {
*pushort++ = pcommon->stat;
*pushort++ = pcommon->sevr;
} else {
@@ -382,7 +382,7 @@ static void getOptions(DBADDR *paddr, char **poriginal, long *options,
if( (*options) & DBR_TIME ) {
epicsUInt32 *ptime = (epicsUInt32 *)pbuffer;
- if (!pfl || pfl->type == dbfl_type_rec) {
+ if (!pfl) {
*ptime++ = pcommon->time.secPastEpoch;
*ptime++ = pcommon->time.nsec;
} else {
@@ -867,14 +867,14 @@ static long getAttrValue(DBADDR *paddr, short dbrType,
return 0;
}
-long dbGetField(DBADDR *paddr,short dbrType,
- void *pbuffer, long *options, long *nRequest, void *pflin)
+long dbGetField(DBADDR *paddr, short dbrType,
+ void *pbuffer, long *options, long *nRequest)
{
dbCommon *precord = paddr->precord;
long status = 0;
dbScanLock(precord);
- status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin);
+ status = dbGet(paddr, dbrType, pbuffer, options, nRequest, NULL);
dbScanUnlock(precord);
return status;
}
@@ -895,22 +895,23 @@ long dbGet(DBADDR *paddr, short dbrType,
if (nRequest && *nRequest == 0)
return 0;
- if (!pfl || pfl->type == dbfl_type_rec) {
+ if (!pfl) {
field_type = paddr->field_type;
no_elements = capacity = paddr->no_elements;
-
- /* Update field info from record
- * may modify paddr->pfield
- */
- if (paddr->pfldDes->special == SPC_DBADDR &&
- (prset = dbGetRset(paddr)) &&
- prset->get_array_info) {
- status = prset->get_array_info(paddr, &no_elements, &offset);
- } else
- offset = 0;
} else {
field_type = pfl->field_type;
no_elements = capacity = pfl->no_elements;
+ }
+
+ /* Update field info from record
+ * may modify paddr->pfield
+ */
+ if ((!pfl || (pfl->type==dbfl_type_ref && !pfl->u.r.dtor)) &&
+ paddr->pfldDes->special == SPC_DBADDR &&
+ (prset = dbGetRset(paddr)) &&
+ prset->get_array_info) {
+ status = prset->get_array_info(paddr, &no_elements, &offset);
+ } else {
offset = 0;
}
@@ -937,7 +938,7 @@ long dbGet(DBADDR *paddr, short dbrType,
if (offset == 0 && (!nRequest || no_elements == 1)) {
if (nRequest)
*nRequest = 1;
- if (!pfl || pfl->type == dbfl_type_rec) {
+ if (!pfl) {
status = dbFastGetConvertRoutine[field_type][dbrType]
(paddr->pfield, pbuf, paddr);
} else {
@@ -950,6 +951,7 @@ long dbGet(DBADDR *paddr, short dbrType,
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
+ /* not used by dbFastConvert: */
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
localAddr.pfield = (char *) &pfl->u.v.field;
@@ -965,6 +967,8 @@ long dbGet(DBADDR *paddr, short dbrType,
if (nRequest) {
if (no_elements < *nRequest)
*nRequest = no_elements;
+ if (capacity < *nRequest)
+ *nRequest = capacity;
n = *nRequest;
} else {
n = 1;
@@ -981,14 +985,15 @@ long dbGet(DBADDR *paddr, short dbrType,
}
/* convert data into the caller's buffer */
if (n <= 0) {
- ;/*do nothing*/
- } else if (!pfl || pfl->type == dbfl_type_rec) {
+ ; /*do nothing */
+ } else if (!pfl) {
status = convert(paddr, pbuf, n, capacity, offset);
} else {
DBADDR localAddr = *paddr; /* Structure copy */
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
+ /* not used by dbConvert, it uses the passed capacity instead: */
localAddr.no_elements = pfl->no_elements;
if (pfl->type == dbfl_type_val)
localAddr.pfield = (char *) &pfl->u.v.field;
diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h
index 805dfd4..4a95989 100644
--- a/modules/database/src/ioc/db/dbAccessDefs.h
+++ b/modules/database/src/ioc/db/dbAccessDefs.h
@@ -243,7 +243,7 @@ epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp);
epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset);
epicsShareFunc long dbGetField(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
- long *nRequest,void *pfl);
+ long *nRequest);
epicsShareFunc long dbGet(
struct dbAddr *,short dbrType,void *pbuffer,long *options,
long *nRequest,void *pfl);
diff --git a/modules/database/src/ioc/db/dbChannel.c b/modules/database/src/ioc/db/dbChannel.c
index a8bfbf1..4c1215c 100644
--- a/modules/database/src/ioc/db/dbChannel.c
+++ b/modules/database/src/ioc/db/dbChannel.c
@@ -49,14 +49,12 @@ typedef struct parseContext {
static void *dbChannelFreeList;
static void *chFilterFreeList;
-static void *dbchStringFreeList;
void dbChannelExit(void)
{
freeListCleanup(dbChannelFreeList);
freeListCleanup(chFilterFreeList);
- freeListCleanup(dbchStringFreeList);
- dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL;
+ dbChannelFreeList = chFilterFreeList = NULL;
}
void dbChannelInit (void)
@@ -66,7 +64,6 @@ void dbChannelInit (void)
freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128);
freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64);
- freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128);
db_init_event_freelists();
}
@@ -446,28 +443,6 @@ static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppn
return status;
}
-/* Stolen from dbAccess.c: */
-static short mapDBFToDBR[DBF_NTYPES] =
- {
- /* DBF_STRING => */DBR_STRING,
- /* DBF_CHAR => */DBR_CHAR,
- /* DBF_UCHAR => */DBR_UCHAR,
- /* DBF_SHORT => */DBR_SHORT,
- /* DBF_USHORT => */DBR_USHORT,
- /* DBF_LONG => */DBR_LONG,
- /* DBF_ULONG => */DBR_ULONG,
- /* DBF_INT64 => */DBR_INT64,
- /* DBF_UINT64 => */DBR_UINT64,
- /* DBF_FLOAT => */DBR_FLOAT,
- /* DBF_DOUBLE => */DBR_DOUBLE,
- /* DBF_ENUM, => */DBR_ENUM,
- /* DBF_MENU, => */DBR_ENUM,
- /* DBF_DEVICE => */DBR_ENUM,
- /* DBF_INLINK => */DBR_STRING,
- /* DBF_OUTLINK => */DBR_STRING,
- /* DBF_FWDLINK => */DBR_STRING,
- /* DBF_NOACCESS => */DBR_NOACCESS };
-
dbChannel * dbChannelCreate(const char *name)
{
const char *pname = name;
@@ -736,37 +711,24 @@ void dbChannelDelete(dbChannel *chan)
freeListFree(dbChannelFreeList, chan);
}
-static void freeArray(db_field_log *pfl) {
- if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
- freeListFree(dbchStringFreeList, pfl->u.r.field);
- } else {
- free(pfl->u.r.field);
- }
-}
-
-void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan)
+/*
+ * Helper function to adjust no_elements, offset, and pfield
+ * when copying an array from a record.
+ */
+void dbChannelGetArrayInfo(dbChannel *chan,
+ void **pfield, long *no_elements, long *offset)
{
- void *p;
- struct dbCommon *prec = dbChannelRecord(chan);
-
- if (pfl->type != dbfl_type_rec) return;
-
- pfl->type = dbfl_type_ref;
- pfl->stat = prec->stat;
- pfl->sevr = prec->sevr;
- pfl->time = prec->time;
- pfl->field_type = chan->addr.field_type;
- pfl->no_elements = chan->addr.no_elements;
- pfl->field_size = chan->addr.field_size;
- pfl->u.r.dtor = freeArray;
- pfl->u.r.pvt = pvt;
- if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) {
- p = freeListCalloc(dbchStringFreeList);
- } else {
- p = calloc(pfl->no_elements, pfl->field_size);
+ rset *prset;
+ if (dbChannelSpecial(chan) == SPC_DBADDR &&
+ (prset = dbGetRset(&chan->addr)) &&
+ prset->get_array_info)
+ {
+ void *pfieldsave = dbChannelField(chan);
+ /* it is expected that this call always succeeds */
+ prset->get_array_info(&chan->addr, no_elements, offset);
+ *pfield = dbChannelField(chan);
+ dbChannelField(chan) = pfieldsave;
}
- if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL);
- pfl->u.r.field = p;
}
/* FIXME: Do these belong in a different file? */
diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h
index fab9c66..7bfc9b0 100644
--- a/modules/database/src/ioc/db/dbChannel.h
+++ b/modules/database/src/ioc/db/dbChannel.h
@@ -64,8 +64,9 @@ typedef struct dbChannel {
/* Prototype for the channel event function that is called in filter stacks
*
* When invoked the scan lock for the record associated with 'chan' _may_ be locked.
- * If pLog->type==dbfl_type_rec then dbScanLock() must be called before copying
- * data out of the associated record.
+ * If pLog->type==dbfl_type_ref and pLog->u.r.dtor is NULL, then dbScanLock() must
+ * be called before accessing the data, as this indicates the data is owned by the
+ * record.
*
* This function has ownership of the field log pLog, if it wishes to discard
* this update it should free the field log with db_delete_field_log() and
@@ -224,7 +225,8 @@ epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, voi
epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn);
epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len);
-epicsShareFunc void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan);
+epicsShareFunc void dbChannelGetArrayInfo(dbChannel *chan,
+ void **pfield, long *no_elements, long *offset);
#ifdef __cplusplus
}
diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c
index 688cb7a..4e1dc69 100644
--- a/modules/database/src/ioc/db/dbDbLink.c
+++ b/modules/database/src/ioc/db/dbDbLink.c
@@ -203,7 +203,10 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
/* filter, array, or special */
ppv_link->getCvt = NULL;
- /* For the moment, empty arrays are not supported by EPICS */
+ /*
+ * For the moment, empty arrays are not supported by EPICS.
+ * See the remark in src/std/filters/arr.c for details.
+ */
if (dbChannelFinalElements(chan) <= 0) /* empty array request */
return S_db_badField;
diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c
index ed73529..f3a6907 100644
--- a/modules/database/src/ioc/db/dbEvent.c
+++ b/modules/database/src/ioc/db/dbEvent.c
@@ -667,27 +667,21 @@ int db_post_extra_labor (dbEventCtx ctx)
return DB_EVENT_OK;
}
-/*
- * DB_CREATE_EVENT_LOG()
- *
- * NOTE: This assumes that the db scan lock is already applied
- * (as it copies data from the record)
- */
-db_field_log* db_create_event_log (struct evSubscrip *pevent)
+static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val)
{
db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
if (pLog) {
- struct dbChannel *chan = pevent->chan;
struct dbCommon *prec = dbChannelRecord(chan);
- pLog->ctx = dbfl_context_event;
- if (pevent->useValque) {
+ pLog->stat = prec->stat;
+ pLog->sevr = prec->sevr;
+ pLog->time = prec->time;
+ pLog->field_type = dbChannelFieldType(chan);
+ pLog->field_size = dbChannelFieldSize(chan);
+ pLog->no_elements = dbChannelElements(chan);
+
+ if (use_val) {
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
@@ -697,23 +691,46 @@ db_field_log* db_create_event_log (struct evSubscrip *pevent)
dbChannelField(chan),
dbChannelFieldSize(chan));
} else {
- pLog->type = dbfl_type_rec;
+ pLog->type = dbfl_type_ref;
+
+ /* don't make a copy yet, just reference the field value */
+ pLog->u.r.field = dbChannelField(chan);
+ /* indicate field value still owned by record */
+ pLog->u.r.dtor = NULL;
+ /* no private data yet, may be set by a filter */
+ pLog->u.r.pvt = NULL;
}
}
return pLog;
}
/*
+ * DB_CREATE_EVENT_LOG()
+ *
+ * NOTE: This assumes that the db scan lock is already applied
+ * (as it calls rset->get_array_info)
+ */
+db_field_log* db_create_event_log (struct evSubscrip *pevent)
+{
+ db_field_log *pLog = db_create_field_log(pevent->chan, pevent->useValque);
+ if (pLog) {
+ pLog->ctx = dbfl_context_event;
+ }
+ return pLog;
+}
+
+/*
* DB_CREATE_READ_LOG()
*
*/
db_field_log* db_create_read_log (struct dbChannel *chan)
{
- db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList);
-
+ db_field_log *pLog = db_create_field_log(chan,
+ dbChannelElements(chan) == 1 &&
+ dbChannelSpecial(chan) != SPC_DBADDR &&
+ dbChannelFieldSize(chan) <= sizeof(union native_value));
if (pLog) {
pLog->ctx = dbfl_context_read;
- pLog->type = dbfl_type_rec;
}
return pLog;
}
@@ -737,20 +754,6 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
LOCKEVQUE (ev_que);
/*
- * 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->npend > 0u &&
- (*pevent->pLastLog)->type == dbfl_type_rec &&
- pLog->type == dbfl_type_rec) {
- db_delete_field_log(pLog);
- UNLOCKEVQUE (ev_que);
- return;
- }
-
- /*
* add to task local event que
*/
diff --git a/modules/database/src/ioc/db/dbExtractArray.c b/modules/database/src/ioc/db/dbExtractArray.c
index e16ab4c..667de24 100644
--- a/modules/database/src/ioc/db/dbExtractArray.c
+++ b/modules/database/src/ioc/db/dbExtractArray.c
@@ -13,11 +13,12 @@
/*
* Author: Ralph Lange <Ralph.Lange at bessy.de>
*
- * based on dbConvert.c
+ * based on dbConvert.c, see copyNoConvert
* written by: Bob Dalesio, Marty Kraimer
*/
#include <string.h>
+#include <assert.h>
#include "epicsTypes.h"
@@ -25,61 +26,30 @@
#include "dbAddr.h"
#include "dbExtractArray.h"
-void dbExtractArrayFromRec(const dbAddr *paddr, void *pto,
- long nRequest, long no_elements, long offset, long increment)
+void dbExtractArray(const void *pfrom, void *pto, short field_size,
+ long nRequest, long no_elements, long offset, long increment)
{
char *pdst = (char *) pto;
- char *psrc = (char *) paddr->pfield;
- long nUpperPart;
- int i;
- short srcSize = paddr->field_size;
- short dstSize = srcSize;
- char isString = (paddr->field_type == DBF_STRING);
+ const char *psrc = (char *) pfrom;
- if (nRequest > no_elements) nRequest = no_elements;
- if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE;
+ /* assert preconditions */
+ assert(nRequest >= 0);
+ assert(no_elements >= 0);
+ assert(increment > 0);
+ assert(0 <= offset);
+ assert(offset < no_elements);
- if (increment == 1 && dstSize == srcSize) {
- nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset;
- memcpy(pdst, &psrc[offset * srcSize], dstSize * nUpperPart);
+ if (increment == 1) {
+ long nUpperPart =
+ nRequest < no_elements - offset ? nRequest : no_elements - offset;
+ memcpy(pdst, psrc + (offset * field_size), field_size * nUpperPart);
if (nRequest > nUpperPart)
- memcpy(&pdst[dstSize * nUpperPart], psrc, dstSize * (nRequest - nUpperPart));
- if (isString)
- for (i = 1; i <= nRequest; i++)
- pdst[dstSize*i-1] = '\0';
+ memcpy(pdst + (field_size * nUpperPart), psrc,
+ field_size * (nRequest - nUpperPart));
} else {
- for (; nRequest > 0; nRequest--, pdst += dstSize, offset += increment) {
+ for (; nRequest > 0; nRequest--, pdst += field_size, offset += increment) {
offset %= no_elements;
- memcpy(pdst, &psrc[offset*srcSize], dstSize);
- if (isString) pdst[dstSize-1] = '\0';
- }
- }
-}
-
-void dbExtractArrayFromBuf(const void *pfrom, void *pto,
- short field_size, short field_type,
- long nRequest, long no_elements, long offset, long increment)
-{
- char *pdst = (char *) pto;
- char *psrc = (char *) pfrom;
- int i;
- short srcSize = field_size;
- short dstSize = srcSize;
- char isString = (field_type == DBF_STRING);
-
- if (nRequest > no_elements) nRequest = no_elements;
- if (offset > no_elements - 1) offset = no_elements - 1;
- if (isString && dstSize >= MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE - 1;
-
- if (increment == 1) {
- memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest);
- if (isString)
- for (i = 1; i <= nRequest; i++)
- pdst[dstSize*i] = '\0';
- } else {
- for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) {
- memcpy(pdst, &psrc[offset*srcSize], dstSize);
- if (isString) pdst[dstSize] = '\0';
+ memcpy(pdst, psrc + (offset * field_size), field_size);
}
}
}
diff --git a/modules/database/src/ioc/db/dbExtractArray.h b/modules/database/src/ioc/db/dbExtractArray.h
index 7ed3584..374d1d1 100644
--- a/modules/database/src/ioc/db/dbExtractArray.h
+++ b/modules/database/src/ioc/db/dbExtractArray.h
@@ -21,11 +21,36 @@
extern "C" {
#endif
-epicsShareFunc void dbExtractArrayFromRec(const DBADDR *paddr, void *pto,
- long nRequest, long no_elements, long offset, long increment);
-epicsShareFunc void dbExtractArrayFromBuf(const void *pfrom, void *pto,
- short field_size, short field_type,
- long nRequest, long no_elements, long offset, long increment);
+/** @brief Make a copy of parts of an array.
+ *
+ * The source array may or may not be a record field.
+ *
+ * The increment parameter is used to support array filters; it
+ * means: copy only every increment'th element, starting at offset.
+ *
+ * The offset and no_elements parameters are used to support the
+ * circular buffer feature of record fields: elements before offset
+ * are treated as if they came right after no_elements.
+ *
+ * This function does not do any conversion on the array elements.
+ *
+ * Preconditions:
+ * nRequest >= 0, no_elements >= 0, increment > 0
+ * 0 <= offset < no_elements
+ * pto points to a buffer with at least field_size*nRequest bytes
+ * pfrom points to a buffer with exactly field_size*no_elements bytes
+ *
+ * @param pfrom Pointer to source array.
+ * @param pto Pointer to target array.
+ * @param field_size Size of an array element.
+ * @param nRequest Number of elements to copy.
+ * @param no_elements Number of elements in source array.
+ * @param offset Wrap-around point in source array.
+ * @param increment Copy only every increment'th element.
+ */
+epicsShareFunc void dbExtractArray(const void *pfrom, void *pto,
+ short field_size, long nRequest, long no_elements, long offset,
+ long increment);
#ifdef __cplusplus
}
diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c
index 1193954..206d6c9 100644
--- a/modules/database/src/ioc/db/dbTest.c
+++ b/modules/database/src/ioc/db/dbTest.c
@@ -341,14 +341,14 @@ long dbgf(const char *pname)
no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size);
if (addr.dbr_field_type == DBR_ENUM) {
long status = dbGetField(&addr, DBR_STRING, pbuffer,
- &options, &no_elements, NULL);
+ &options, &no_elements);
printBuffer(status, DBR_STRING, pbuffer, 0L, 0L,
no_elements, &msg_Buff, 10);
}
else {
long status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
- &options, &no_elements, NULL);
+ &options, &no_elements);
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
no_elements, &msg_Buff, 10);
@@ -487,7 +487,7 @@ long dbtgf(const char *pname)
ret_options = req_options;
no_elements = 0;
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
- &ret_options, &no_elements, NULL);
+ &ret_options, &no_elements);
printBuffer(status, addr.dbr_field_type, pbuffer,
req_options, ret_options, no_elements, pMsgBuff, tab_size);
@@ -496,62 +496,62 @@ long dbtgf(const char *pname)
dbr_type = DBR_STRING;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_CHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UCHAR;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_SHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_USHORT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_LONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ULONG;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_INT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_UINT64;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_FLOAT;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_DOUBLE;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
dbr_type = DBR_ENUM;
no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16)));
- status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL);
+ status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements);
printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size);
pmsg[0] = '\0';
@@ -651,7 +651,7 @@ long dbtpf(const char *pname, const char *pvalue)
printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]);
status = dbGetField(&addr, addr.dbr_field_type, pbuffer,
- &options, &no_elements, NULL);
+ &options, &no_elements);
printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L,
no_elements, pMsgBuff, tab_size);
}
diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c
index 6846ef5..458a28b 100644
--- a/modules/database/src/ioc/db/dbUnitTest.c
+++ b/modules/database/src/ioc/db/dbUnitTest.c
@@ -197,7 +197,7 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap)
return;
}
- status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL);
+ status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status));
return;
@@ -270,7 +270,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
return;
}
- status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL);
+ status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest);
if (status) {
testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status);
diff --git a/modules/database/src/ioc/db/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h
index 1534517..a801142 100644
--- a/modules/database/src/ioc/db/db_field_log.h
+++ b/modules/database/src/ioc/db/db_field_log.h
@@ -56,20 +56,31 @@ union native_value {
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 */
+/*
+ * A db_field_log has one of two types:
+ *
+ * dbfl_type_ref - Reference to value
+ * Used for variable size (array) data types. Meta-data
+ * is stored in the field log, but value data is stored externally.
+ * Only the dbfl_ref side of the data union is valid.
+ *
+ * dbfl_type_val - Internal value
+ * Used to store small scalar data. Meta-data and value are
+ * present in this structure and no external references are used.
+ * Only the dbfl_val side of the data union is valid.
+ */
typedef enum dbfl_type {
- dbfl_type_rec = 0,
dbfl_type_val,
dbfl_type_ref
} dbfl_type;
/* Context of db_field_log: event = subscription update, read = read reply */
typedef enum dbfl_context {
- dbfl_context_read = 0,
+ dbfl_context_read,
dbfl_context_event
} dbfl_context;
-#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref")
+#define dbflTypeStr(t) (t==dbfl_type_val?"val":"ref")
struct dbfl_val {
union native_value field; /* Field value */
@@ -81,6 +92,8 @@ struct dbfl_val {
* db_delete_field_log(). Any code which changes a dbfl_type_ref
* field log to another type, or to reference different data,
* must explicitly call the dtor function.
+ * If the dtor is NULL, then this means the array data is still owned
+ * by a record.
*/
struct dbfl_ref {
dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */
@@ -88,8 +101,11 @@ struct dbfl_ref {
void *field; /* Field value */
};
+/*
+ * Note that field_size may be larger than MAX_STRING_SIZE.
+ */
typedef struct db_field_log {
- unsigned int type:2; /* type (union) selector */
+ unsigned int type:1; /* type (union) selector */
/* ctx is used for all types */
unsigned int ctx:1; /* context (operation type) */
/* the following are used for value and reference types */
@@ -97,37 +113,14 @@ typedef struct db_field_log {
unsigned short stat; /* Alarm Status */
unsigned short sevr; /* Alarm Severity */
short field_type; /* DBF type of data */
- short field_size; /* Data size */
- long no_elements; /* No of array elements */
+ short field_size; /* Size of a single element */
+ long no_elements; /* No of valid array elements */
union {
struct dbfl_val v;
struct dbfl_ref r;
} u;
} db_field_log;
-/*
- * A db_field_log will in one of three types:
- *
- * dbfl_type_rec - Reference to record
- * The field log stores no data itself. Data must instead be taken
- * via the dbChannel* which must always be provided when along
- * with the field log.
- * For this type only the 'type' and 'ctx' members are used.
- *
- * dbfl_type_ref - Reference to outside value
- * Used for variable size (array) data types. Meta-data
- * is stored in the field log, but value data is stored externally
- * (see struct dbfl_ref).
- * For this type all meta-data members are used. The dbfl_ref side of the
- * data union is used.
- *
- * dbfl_type_val - Internal value
- * Used to store small scalar data. Meta-data and value are
- * present in this structure and no external references are used.
- * For this type all meta-data members are used. The dbfl_val side of the
- * data union is used.
- */
-
#ifdef __cplusplus
}
#endif
diff --git a/modules/database/src/std/filters/arr.c b/modules/database/src/std/filters/arr.c
index f91708a..1e506a2 100644
--- a/modules/database/src/std/filters/arr.c
+++ b/modules/database/src/std/filters/arr.c
@@ -12,16 +12,14 @@
#include <stdio.h>
-#include <freeList.h>
-#include <dbAccess.h>
-#include <dbExtractArray.h>
-#include <db_field_log.h>
-#include <dbLock.h>
-#include <recSup.h>
-#include <epicsExit.h>
-#include <special.h>
-#include <chfPlugin.h>
-#include <epicsExport.h>
+#include "chfPlugin.h"
+#include "dbAccessDefs.h"
+#include "dbExtractArray.h"
+#include "db_field_log.h"
+#include "dbLock.h"
+#include "epicsExit.h"
+#include "freeList.h"
+#include "epicsExport.h"
typedef struct myStruct {
epicsInt32 start;
@@ -45,6 +43,8 @@ static void * allocPvt(void)
myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
if (!my) return NULL;
+ /* defaults */
+ my->start = 0;
my->incr = 1;
my->end = -1;
return (void *) my;
@@ -76,8 +76,6 @@ static void freeArray(db_field_log *pfl)
static long wrapArrayIndices(long *start, const long increment, long *end,
const long no_elements)
{
- long len = 0;
-
if (*start < 0) *start = no_elements + *start;
if (*start < 0) *start = 0;
if (*start > no_elements) *start = no_elements;
@@ -86,19 +84,22 @@ static long wrapArrayIndices(long *start, const long increment, long *end,
if (*end < 0) *end = 0;
if (*end >= no_elements) *end = no_elements - 1;
- if (*end - *start >= 0) len = 1 + (*end - *start) / increment;
- return len;
+ if (*end - *start >= 0)
+ return 1 + (*end - *start) / increment;
+ else
+ return 0;
}
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
{
myStruct *my = (myStruct*) pvt;
- struct dbCommon *prec;
- rset *prset;
+ int must_lock;
long start = my->start;
long end = my->end;
- long nTarget = 0;
+ long nTarget;
+ void *pTarget;
long offset = 0;
+<<<<<<< modules/database/src/std/filters/arr.c
long nSource = dbChannelElements(chan);
long capacity = nSource;
void *pdst;
@@ -141,30 +142,52 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
dbScanUnlock(prec);
dbChannelField(chan) = pfieldsave;
}
+=======
+ long nSource = pfl->no_elements;
+ void *pSource = pfl->u.r.field;
+
+ switch (pfl->type) {
+ case dbfl_type_val:
+ /* TODO Treat scalars as arrays with 1 element */
+>>>>>>> modules/database/src/std/filters/arr.c
break;
- /* Extract from buffer */
case dbfl_type_ref:
- pdst = NULL;
- nSource = pfl->no_elements;
- nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
- pfl->no_elements = nTarget;
- if (nTarget) {
- /* Copy the data out */
- void *psrc = pfl->u.r.field;
-
- pdst = freeListCalloc(my->arrayFreeList);
- if (!pdst) break;
- offset = start;
- dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type,
- nTarget, nSource, offset, my->incr);
+ must_lock = !pfl->u.r.dtor;
+ if (must_lock) {
+ dbScanLock(dbChannelRecord(chan));
+ dbChannelGetArrayInfo(chan, &pSource, &nSource, &offset);
}
- if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
- if (nTarget) {
+ nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
+ if (nTarget > 0) {
+ /* copy the data */
+ pTarget = freeListCalloc(my->arrayFreeList);
+ if (!pTarget) break;
+ /* must do the wrap-around with the original no_elements */
+ offset = (offset + start) % pfl->no_elements;
+ dbExtractArray(pSource, pTarget, pfl->field_size,
+ nTarget, pfl->no_elements, offset, my->incr);
+ if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
+ pfl->u.r.field = pTarget;
pfl->u.r.dtor = freeArray;
pfl->u.r.pvt = my->arrayFreeList;
- pfl->u.r.field = pdst;
}
+ /* Adjust no_elements to refer to the new pTarget.
+ *
+ * Setting pfl->no_elements outside of the "if" clause above is
+ * done to make requests fail if nTarget is zero, that is, if all
+ * elements selected by the filter are outside the array bounds.
+ * TODO:
+ * It would be possible to lift this restriction by interpreting
+ * a request with *no* number of elements (NULL pointer) as scalar
+ * (meaning: fail if we get less than one element); in contrast,
+ * a request that explicitly specifies one element would be
+ * interpreted as an array request, for which zero elements would
+ * be a normal expected result.
+ */
+ pfl->no_elements = nTarget;
+ if (must_lock)
+ dbScanUnlock(dbChannelRecord(chan));
break;
}
return pfl;
diff --git a/modules/database/src/std/filters/ts.c b/modules/database/src/std/filters/ts.c
index 5925b0b..aed3b41 100644
--- a/modules/database/src/std/filters/ts.c
+++ b/modules/database/src/std/filters/ts.c
@@ -11,21 +11,44 @@
*/
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
-#include <chfPlugin.h>
-#include <dbLock.h>
-#include <db_field_log.h>
-#include <epicsExport.h>
+#include "chfPlugin.h"
+#include "db_field_log.h"
+#include "dbExtractArray.h"
+#include "dbLock.h"
+#include "epicsExport.h"
+
+/*
+ * The size of the data is different for each channel, and can even
+ * change at runtime, so a freeList doesn't make much sense here.
+ */
+static void freeArray(db_field_log *pfl) {
+ free(pfl->u.r.field);
+}
static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
epicsTimeStamp now;
epicsTimeGetCurrent(&now);
- /* If string or array, must make a copy (to ensure coherence between time and data) */
- if (pfl->type == dbfl_type_rec) {
- dbScanLock(dbChannelRecord(chan));
- dbChannelMakeArrayCopy(pvt, pfl, chan);
- dbScanUnlock(dbChannelRecord(chan));
+ /* If reference and not already copied,
+ must make a copy (to ensure coherence between time and data) */
+ if (pfl->type == dbfl_type_ref && !pfl->u.r.dtor) {
+ void *pTarget = calloc(pfl->no_elements, pfl->field_size);
+ void *pSource = pfl->u.r.field;
+ if (pTarget) {
+ long offset = 0;
+ long nSource = pfl->no_elements;
+ dbScanLock(dbChannelRecord(chan));
+ dbChannelGetArrayInfo(chan, &pSource, &nSource, &offset);
+ dbExtractArray(pSource, pTarget, pfl->field_size,
+ nSource, pfl->no_elements, offset, 1);
+ pfl->u.r.field = pTarget;
+ pfl->u.r.dtor = freeArray;
+ pfl->u.r.pvt = pvt;
+ dbScanUnlock(dbChannelRecord(chan));
+ }
}
pfl->time = now;
diff --git a/modules/database/test/ioc/db/dbChArrTest.cpp b/modules/database/test/ioc/db/dbChArrTest.cpp
index 8255fdc..6ec6ea4 100644
--- a/modules/database/test/ioc/db/dbChArrTest.cpp
+++ b/modules/database/test/ioc/db/dbChArrTest.cpp
@@ -130,7 +130,7 @@ static void check(short dbr_type) {
memset(buf, 0, sizeof(buf)); \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
- testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \
+ testOk(pfl && pfl->type == dbfl_type_ref, "Valid pfl, type = ref"); \
testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \
testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \
if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \
diff --git a/modules/database/test/std/filters/arrTest.cpp b/modules/database/test/std/filters/arrTest.cpp
index 1ec16b3..5db3757 100644
--- a/modules/database/test/std/filters/arrTest.cpp
+++ b/modules/database/test/std/filters/arrTest.cpp
@@ -72,9 +72,9 @@ static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) {
}
break;
case DBR_STRING:
- if (strtol(&((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], NULL, 0) != ((epicsInt32*)p2)[i]) {
+ if (strtol(&((const char*)pfl1->u.r.field)[i*pfl1->field_size], NULL, 0) != ((epicsInt32*)p2)[i]) {
testDiag("at index=%d: field log has '%s', should be '%d'",
- i, &((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], ((epicsInt32*)p2)[i]);
+ i, &((const char*)pfl1->u.r.field)[i*pfl1->field_size], ((epicsInt32*)p2)[i]);
return 0;
}
break;
@@ -119,7 +119,7 @@ static void testHead (const char *title, const char *typ = "") {
off = Offset; \
(void) dbPutField(&offaddr, DBR_LONG, &off, 1); \
pfl = db_create_read_log(pch); \
- testOk(pfl->type == dbfl_type_rec, "original field log has type rec"); \
+ testOk(pfl->type == dbfl_type_ref, "original field log has type ref"); \
pfl2 = dbChannelRunPostChain(pch, pfl); \
testOk(pfl2 == pfl, "call does not drop or replace field_log"); \
testOk(pfl->type == dbfl_type_ref, "filtered field log has type ref"); \
diff --git a/modules/database/test/std/filters/dbndTest.c b/modules/database/test/std/filters/dbndTest.c
index 4d70f83..fd4a472 100644
--- a/modules/database/test/std/filters/dbndTest.c
+++ b/modules/database/test/std/filters/dbndTest.c
@@ -129,7 +129,7 @@ MAIN(dbndTest)
dbEventCtx evtctx;
int logsFree, logsFinal;
- testPlan(77);
+ testPlan(72);
testdbPrepare();
@@ -170,12 +170,9 @@ MAIN(dbndTest)
"dbnd has one filter with argument in pre chain");
testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain");
- /* Field logs of type ref and rec: pass any update */
-
- testHead("Field logs of type ref and rec");
- fl1.type = dbfl_type_rec;
- mustPassTwice(pch, &fl1, "abs field_log=rec", 0., 0);
+ /* Field logs of type ref: pass any update */
+ testHead("Field logs of type ref");
fl1.type = dbfl_type_ref;
mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0);
- Replies:
- Re: [Merge] ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 Ben Franksen via Core-talk
- Re: [Merge] ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 Ben Franksen via Core-talk
- Navigate by Date:
- Prev:
[Merge] ~bfrk/epics-base:write-filters into epics-base:7.0 Ben Franksen via Core-talk
- Next:
Re: [Merge] ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 Ben Franksen via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
[Merge] ~anj/epics-base/+git/base-7.0:add-makeAPIheader into epics-base:7.0 mdavidsaver via Core-talk
- Next:
Re: [Merge] ~bfrk/epics-base:remove-dbfl_type_rec into epics-base:7.0 Ben Franksen via Core-talk
- Index:
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024
|