From 4ab9808180b8a4cc59294b2f52687e5311f50635 Mon Sep 17 00:00:00 2001 From: Ben Franksen Date: Mon, 30 Mar 2020 21:46:46 +0200 Subject: [PATCH 01/52] make it clearer what the result of wrapArrayIndices will be --- modules/database/src/std/filters/arr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/database/src/std/filters/arr.c b/modules/database/src/std/filters/arr.c index 813848076..cfa7118bf 100644 --- a/modules/database/src/std/filters/arr.c +++ b/modules/database/src/std/filters/arr.c @@ -77,8 +77,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; @@ -87,8 +85,10 @@ 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) From 27fe3e4468ec62d4d17f775c4aced939a666ba36 Mon Sep 17 00:00:00 2001 From: Ben Franksen Date: Mon, 30 Mar 2020 21:34:32 +0200 Subject: [PATCH 02/52] refactor db_field_log and filters to get rid of dbfl_type_rec This refactor simplifies and streamlines the code associated with server side filters. Apart from immediate benefits (clearer code, less duplication) it is also hoped that this will make it easier to add write filters. The data pointer dbfl_ref.field can now either point to a copy owned by a filter, or it can point to the original data owned by a record. In the latter case, the dbfl_ref.dtor is NULL. The dbExtractArray* functions are unified to the single function dbExtractArray and stripped of conversion functionality. This is redundant because we always call dbGet after applying filters, which takes care of conversion. Accordingly, dbChannelMakeArrayCopy is now obsolete and its single use (in the ts filter) replaced with dbExtractArray. Instead, we add the helper function dbChannelGetArrayInfo to wrap the common boilerplate around calls to the get_array_info method, used in both arr.c and ts.c. --- modules/database/src/ioc/db/dbAccess.c | 39 +++--- modules/database/src/ioc/db/dbChannel.c | 72 +++-------- modules/database/src/ioc/db/dbChannel.h | 8 +- modules/database/src/ioc/db/dbEvent.c | 69 ++++++----- modules/database/src/ioc/db/dbExtractArray.c | 70 +++-------- modules/database/src/ioc/db/dbExtractArray.h | 35 +++++- modules/database/src/ioc/db/db_field_log.h | 53 ++++---- modules/database/src/std/filters/arr.c | 116 +++++++----------- modules/database/src/std/filters/ts.c | 41 +++++-- modules/database/test/ioc/db/dbChArrTest.cpp | 2 +- modules/database/test/std/filters/arrTest.cpp | 6 +- modules/database/test/std/filters/dbndTest.c | 9 +- 12 files changed, 239 insertions(+), 281 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index d7e5d0890..39e6e9a98 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -339,7 +339,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; @@ -349,7 +349,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 { @@ -383,7 +383,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 { @@ -904,22 +904,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; } @@ -951,7 +952,7 @@ long dbGet(DBADDR *paddr, short dbrType, goto done; } - if (!pfl || pfl->type == dbfl_type_rec) { + if (!pfl) { status = dbFastGetConvertRoutine[field_type][dbrType] (paddr->pfield, pbuf, paddr); } else { @@ -964,6 +965,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; @@ -979,6 +981,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; @@ -995,8 +999,8 @@ 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 */ @@ -1008,6 +1012,7 @@ long dbGet(DBADDR *paddr, short dbrType, 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/dbChannel.c b/modules/database/src/ioc/db/dbChannel.c index b6f53f797..c71d8426f 100644 --- a/modules/database/src/ioc/db/dbChannel.c +++ b/modules/database/src/ioc/db/dbChannel.c @@ -52,14 +52,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) @@ -69,7 +67,6 @@ void dbChannelInit (void) freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128); freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64); - freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128); db_init_event_freelists(); } @@ -449,28 +446,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; @@ -743,37 +718,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 1ca02bbb6..063d91aa5 100644 --- a/modules/database/src/ioc/db/dbChannel.h +++ b/modules/database/src/ioc/db/dbChannel.h @@ -65,8 +65,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 @@ -225,7 +226,8 @@ DBCORE_API void dbRegisterFilter(const char *key, const chFilterIf *fif, void *p DBCORE_API db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn); DBCORE_API db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn); DBCORE_API const chFilterPlugin * dbFindFilter(const char *key, size_t len); -DBCORE_API void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan); +DBCORE_API void dbChannelGetArrayInfo(dbChannel *chan, + void **pfield, long *no_elements, long *offset); #ifdef __cplusplus } diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 437cb6d5d..1db01f2cd 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -668,27 +668,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 @@ -698,23 +692,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 a7dcf4d0c..197e66c3a 100644 --- a/modules/database/src/ioc/db/dbExtractArray.c +++ b/modules/database/src/ioc/db/dbExtractArray.c @@ -14,11 +14,12 @@ /* * Author: Ralph Lange * - * based on dbConvert.c + * based on dbConvert.c, see copyNoConvert * written by: Bob Dalesio, Marty Kraimer */ #include +#include #include "epicsTypes.h" @@ -26,61 +27,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; - - if (increment == 1 && dstSize == srcSize) { - nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset; - memcpy(pdst, &psrc[offset * srcSize], dstSize * 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'; - } else { - for (; nRequest > 0; nRequest--, pdst += dstSize, 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; + /* assert preconditions */ + assert(nRequest >= 0); + assert(no_elements >= 0); + assert(increment > 0); + assert(0 <= offset); + assert(offset < no_elements); if (increment == 1) { - memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest); - if (isString) - for (i = 1; i <= nRequest; i++) - pdst[dstSize*i] = '\0'; + long nUpperPart = + nRequest < no_elements - offset ? nRequest : no_elements - offset; + memcpy(pdst, psrc + (offset * field_size), field_size * nUpperPart); + if (nRequest > nUpperPart) + memcpy(pdst + (field_size * nUpperPart), psrc, + field_size * (nRequest - nUpperPart)); } else { - for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) { - memcpy(pdst, &psrc[offset*srcSize], dstSize); - if (isString) pdst[dstSize] = '\0'; + for (; nRequest > 0; nRequest--, pdst += field_size, offset += increment) { + offset %= no_elements; + 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 b44bd15fc..9755ac570 100644 --- a/modules/database/src/ioc/db/dbExtractArray.h +++ b/modules/database/src/ioc/db/dbExtractArray.h @@ -22,11 +22,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/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h index 5a40f5fad..a043899ae 100644 --- a/modules/database/src/ioc/db/db_field_log.h +++ b/modules/database/src/ioc/db/db_field_log.h @@ -57,20 +57,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 */ @@ -82,6 +93,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 */ @@ -89,8 +102,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 */ @@ -98,37 +114,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 cfa7118bf..5f251844a 100644 --- a/modules/database/src/std/filters/arr.c +++ b/modules/database/src/std/filters/arr.c @@ -13,16 +13,14 @@ #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#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; @@ -46,6 +44,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; @@ -94,78 +94,56 @@ static long wrapArrayIndices(long *start, const long increment, long *end, 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; - long nSource = dbChannelElements(chan); - long capacity = nSource; - void *pdst; + long nSource = pfl->no_elements; + void *pSource = pfl->u.r.field; switch (pfl->type) { case dbfl_type_val: - /* Only filter arrays */ + /* TODO Treat scalars as arrays with 1 element */ break; - case dbfl_type_rec: - /* Extract from record */ - if (dbChannelSpecial(chan) == SPC_DBADDR && - nSource > 1 && - (prset = dbGetRset(&chan->addr)) && - prset->get_array_info) - { - void *pfieldsave = dbChannelField(chan); - prec = dbChannelRecord(chan); - dbScanLock(prec); - prset->get_array_info(&chan->addr, &nSource, &offset); - nTarget = wrapArrayIndices(&start, my->incr, &end, nSource); - pfl->type = dbfl_type_ref; - pfl->stat = prec->stat; - pfl->sevr = prec->sevr; - pfl->time = prec->time; - pfl->field_type = dbChannelFieldType(chan); - pfl->field_size = dbChannelFieldSize(chan); - pfl->no_elements = nTarget; - if (nTarget) { - pdst = freeListCalloc(my->arrayFreeList); - if (pdst) { - pfl->u.r.dtor = freeArray; - pfl->u.r.pvt = my->arrayFreeList; - offset = (offset + start) % dbChannelElements(chan); - dbExtractArrayFromRec(&chan->addr, pdst, nTarget, capacity, - offset, my->incr); - pfl->u.r.field = pdst; - } - } - dbScanUnlock(prec); - dbChannelField(chan) = pfieldsave; - } - 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 8a07c3f2f..0feadb0f5 100644 --- a/modules/database/src/std/filters/ts.c +++ b/modules/database/src/std/filters/ts.c @@ -12,21 +12,44 @@ */ #include +#include +#include -#include -#include -#include -#include +#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 90702b52e..9965852a8 100644 --- a/modules/database/test/ioc/db/dbChArrTest.cpp +++ b/modules/database/test/ioc/db/dbChArrTest.cpp @@ -131,7 +131,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 bd83bd8ab..dfbbf463f 100644 --- a/modules/database/test/std/filters/arrTest.cpp +++ b/modules/database/test/std/filters/arrTest.cpp @@ -73,9 +73,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; @@ -120,7 +120,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 e7897e28a..0206865fb 100644 --- a/modules/database/test/std/filters/dbndTest.c +++ b/modules/database/test/std/filters/dbndTest.c @@ -130,7 +130,7 @@ MAIN(dbndTest) dbEventCtx evtctx; int logsFree, logsFinal; - testPlan(77); + testPlan(72); testdbPrepare(); @@ -171,12 +171,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); From 85822f3051d2236144bb46dc2c24b7e38143e531 Mon Sep 17 00:00:00 2001 From: Ben Franksen Date: Wed, 1 Apr 2020 10:42:22 +0200 Subject: [PATCH 03/52] add macro dbfl_has_copy to db_field_log.h and use it in dbAccess.c It encapsulates the slightly tricky logic to decide whether a pointer to a db_field_log has ownership of the data or not. --- modules/database/src/ioc/db/dbAccess.c | 6 +++--- modules/database/src/ioc/db/dbChannel.h | 5 ++--- modules/database/src/ioc/db/db_field_log.h | 16 ++++++++++++++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index 39e6e9a98..3f7554a58 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -912,10 +912,10 @@ long dbGet(DBADDR *paddr, short dbrType, no_elements = capacity = pfl->no_elements; } - /* Update field info from record - * may modify paddr->pfield + /* Update field info from record (if neccessary); + * may modify paddr->pfield. */ - if ((!pfl || (pfl->type==dbfl_type_ref && !pfl->u.r.dtor)) && + if (!dbfl_has_copy(pfl) && paddr->pfldDes->special == SPC_DBADDR && (prset = dbGetRset(paddr)) && prset->get_array_info) { diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h index 063d91aa5..ec86e9e28 100644 --- a/modules/database/src/ioc/db/dbChannel.h +++ b/modules/database/src/ioc/db/dbChannel.h @@ -65,9 +65,8 @@ 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_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. + * Unless dbfl_has_copy(pLog), it must call dbScanLock before accessing the data, + * as this indicates the data is still 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 diff --git a/modules/database/src/ioc/db/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h index a043899ae..222bad0c1 100644 --- a/modules/database/src/ioc/db/db_field_log.h +++ b/modules/database/src/ioc/db/db_field_log.h @@ -93,8 +93,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. + * If the dtor is NULL and no_elements > 0, then this means the array + * data is still owned by a record. See the macro dbfl_has_copy below. */ struct dbfl_ref { dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */ @@ -122,6 +122,18 @@ typedef struct db_field_log { } u; } db_field_log; +/* + * Whether a db_field_log* owns the field data. If this is the case, then the + * db_field_log is fully decoupled from the record: there is no need to lock + * the record when accessing the data, nor to call any rset methods (like + * get_array_info) because this has already been done when we made the copy. A + * special case here is that of no (remaining) data (i.e. no_elements==0). In + * this case, making a copy is redundant, so we have no dtor. But conceptually + * the db_field_log still owns the (empty) data. + */ +#define dbfl_has_copy(p)\ + ((p) && ((p)->type==dbfl_type_val || (p)->u.r.dtor || (p)->no_elements==0)) + #ifdef __cplusplus } #endif From 56f05d722dee4b8ca2968b8bface2737a3a9b185 Mon Sep 17 00:00:00 2001 From: Ben Franksen Date: Thu, 14 Jan 2021 17:38:58 +0100 Subject: [PATCH 04/52] fix in dbGet: decide use of db_field_log based on whether it has copy or not --- modules/database/src/ioc/db/dbAccess.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index 3f7554a58..d50b2561d 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -952,7 +952,7 @@ long dbGet(DBADDR *paddr, short dbrType, goto done; } - if (!pfl) { + if (!dbfl_has_copy(pfl)) { status = dbFastGetConvertRoutine[field_type][dbrType] (paddr->pfield, pbuf, paddr); } else { @@ -1000,7 +1000,7 @@ long dbGet(DBADDR *paddr, short dbrType, /* convert data into the caller's buffer */ if (n <= 0) { ; /*do nothing */ - } else if (!pfl) { + } else if (!dbfl_has_copy(pfl)) { status = convert(paddr, pbuf, n, capacity, offset); } else { DBADDR localAddr = *paddr; /* Structure copy */ From 372e937717af65b903d7b9885b7c34e151c9bd86 Mon Sep 17 00:00:00 2001 From: Ben Franksen Date: Thu, 14 Jan 2021 17:45:25 +0100 Subject: [PATCH 05/52] add macro dbfl_pfield to db_field_log.h and use it in dbGet --- modules/database/src/ioc/db/dbAccess.c | 10 ++-------- modules/database/src/ioc/db/db_field_log.h | 3 +++ 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index d50b2561d..bac208f02 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -967,10 +967,7 @@ long dbGet(DBADDR *paddr, short dbrType, 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; - else - localAddr.pfield = (char *) pfl->u.r.field; + localAddr.pfield = dbfl_pfield(pfl); status = dbFastGetConvertRoutine[field_type][dbrType] (localAddr.pfield, pbuf, &localAddr); } @@ -1014,10 +1011,7 @@ long dbGet(DBADDR *paddr, short dbrType, 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; - else - localAddr.pfield = (char *) pfl->u.r.field; + localAddr.pfield = dbfl_pfield(pfl); status = convert(&localAddr, pbuf, n, capacity, offset); } diff --git a/modules/database/src/ioc/db/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h index 222bad0c1..e517d529f 100644 --- a/modules/database/src/ioc/db/db_field_log.h +++ b/modules/database/src/ioc/db/db_field_log.h @@ -134,6 +134,9 @@ typedef struct db_field_log { #define dbfl_has_copy(p)\ ((p) && ((p)->type==dbfl_type_val || (p)->u.r.dtor || (p)->no_elements==0)) +#define dbfl_pfield(p)\ + ((p)->type==dbfl_type_val ? &p->u.v.field : p->u.r.field) + #ifdef __cplusplus } #endif From 236bb2c671b00891d7d010a2a38e22894819987d Mon Sep 17 00:00:00 2001 From: Ben Franksen Date: Fri, 15 Jan 2021 14:59:33 +0100 Subject: [PATCH 06/52] fix an out-dated comment in the array filter code --- modules/database/src/std/filters/arr.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/modules/database/src/std/filters/arr.c b/modules/database/src/std/filters/arr.c index 5f251844a..ffe3fce8f 100644 --- a/modules/database/src/std/filters/arr.c +++ b/modules/database/src/std/filters/arr.c @@ -128,19 +128,7 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) pfl->u.r.dtor = freeArray; pfl->u.r.pvt = my->arrayFreeList; } - /* 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. - */ + /* adjust no_elements (even if zero elements remain) */ pfl->no_elements = nTarget; if (must_lock) dbScanUnlock(dbChannelRecord(chan)); From 2340c6e6c1a3b34526108fc84f0220fadd052146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20L=C3=B6ki?= Date: Thu, 25 Feb 2021 14:54:07 +0100 Subject: [PATCH 07/52] Allow changing the BPTR field This fixes github issue #97: Reading into an aai record from a compress or histogram or subArray record could cause a segfault if the aai record was initialized before the linked one. --- modules/database/src/std/rec/compressRecord.c | 5 +++-- modules/database/src/std/rec/histogramRecord.c | 4 ++-- modules/database/src/std/rec/subArrayRecord.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/database/src/std/rec/compressRecord.c b/modules/database/src/std/rec/compressRecord.c index 98e17985f..d7da7f9b6 100644 --- a/modules/database/src/std/rec/compressRecord.c +++ b/modules/database/src/std/rec/compressRecord.c @@ -106,7 +106,7 @@ static void monitor(compressRecord *prec) db_post_events(prec, &prec->nuse, monitor_mask); prec->ouse = prec->nuse; } - db_post_events(prec, prec->bptr, monitor_mask); + db_post_events(prec, (void*)&prec->val, monitor_mask); } static void put_value(compressRecord *prec, double *psource, int n) @@ -404,7 +404,6 @@ static long cvt_dbaddr(DBADDR *paddr) { compressRecord *prec = (compressRecord *) paddr->precord; - paddr->pfield = prec->bptr; paddr->no_elements = prec->nsam; paddr->field_type = DBF_DOUBLE; paddr->field_size = sizeof(double); @@ -426,6 +425,8 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) epicsUInt32 off = prec->off; epicsUInt32 nuse = prec->nuse; + paddr->pfield = prec->bptr; + if (prec->balg == bufferingALG_FIFO) { epicsUInt32 nsam = prec->nsam; diff --git a/modules/database/src/std/rec/histogramRecord.c b/modules/database/src/std/rec/histogramRecord.c index 0e9724cb6..bc618df2e 100644 --- a/modules/database/src/std/rec/histogramRecord.c +++ b/modules/database/src/std/rec/histogramRecord.c @@ -291,7 +291,7 @@ static void monitor(histogramRecord *prec) } /* send out monitors connected to the value field */ if (monitor_mask) - db_post_events(prec, prec->bptr, monitor_mask); + db_post_events(prec, (void*)&prec->val, monitor_mask); return; } @@ -300,7 +300,6 @@ static long cvt_dbaddr(DBADDR *paddr) { histogramRecord *prec = (histogramRecord *) paddr->precord; - paddr->pfield = prec->bptr; paddr->no_elements = prec->nelm; paddr->field_type = DBF_ULONG; paddr->field_size = sizeof(epicsUInt32); @@ -312,6 +311,7 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) { histogramRecord *prec = (histogramRecord *) paddr->precord; + paddr->pfield = prec->bptr; *no_elements = prec->nelm; *offset = 0; return 0; diff --git a/modules/database/src/std/rec/subArrayRecord.c b/modules/database/src/std/rec/subArrayRecord.c index 82e543ca7..b73dee16b 100644 --- a/modules/database/src/std/rec/subArrayRecord.c +++ b/modules/database/src/std/rec/subArrayRecord.c @@ -161,7 +161,6 @@ static long cvt_dbaddr(DBADDR *paddr) { subArrayRecord *prec = (subArrayRecord *) paddr->precord; - paddr->pfield = prec->bptr; paddr->no_elements = prec->malm; paddr->field_type = prec->ftvl; paddr->field_size = dbValueSize(prec->ftvl); @@ -174,6 +173,7 @@ static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) { subArrayRecord *prec = (subArrayRecord *) paddr->precord; + paddr->pfield = prec->bptr; if (prec->udf) *no_elements = 0; else @@ -293,7 +293,7 @@ static void monitor(subArrayRecord *prec) monitor_mask = recGblResetAlarms(prec); monitor_mask |= (DBE_LOG|DBE_VALUE); - db_post_events(prec, prec->bptr, monitor_mask); + db_post_events(prec, (void*)&prec->val, monitor_mask); return; } From 4a0f488657e208ab2ed6aed17473d42d19fc9d2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kriszti=C3=A1n=20L=C3=B6ki?= Date: Thu, 25 Feb 2021 16:13:48 +0100 Subject: [PATCH 08/52] Fixed db_post_events to not use bptr --- modules/database/src/std/rec/histogramRecord.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/src/std/rec/histogramRecord.c b/modules/database/src/std/rec/histogramRecord.c index bc618df2e..44b278f39 100644 --- a/modules/database/src/std/rec/histogramRecord.c +++ b/modules/database/src/std/rec/histogramRecord.c @@ -111,7 +111,7 @@ static void wdogCallback(epicsCallback *arg) if (prec->mcnt > 0){ dbScanLock((struct dbCommon *)prec); recGblGetTimeStamp(prec); - db_post_events(prec, prec->bptr, DBE_VALUE | DBE_LOG); + db_post_events(prec, (void*)&prec->val, DBE_VALUE | DBE_LOG); prec->mcnt = 0; dbScanUnlock((struct dbCommon *)prec); } From e881cb15c4a9ba7c74b61782e0bb6b043ddcdfd0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Feb 2021 07:58:40 -0800 Subject: [PATCH 09/52] registerAllRecordDeviceDrivers() handle function --- .../ioc/misc/registerAllRecordDeviceDrivers.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp b/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp index 0afb997d4..8ba5182d0 100644 --- a/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp +++ b/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp @@ -185,6 +185,21 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase) registerJLinks(pdbbase, 1, ptr); } + // for each function() + for(ELLNODE *cur = ellFirst(&pdbbase->functionList); cur; cur = ellNext(cur)) { + dbText& reg = *CONTAINER(cur, dbText, node); + + typedef void(*registrar)(void); + registrar* ptr = lookupAs("pvar_func_register_func_", reg.text); + + if(!ptr || !*ptr) { + fprintf(stderr, "Unable to find function '%s' : %s\n", reg.text, epicsLoadError()); + return 1; + } + + runRegistrarOnce(*ptr); + } + // for each registrar() for(ELLNODE *cur = ellFirst(&pdbbase->registrarList); cur; cur = ellNext(cur)) { dbText& reg = *CONTAINER(cur, dbText, node); @@ -193,7 +208,7 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase) registrar* ptr = lookupAs("pvar_func_", reg.text); if(!ptr || !*ptr) { - fprintf(stderr, "Unable to find registar '%s' : %s\n", reg.text, epicsLoadError()); + fprintf(stderr, "Unable to find registrar '%s' : %s\n", reg.text, epicsLoadError()); return 1; } From bee00658ae652af8cb6d52f1aa06ba726c28f848 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 21 Feb 2021 17:13:44 -0600 Subject: [PATCH 10/52] Limit auto-declaration of record types to regRecDevDrv only Allowing this while expanding DBD files for IOCs can insert other device supports before of the Base "Soft Channel" ones, making the other type the default. Adds a note that DBD file order matters. Fixes lp: #1908305 --- .../database/src/template/top/exampleApp/src/xxxSupport.dbd | 2 +- modules/database/src/tools/DBD/Parser.pm | 6 +++++- modules/database/src/tools/registerRecordDeviceDriver.pl | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/database/src/template/top/exampleApp/src/xxxSupport.dbd b/modules/database/src/template/top/exampleApp/src/xxxSupport.dbd index 8094bdda6..64f2e3842 100644 --- a/modules/database/src/template/top/exampleApp/src/xxxSupport.dbd +++ b/modules/database/src/template/top/exampleApp/src/xxxSupport.dbd @@ -1,2 +1,2 @@ include "xxxRecord.dbd" -device(xxx,CONSTANT,devXxxSoft,"SoftChannel") +device(xxx,CONSTANT,devXxxSoft,"Soft Channel") diff --git a/modules/database/src/tools/DBD/Parser.pm b/modules/database/src/tools/DBD/Parser.pm index d7e16ff52..cb046e062 100644 --- a/modules/database/src/tools/DBD/Parser.pm +++ b/modules/database/src/tools/DBD/Parser.pm @@ -29,6 +29,7 @@ use DBD::Function; use DBD::Variable; our $debug=0; +our $allowAutoDeclarations=0; sub ParseDBD { (my $dbd, $_) = @_; @@ -102,8 +103,11 @@ sub ParseDBD { unquote($1, $2, $3, $4); my $rtyp = $dbd->recordtype($record_type); if (!defined $rtyp) { + my $msg = "Device '$choice' defined for unknown record type '$record_type'."; + dieContext($msg, "DBD files must be added in the correct order.") + unless $allowAutoDeclarations; + warn "$msg\nRecord type '$record_type' declared.\n"; $rtyp = DBD::Recordtype->new($record_type); - warn "Device using unknown record type '$record_type', declaration created\n"; $dbd->add($rtyp); } $rtyp->add_device(DBD::Device->new($link_type, $dset, $choice)); diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 74b518a66..8d6bcd1ea 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -31,6 +31,9 @@ my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32? my ($file, $subname, $bldTop) = @ARGV; +# Permit auto-declaration of record types for building runtime-loadable modules +$DBD::Parser::allowAutoDeclarations = 1; + my $dbd = DBD->new(); ParseDBD($dbd, Readfile($file, "", \@path)); From 08eaea64d20d09fc92ec66ee02568bb9368a7cd7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 27 Feb 2021 16:45:12 -0600 Subject: [PATCH 11/52] Fix up comments & messages, add Release Notes --- documentation/RELEASE_NOTES.md | 14 ++++++++++++++ modules/database/src/tools/DBD/Parser.pm | 4 ++-- .../src/tools/registerRecordDeviceDriver.pl | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index eb9ba33fa..d7f0656fa 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -18,6 +18,20 @@ should also be read to understand what has changed since earlier releases. +### Prevent default DTYPs from changing + +[Kay Kasemir reported](https://bugs.launchpad.net/epics-base/+bug/1908305) that +it is possible to change the Base record type's default DTYP if a `device()` +entry is seen before the `recordtype()` definition to which it refers. The +default DTYP is the first device loaded, which is normally the `Soft Channel` +support from Base. A warning was being displayed by dbdExpand when a `device()` +entry was see first, but that was easily missed. + +The DBD file parser in dbdExpand.pl has now been modified to make this an error, +although the registerRecordDeviceDriver.pl script will still accept `device()` +entries without having their `recordtype()` loaded since this is necessary to +compile device supports as loadable modules. + ### Priority inversion safe posix mutexes diff --git a/modules/database/src/tools/DBD/Parser.pm b/modules/database/src/tools/DBD/Parser.pm index cb046e062..b4cef4781 100644 --- a/modules/database/src/tools/DBD/Parser.pm +++ b/modules/database/src/tools/DBD/Parser.pm @@ -103,8 +103,8 @@ sub ParseDBD { unquote($1, $2, $3, $4); my $rtyp = $dbd->recordtype($record_type); if (!defined $rtyp) { - my $msg = "Device '$choice' defined for unknown record type '$record_type'."; - dieContext($msg, "DBD files must be added in the correct order.") + my $msg = "Device '$choice' refers to unknown record type '$record_type'."; + dieContext($msg, "DBD files must be combined in the correct order.") unless $allowAutoDeclarations; warn "$msg\nRecord type '$record_type' declared.\n"; $rtyp = DBD::Recordtype->new($record_type); diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 8d6bcd1ea..49354fbd7 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -31,7 +31,7 @@ my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32? my ($file, $subname, $bldTop) = @ARGV; -# Permit auto-declaration of record types for building runtime-loadable modules +# Auto-declaration of record types is needed to build loadable modules $DBD::Parser::allowAutoDeclarations = 1; my $dbd = DBD->new(); From 0926f7db0ffb0d0275525ac673fb807f5f013164 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 27 Feb 2021 17:15:35 -0600 Subject: [PATCH 12/52] Release Notes updates Added notes for the Windows Monotonic fix, and Apple arm64 support. Expanded and edited some other notes. --- documentation/RELEASE_NOTES.md | 80 +++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index eb9ba33fa..661aa979b 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -19,20 +19,45 @@ should also be read to understand what has changed since earlier releases. -### Priority inversion safe posix mutexes +### Priority inversion safe Posix mutexes On Posix systems, epicsMutex now support priority inheritance if available. -The IOC needs to run with SCHED_FIFO engaged. -Support for Posix implementations before POSIX.1-2001 (_XOPEN_SOURCE < 500, -glibc version < 2.3.3) has been dropped. +The IOC needs to run with SCHED_FIFO engaged to use these. +Support for Posix implementations before POSIX.1-2001 (`_XOPEN_SOURCE < 500`, +glibc version < 2.3.3) has been dropped. -The epicsMutexShowAll() function (available through IOC shell) -will print "PI is enabled" if both libc and kernel support is present. +The IOC shell's `epicsMutexShowAll` command prints "PI is enabled" if both +libc and kernel support is present. -### Add epicsStrSimilarity() +### Fix for Periodic Scan threads hanging on Windows -Add epicsStrSimilarity() to epicsString.h which uses edit distance as an approximate comparison. -Enables a new "Did you mean ..." suggestion when a .db file provides an invalid value for a DBF_MENU or DBF_DEVICE field. +Since 7.0.3.1 a Windows IOC could not run for more than 49.7 days; at that +time the periodic scan threads would stop processing. This issue should now +have been fixed and the Monotonic time functions on Windows should return +values which count at nanosecond resolution. However we have not waited 49.7 +days to test the final software, so there is a small chance that it's still +broken. + +This fixes [lauchpad bug #1896295](https://bugs.launchpad.net/bugs/1896295). + +### Support for Apple M1 (arm64) Processors + +Thanks to Jeong Han Lee this release comes with build support for Apple's new +M1 CPUs running macOS, using the target name `darwin-aarch64`. + +It should also be possible to build universal binaries containing code for +both the Intel and arm64 processors under either target name: In the +appropriate `configure/os/CONFIG_SITE.Common.darwin-*` file add the other +architecture class name to the `ARCH_CLASS` variable (after a space). + +### New String Comparison Routine `epicsStrSimilarity()` + +The new `epicsStrSimilarity()` routine in epicsString.h uses a modified +Levenshtein distance to compare two strings, with a character case difference +being half the weight of a full substitution. The double return value falls in +the range 0.0 (identical) through 1.0 (no characters matching), or -1.0 for +error. This is used to provide a new "Did you mean ..." suggestion when a .db +file provides an invalid choice string for a `DBF_MENU` or `DBF_DEVICE` field. ### Build System: New `VALID_BUILDS` type "Command" @@ -196,32 +221,35 @@ as an array field, and its record support must define a `put_array_info()` routine. ### Timestamp before processing output links -The record processing code for records with output links has been modified -to update the timestamp via recGblGetTimeStamp() before processing the -output links. This ensures that other records which get processed via -the output link can use TSEL links to fetch the timestamp which corresponds -to the data processed by the output link. + +The record processing code for records with output links has been modified to +update the timestamp via recGblGetTimeStamp() _before_ processing the output +links. This ensures that other records which get processed via an output link +can use TSEL links to fetch the timestamp corresponding to the data processed +by the output link. This change could result in a slightly earlier timestamp for records whose output link is handled by a device driver, but only if the device driver does -not handle its own timestamping via TSE -2 and instead uses TSE 0 or TSE -1 -to get current time or best time, and the time spent in the device driver is +not handle its own timestamping via TSE -2 and instead uses TSE 0 or TSE -1 to +get current time or best time, and the time spent in the device driver is greater than your timestamp provider resolution. For these situations it is recommended to set TSE to -2 and set the timestamp in the driver code. ### Add registerAllRecordDeviceDrivers() -Addition of registerAllRecordDeviceDrivers() as an iocsh function -and in iocshRegisterCommon.h. This function uses dynamic lookup with -`epicsFindSymbol()` to perform the same function as a generated -`*_registerRecordDeviceDriver()` function. -This allows dynamic loading/linking of support modules without code generation. +A new iocsh command `registerAllRecordDeviceDrivers` is provided and also +defined as a function in iocshRegisterCommon.h. This uses dynamic symbol +lookup with `epicsFindSymbol()` to perform the same function as a generated +`*_registerRecordDeviceDriver()` function. This allows for an alternative +approach to dynamic loading of support modules without code generation. -This feature is not intended for use by IOCs constructed using the standard EPICS application -build process and booted from a startup script in an iocBoot subdirectory, although it might -work in some of those cases (the IOC's registerRecordDeviceDriver.cpp file is still required -to link everything into the executable). It also won't work with some static build -configurations or where the symbol table has been stripped from the executable. +This feature is not intended for use by IOCs constructed using the standard +EPICS application build process and booted from a startup script in an iocBoot +subdirectory, although it might work in some of those cases — the +generated registerRecordDeviceDriver.cpp file is normally required to link +everything referred to in the DBD file into the IOC's executable. It also +won't work with some static build configurations, or if the symbol table has +been stripped from the executable. ### Using a `{const:"string"}` to initialize an array of `DBF_CHAR` From 12ab69402a5e606d00e2cb99b6a1b1559b7d2131 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 25 Feb 2021 13:19:41 -0600 Subject: [PATCH 13/52] Improve the message from a DBD field-count mismatch --- .../database/src/tools/dbdToRecordtypeH.pl | 62 ++++++++++++------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl index dad767124..76bae7fbf 100644 --- a/modules/database/src/tools/dbdToRecordtypeH.pl +++ b/modules/database/src/tools/dbdToRecordtypeH.pl @@ -111,31 +111,47 @@ if ($opt_D) { # Output dependencies only, to stdout sub oldtables { # Output compatible with R3.14.x + + my @fields = $rtyp->fields; + my $no_fields = scalar @fields; + + print OUTFILE << "__EOF__"; +#include +#include +#ifdef __cplusplus +extern "C" { +#endif +static int ${rn}RecordSizeOffset(dbRecordType *prt) +{ + ${rn}Record *prec = 0; + + if (prt->no_fields != ${no_fields}) { + cantProceed("IOC build or installation error:\\n" + " The ${rn}Record defined in the DBD file has %d fields,\\n" + " but the record support code was built with ${no_fields}.\\n", + prt->no_fields); + } +__EOF__ + print OUTFILE - "#include \n" . - "#include \n" . - "#ifdef __cplusplus\n" . - "extern \"C\" {\n" . - "#endif\n" . - "static int ${rn}RecordSizeOffset(dbRecordType *prt)\n" . - "{\n" . - " ${rn}Record *prec = 0;\n\n" . - " assert(prt->no_fields == " . scalar($rtyp->fields) . ");\n" . join("\n", map { - " prt->papFldDes[${rn}Record" . $_->name . "]->size = " . - "sizeof(prec->" . $_->C_name . ");" - } $rtyp->fields) . "\n" . - join("\n", map { - " prt->papFldDes[${rn}Record" . $_->name . "]->offset = (unsigned short)(" . - "(char *)&prec->" . $_->C_name . " - (char *)prec);" - } $rtyp->fields) . "\n" . - " prt->rec_size = sizeof(*prec);\n" . - " return 0;\n" . - "}\n" . - "epicsExportRegistrar(${rn}RecordSizeOffset);\n\n" . - "#ifdef __cplusplus\n" . - "}\n" . - "#endif\n"; + my $fn = $_->name; + my $cn = $_->C_name; + " prt->papFldDes[${rn}Record${fn}]->size = " . + "sizeof(prec->${cn});\n" . + " prt->papFldDes[${rn}Record${fn}]->offset = " . + "(unsigned short)((char *)&prec->${cn} - (char *)prec);" + } @fields), << "__EOF__"; + + prt->rec_size = sizeof(*prec); + return 0; +} +epicsExportRegistrar(${rn}RecordSizeOffset); + +#ifdef __cplusplus +} +#endif +__EOF__ } sub newtables { From 1c566e21102e254a47974e2526847fa3d7117ecc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 27 Feb 2021 22:08:50 -0600 Subject: [PATCH 14/52] Modify aai to support pass-1 device initialization The Soft Channel device support requests pass-1 initialization. It no longer needs to initialize the INP link or allocate the array buffer itself, these are taken care of elsewhere. The record code uses PACT to remember that the device must be initialized again in pass 1. --- modules/database/src/std/dev/devAaiSoft.c | 12 ++++-------- modules/database/src/std/rec/aaiRecord.c | 24 ++++++++++++++++------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/modules/database/src/std/dev/devAaiSoft.c b/modules/database/src/std/dev/devAaiSoft.c index 55975bae0..aafdd1bcd 100644 --- a/modules/database/src/std/dev/devAaiSoft.c +++ b/modules/database/src/std/dev/devAaiSoft.c @@ -47,19 +47,15 @@ static long init_record(dbCommon *pcommon) aaiRecord *prec = (aaiRecord *)pcommon; DBLINK *plink = &prec->inp; - /* This is pass 0, link hasn't been initialized yet */ - dbInitLink(plink, DBF_INLINK); + /* Ask record to call us in pass 1 instead */ + if (prec->pact != 2) { + return 2; + } if (dbLinkIsConstant(plink)) { long nRequest = prec->nelm; long status; - /* Allocate a buffer, record support hasn't done that yet */ - if (!prec->bptr) { - prec->bptr = callocMustSucceed(nRequest, dbValueSize(prec->ftvl), - "devAaiSoft: buffer calloc failed"); - } - status = dbLoadLinkArray(plink, prec->ftvl, prec->bptr, &nRequest); if (!status) { prec->nord = nRequest; diff --git a/modules/database/src/std/rec/aaiRecord.c b/modules/database/src/std/rec/aaiRecord.c index c1410067c..157a48f5b 100644 --- a/modules/database/src/std/rec/aaiRecord.c +++ b/modules/database/src/std/rec/aaiRecord.c @@ -112,16 +112,18 @@ static long init_record(struct dbCommon *pcommon, int pass) prec->ftvl = DBF_UCHAR; prec->nord = (prec->nelm == 1); - /* we must call pdset->init_record in pass 0 - because it may set prec->bptr which must - not change after links are established before pass 1 - */ - + /* call pdset->init_record() in pass 0 so it can do its own + * memory allocation and set prec->bptr, which must be set by + * the end of pass 0. + */ if (pdset->common.init_record) { long status = pdset->common.init_record(pcommon); - /* init_record may set the bptr to point to the data */ - if (status) + if (status == 2) { + /* requesting pass 1 callback, remember to do that */ + prec->pact = 2; + } + else if (status) return status; } if (!prec->bptr) { @@ -132,6 +134,14 @@ static long init_record(struct dbCommon *pcommon, int pass) return 0; } + if (prec->pact == 2) { + /* device support asked for an init_record() callback in pass 1 */ + long status = pdset->common.init_record(pcommon); + if (status) + return status; + prec->pact = FALSE; + } + recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml); /* must have read_aai function defined */ From 6734918e6e188b1f846e603e7943c24bc6c1bed7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 27 Feb 2021 22:19:48 -0600 Subject: [PATCH 15/52] Release notes and aai documentation updates --- documentation/RELEASE_NOTES.md | 15 +++++++ .../database/src/std/rec/aaiRecord.dbd.pod | 44 +++++++++++++------ 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index eb9ba33fa..a8570f9e7 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -18,6 +18,21 @@ should also be read to understand what has changed since earlier releases. +### Fix aai's Device Support Initialization + +Krisztian Loki [reported](https://github.com/epics-base/epics-base/issues/97) +segfaults occurring when a Soft Channel aai record INP field was a DB link to +an array field of a compress record. This was caused by the aai record's +pass-0 device support initialization clashing with the semantics of the new +link support API. + +The aai record +[has been modified](https://github.com/epics-base/epics-base/pull/114) to +allow the Soft Channel device support to request a pass-1 initialization +callback. See the Device Support section of the Array Analogue Input Record +Reference pages in this release for the API changes, which are fully backwards +compatible for existing aai device support. + ### Priority inversion safe posix mutexes diff --git a/modules/database/src/std/rec/aaiRecord.dbd.pod b/modules/database/src/std/rec/aaiRecord.dbd.pod index 8eb8bad05..b3dd19216 100644 --- a/modules/database/src/std/rec/aaiRecord.dbd.pod +++ b/modules/database/src/std/rec/aaiRecord.dbd.pod @@ -151,10 +151,15 @@ for more information on simulation mode and its fields. static long init_record(aaiRecord *prec, int pass) -If device support includes C, it is called. +If device support includes an C routine it is called, but unlike +most record types this occurs in pass 0, which allows the device support to +allocate the array buffer itself. + +Since EPICS 7.0.5 the device support may return 2 to request a second call to +its C routine in pass 1. Checks if device support allocated array space. If not, space for the array is -allocated using NELM and FTVL. The array address is stored in the record. +allocated using NELM and FTVL. The array address is stored in BPTR. This routine initializes SIMM with the value of SIML if SIML type is CONSTANT link or creates a channel access link if SIML type is PV_LINK. VAL is likewise @@ -294,7 +299,7 @@ Scan forward link if necessary, set PACT FALSE, and return. %/* Declare Device Support Entry Table */ %struct aaiRecord; %typedef struct aaidset { - % dset common; /*init_record returns: (-1,0)=>(failure,success)*/ + % dset common; /*init_record returns: (-1,0,2)=>(failure,success,callback)*/ % long (*read_aai)(struct aaiRecord *prec); /*returns: (-1,0)=>(failure,success)*/ %} aaidset; %#define HAS_aaidset @@ -469,8 +474,19 @@ with C set to 1. long init_record(dbCommon *precord) -This routine is optional. If provided, it is called by the record support -C routine. +This routine is optional. +If provided, it is called by the record support's C routine in +pass 0. +The device support may allocate memory for the VAL field's array (enough space +for NELM elements of type FTVA) from its own memory pool if desired, and store +the pointer to this buffer in the BPTR field. +The record will use C for this memory allocation if BPTR has not been +set by this routine. +The routine must return 0 for success, -1 or a error status on failure. + +Since EPICS 7.0.5 if this routine returns 2 in pass 0, it will be called again +in pass 1 with the PACT field set to 2. +In pass 0 the PACT field is set to zero (FALSE). =head4 get_ioint_info @@ -485,7 +501,8 @@ provided for any device type that can use the ioEvent scanner. long read_aai(dbCommon *precord) -This routine must provide a new input value. It returns the following values: +This routine should provide a new input value. +It returns the following values: =over @@ -501,16 +518,15 @@ Other: Error. =head3 Device Support For Soft Records -The C<<< Soft Channel >>> device support module is provided to read values from -other records and store them in arrays. If INP is a constant link, then read_aai -does nothing. In this case, the record can be used to hold arrays written via -dbPuts. If INP is a database or channel access link, the new array value is read -from the link. NORD is set. +The C<<< Soft Channel >>> device support is provided to read values from other +records via the INP link, or to hold array values that are written into it. -This module places a value directly in VAL and NORD is set to the number of items -in the array. +If INP is a constant link the array value gets loaded from the link constant by +the C routine, which also sets NORD. +The C routine does nothing in this case. -If the INP link type is constant, then NORD is set to zero. +If INP is a database or channel access link, the C routine gets a +new array value from the link and sets NORD. =cut } From 6754404d0fc71b805c1825bfea42f7fc2356ad30 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 15:02:27 -0600 Subject: [PATCH 16/52] Replace magic "2" with macro AAI_DEVINIT_PASS1 --- modules/database/src/std/dev/devAaiSoft.c | 4 ++-- modules/database/src/std/rec/aaiRecord.c | 6 +++--- modules/database/src/std/rec/aaiRecord.dbd.pod | 11 ++++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/modules/database/src/std/dev/devAaiSoft.c b/modules/database/src/std/dev/devAaiSoft.c index aafdd1bcd..f2e4a41f9 100644 --- a/modules/database/src/std/dev/devAaiSoft.c +++ b/modules/database/src/std/dev/devAaiSoft.c @@ -48,8 +48,8 @@ static long init_record(dbCommon *pcommon) DBLINK *plink = &prec->inp; /* Ask record to call us in pass 1 instead */ - if (prec->pact != 2) { - return 2; + if (prec->pact != AAI_DEVINIT_PASS1) { + return AAI_DEVINIT_PASS1; } if (dbLinkIsConstant(plink)) { diff --git a/modules/database/src/std/rec/aaiRecord.c b/modules/database/src/std/rec/aaiRecord.c index 157a48f5b..756b892ab 100644 --- a/modules/database/src/std/rec/aaiRecord.c +++ b/modules/database/src/std/rec/aaiRecord.c @@ -119,9 +119,9 @@ static long init_record(struct dbCommon *pcommon, int pass) if (pdset->common.init_record) { long status = pdset->common.init_record(pcommon); - if (status == 2) { + if (status == AAI_DEVINIT_PASS1) { /* requesting pass 1 callback, remember to do that */ - prec->pact = 2; + prec->pact = AAI_DEVINIT_PASS1; } else if (status) return status; @@ -134,7 +134,7 @@ static long init_record(struct dbCommon *pcommon, int pass) return 0; } - if (prec->pact == 2) { + if (prec->pact == AAI_DEVINIT_PASS1) { /* device support asked for an init_record() callback in pass 1 */ long status = pdset->common.init_record(pcommon); if (status) diff --git a/modules/database/src/std/rec/aaiRecord.dbd.pod b/modules/database/src/std/rec/aaiRecord.dbd.pod index b3dd19216..969f5800f 100644 --- a/modules/database/src/std/rec/aaiRecord.dbd.pod +++ b/modules/database/src/std/rec/aaiRecord.dbd.pod @@ -155,8 +155,8 @@ If device support includes an C routine it is called, but unlike most record types this occurs in pass 0, which allows the device support to allocate the array buffer itself. -Since EPICS 7.0.5 the device support may return 2 to request a second call to -its C routine in pass 1. +Since EPICS 7.0.5 the device support may return C to request +a second call to its C routine in pass 1. Checks if device support allocated array space. If not, space for the array is allocated using NELM and FTVL. The array address is stored in BPTR. @@ -299,10 +299,11 @@ Scan forward link if necessary, set PACT FALSE, and return. %/* Declare Device Support Entry Table */ %struct aaiRecord; %typedef struct aaidset { - % dset common; /*init_record returns: (-1,0,2)=>(failure,success,callback)*/ + % dset common; /*init_record returns: (-1,0,AAI_DEVINIT_PASS1)=>(failure,success,callback)*/ % long (*read_aai)(struct aaiRecord *prec); /*returns: (-1,0)=>(failure,success)*/ %} aaidset; %#define HAS_aaidset + %#define AAI_DEVINIT_PASS1 2 % field(VAL,DBF_NOACCESS) { prompt("Value") @@ -484,8 +485,8 @@ The record will use C for this memory allocation if BPTR has not been set by this routine. The routine must return 0 for success, -1 or a error status on failure. -Since EPICS 7.0.5 if this routine returns 2 in pass 0, it will be called again -in pass 1 with the PACT field set to 2. +Since EPICS 7.0.5 if this routine returns C in pass 0, it +will be called again in pass 1 with the PACT field set to C. In pass 0 the PACT field is set to zero (FALSE). =head4 get_ioint_info From 458c0af4e952b0676ee007ca05116475be089919 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 17:36:25 -0600 Subject: [PATCH 17/52] Checkout submodules at tagged versions for 7.0.5 --- modules/normativeTypes | 2 +- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/normativeTypes b/modules/normativeTypes index 7a2d264f2..1250a3c23 160000 --- a/modules/normativeTypes +++ b/modules/normativeTypes @@ -1 +1 @@ -Subproject commit 7a2d264f2cb107bfd10adb23bc2b73d8323a79e4 +Subproject commit 1250a3c236f0aa92e0b5bd73647fd71d8a09360d diff --git a/modules/pvAccess b/modules/pvAccess index 4638c11c8..64c284cd4 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 4638c11c8cd9ef0ee9797080abeb2f0dbbf23b82 +Subproject commit 64c284cd41f114ee07e999a94ff55ae53a87c7e0 diff --git a/modules/pvData b/modules/pvData index ca86a6318..b1c830387 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit ca86a63180e400146f112593d9cb8d388677b656 +Subproject commit b1c8303870a04f1c3ee5a01a84aad2b2596e918c diff --git a/modules/pvDatabase b/modules/pvDatabase index b62b047f6..09423edea 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit b62b047f63c4c30f305de00b921519306de9b98b +Subproject commit 09423edeabc4b46c0ff3a6a09c8c1268e3de291f diff --git a/modules/pva2pva b/modules/pva2pva index 527afaf85..b8389ac6a 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 527afaf8560223d42f1a957182fe9c4eef76b661 +Subproject commit b8389ac6a19679fe515fd74cddeb1e02467b1007 diff --git a/modules/pvaClient b/modules/pvaClient index 7722fdf35..bc9ac8422 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit 7722fdf353b54b681a2d883c36374aa0211241ef +Subproject commit bc9ac8422cb94a38c27385c3c6781aea30c2c8b8 From a9ff175cf0e8a8d991f1f73ff4c2aeb14211eb21 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 17:37:40 -0600 Subject: [PATCH 18/52] Replace "UNRELEASED" in epicsString.h --- modules/libcom/src/misc/epicsString.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/misc/epicsString.h b/modules/libcom/src/misc/epicsString.h index 3c08e5277..854b552c6 100644 --- a/modules/libcom/src/misc/epicsString.h +++ b/modules/libcom/src/misc/epicsString.h @@ -48,7 +48,7 @@ LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length, * @returns 1.0 when A and B are identical, down to 0.0 when A and B are unrelated, * or < 0.0 on error. * - * @since UNRELEASED + * @since EPICS 7.0.5 */ LIBCOM_API double epicsStrSimilarity(const char *A, const char *B); From bb7b754730f264e997a6026304a9a962e9a9e652 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 20:04:16 -0600 Subject: [PATCH 19/52] Documentation updates for release Mostly version numbers, a few text and formatting changes. --- documentation/README.md | 24 ++++------------ documentation/RELEASE_NOTES.md | 44 ++++++++++++++++++++++++----- documentation/ReleaseChecklist.html | 20 ++++++------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/documentation/README.md b/documentation/README.md index dabee1759..7e995bfde 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -1,6 +1,6 @@ # Installation Instructions {#install} -## EPICS Base Release 7.0.4.1 +## EPICS Base Release 7.0.5 ----- @@ -12,7 +12,6 @@ - [Supported platforms](#0_0_4) - [Supported compilers](#0_0_5) - [Software requirements](#0_0_6) - - [Host system storage requirements](#0_0_7) - [Documentation](#0_0_8) - [Directory Structure](#0_0_10) - [Build related components](#0_0_11) @@ -39,7 +38,7 @@ interfaces) of various types. Please check the `RELEASE_NOTES` file in the distribution for description of changes and release migration details. -### Copyright +### Copyright Licenses Please review the LICENSE file included in the distribution for legal terms of usage. @@ -68,10 +67,10 @@ path to do EPICS builds; check the definitions of CC and CCC in **GNU make** You must use GNU make, gnumake, for any EPICS builds. Set your path so -that a gnumake version 3.81 or later is available. +that a gnumake version 4.1 or later is available. **Perl** -You must have Perl version 5.8.1 or later installed. The EPICS +You must have Perl version 5.10 or later installed. The EPICS configuration files do not specify the perl full pathname, so the perl executable must be found through your normal search path. @@ -114,13 +113,6 @@ installed on linux-x86. Command-line editing and history will then be those supplied by the os. On vxWorks the ledLib command-line input library is used instead. -### Host system storage requirements - -The compressed tar file is approximately 1.6 MB in size. The -distribution source tree takes up approximately 12 MB. Each host -target will need around 40 MB for build files, and each cross-compiled -target around 20 MB. - ### Documentation EPICS documentation is available through the [EPICS @@ -242,17 +234,13 @@ Before you can build or use this EPICS base, the environment variable the base/startup directory has been provided to help set `EPICS_HOST_ARCH.` You should have `EPICS_HOST_ARCH` set to your host operating system followed by a dash and then your host -architecture, e.g. solaris-sparc. If you are not using the OS +architecture, e.g. linux-x86_64. If you are not using the OS vendor's c/c++ compiler for host builds, you will need another dash followed by the alternate compiler name (e.g. "-gnu" for GNU c/c++ compilers on a solaris host or "-mingw" for MinGW c/c++ compilers on -a WIN32 host). See `configure/CONFIG_SITE` for a list of supported +Windows). See `configure/CONFIG_SITE` for a list of supported `EPICS_HOST_ARCH` values. -* `PERLLIB` -On WIN32, some versions of Perl require that the environment -variable PERLLIB be set to <perl directory location>. - * `PATH` As already mentioned, you must have the perl executable and you may need C and C++ compilers in your search path. For building base you diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index ffee7d83a..dfb93e613 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -11,12 +11,7 @@ release. The PVA submodules each have their own individual sets of release notes which should also be read to understand what has changed since earlier releases. -**This version of EPICS has not been released yet.** - -## Changes made on the 7.0 branch since 7.0.4.1 - - - +## EPICS Release 7.0.5 ### Fix aai's Device Support Initialization @@ -301,6 +296,8 @@ GNUmake added the directive `undefine` in version 3.82 to allow variables to be undefined. Support for this has been added to the EPICS Release file parser, so `undefine` can now be used in configure/RELEASE files to unset variables. +----- + ## EPICS Release 7.0.4.1 ### ARM Architecture Changes @@ -348,6 +345,8 @@ Bad character ' ' in record name "bad practice" if a record name begins with a minus, plus, left square bracket, or left curly bracket. +----- + ## EPICS Release 7.0.4 ### Bug fixes @@ -532,6 +531,8 @@ devLsiEtherIP = { }; ``` +----- + ## EPICS Release 7.0.3.1 **IMPORTANT NOTE:** *Some record types in this release will not be compatible @@ -725,6 +726,8 @@ necessary, all RTEMS targets should now link although the IOC won't be able to be used with the VME I/O on those systems (that we don't have VMEbus I/O support for in libCom). +----- + ## EPICS Release 7.0.3 ### `epicsTimeGetCurrent()` optimization @@ -745,6 +748,8 @@ This may result in slightly fewer, but larger frames being sent. Report NOBT as "precision" through the dbAccess API. This is not accessible through CA, but is planned to be used through QSRV. +----- + ## EPICS Release 7.0.2.2 ### Build System changes @@ -779,6 +784,8 @@ substantial than bug fixes. Turns out this is ~10x slower to query than `CLOCK_MONOTONIC`. +----- + ## EPICS Release 7.0.2.1 ### Linking shared libraries on macOS @@ -830,6 +837,8 @@ rewrite of the link address parser code in dbStaticLib. This release fixes that issue, although in some cases the output may be slightly different than it used to be. +----- + ## EPICS Release 7.0.2 ### Launchpad Bugs @@ -847,6 +856,8 @@ modules. The layout of the source files has not changed at all however, so the source code for libcom, ca and the database are still found separately under the module subdirectory. +----- + ## EPICS Release 7.0.1.1 ### Changed SIML failure behavior @@ -905,7 +916,11 @@ than is currently available, but as developers we generally much prefer to write code than documentation. Send questions to the tech-talk mailing list and we'll be happy to try and answer them! -## Changes between 3.16.1 and 3.16.2 +----- + +## Changes made between 3.16.1 and 3.16.2 + +### Launchpad Bugs The list of tracked bugs fixed in this release can be found on the [Launchpad Milestone page for EPICS Base 3.16.2](https://launchpad.net/epics-base/+milestone/3.16.2). @@ -1112,6 +1127,8 @@ array is made even larger; the previous array buffer was not being released correctly. See Launchpad [bug #1706703](https://bugs.launchpad.net/epics-base/+bug/1706703). +----- + ## Changes made between 3.16.0.1 and 3.16.1 ### IOC Database Support for 64-bit integers @@ -1548,6 +1565,7 @@ and then replace `(RECSUPFUN)` with `RECSUPFUN_CAST` when initializing the rset. Further changes might also be needed, e.g. to adapt `const`-ness of method parameters. +----- ## Changes made between 3.15.3 and 3.16.0.1 @@ -1656,6 +1674,8 @@ header and removed the need for dbScan.c to reach into the internals of its `CALLBACK` objects. +----- + # Changes incorporated from the 3.15 branch @@ -1667,6 +1687,7 @@ The names of the generated junit xml test output files have been changed from `.xml` to `-results.xml`, to allow better distinction from other xml files. (I.e., for easy wildcard matching.) +----- ## Changes made between 3.15.7 and 3.15.8 @@ -1772,6 +1793,7 @@ don't provide it any more. If multiple IOCs were started at the same time, by systemd say, they could race to obtain the Channel Access TCP port number 5064. This issue has been fixed. +----- ## Changes made between 3.15.6 and 3.15.7 @@ -1915,6 +1937,8 @@ into the htmls directory. Thanks to Tony Pietryla. This displays the version numbers of EPICS Base and the CA protocol. +----- + ## Changes made between 3.15.5 and 3.15.6 ### Unsetting environment variables @@ -2140,6 +2164,8 @@ choice string cannot be parsed, the associated periodic scan thread will no longer be started by the IOC and a warning message will be displayed at iocInit time. The `scanppl` command will also flag the faulty menuScan value. +----- + ## Changes made between 3.15.4 and 3.15.5 ### dbStatic Library Speedup and Cleanup @@ -2271,6 +2297,8 @@ will be installed into the target bin directory, from where it can be copied into the appropriate systemd location and modified as necessary. Installation instructions are included as comments in the file. +----- + ## Changes made between 3.15.3 and 3.15.4 ### New string input device support "getenv" @@ -2376,6 +2404,8 @@ variable to a non-zero value before loading the file, like this: This was [Launchpad bug 541119](https://bugs.launchpad.net/bugs/541119). +----- + ## Changes from the 3.14 branch between 3.15.3 and 3.15.4 ### NTP Time Provider adjusts to OS tick rate changes diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index 117748b06..036f56a65 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -147,17 +147,17 @@ starting at Release Approval.

Tag the module in Git, using these tag conventions:
  • - R7.0.4.1-pren + R7.0.5-pren — pre-release tag
  • - R7.0.4.1-rcn + R7.0.5-rcn — release candidate tag
cd base-7.0
- git tag -m 'ANJ: Tagged for 7.0.4.1-rc1' R7.0.4.1-rc1 + git tag -m 'ANJ: Tagged for 7.0.5-rc1' R7.0.5-rc1
Note that submodules must not be tagged with the version used for the top-level, they each have their own separate version numbers @@ -171,11 +171,11 @@ starting at Release Approval.

files and directories that are only used for continuous integration:
cd base-7.0
- ./.tools/make-tar.sh R7.0.4.1-rc1 base-7.0.4.1-rc1.tar.gz base-7.0.4.1-rc1/ + ./.tools/make-tar.sh R7.0.5-rc1 base-7.0.5-rc1.tar.gz base-7.0.5-rc1/
Create a GPG signature file of the tarfile as follows:
- gpg --armor --sign --detach-sig base-7.0.4.1-rc1.tar.gz + gpg --armor --sign --detach-sig base-7.0.5-rc1.tar.gz
@@ -298,7 +298,7 @@ starting at Release Approval.

  • Tag the module:
    - git tag -m 'ANJ: Tag for EPICS 7.0.4.1' <module-version> + git tag -m 'ANJ: Tag for EPICS 7.0.5' <module-version>
  • @@ -355,7 +355,7 @@ starting at Release Approval.

    Tag the epics-base module in Git:
    cd base-7.0
    - git tag -m 'ANJ: Tagged for release' R7.0.4.1 + git tag -m 'ANJ: Tagged for release' R7.0.5

    Don't push these commits or the new tag to the Launchpad repository yet.

    @@ -387,12 +387,12 @@ starting at Release Approval.

    files and directories that are only used for continuous integration:
    cd base-7.0
    - ./.tools/make-tar.sh R7.0.4.1 ../base-7.0.4.1.tar.gz base-7.0.4.1/ + ./.tools/make-tar.sh R7.0.5 ../base-7.0.5.tar.gz base-7.0.5/
    Create a GPG signature file of the tarfile as follows:
    cd ..
    - gpg --armor --sign --detach-sig base-7.0.4.1.tar.gz + gpg --armor --sign --detach-sig base-7.0.5.tar.gz
    @@ -457,7 +457,7 @@ starting at Release Approval.

    Upload the tar file and its .asc signature file to the epics-controls web-server.
    - scp base-7.0.4.1.tar.gz base-7.0.4.1.tar.gz.asc epics-controls:download/base
    + scp base-7.0.5.tar.gz base-7.0.5.tar.gz.asc epics-controls:download/base
    From 7f142e03f5cef74b5516e76494f29c3a0f143f4f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 20:06:40 -0600 Subject: [PATCH 20/52] Version number updates for 7.0.5 release --- configure/CONFIG_BASE_VERSION | 6 +++--- configure/CONFIG_CA_VERSION | 2 +- configure/CONFIG_DATABASE_VERSION | 6 +++--- configure/CONFIG_LIBCOM_VERSION | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index f1724487b..a32f28c54 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -48,15 +48,15 @@ EPICS_VERSION = 7 EPICS_REVISION = 0 # EPICS_MODIFICATION must be a number >=0 and <256 -EPICS_MODIFICATION = 4 +EPICS_MODIFICATION = 5 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included in the official EPICS version number if zero -EPICS_PATCH_LEVEL = 2 +EPICS_PATCH_LEVEL = 0 # Immediately after an official release the EPICS_PATCH_LEVEL is incremented # and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions) -EPICS_DEV_SNAPSHOT=-DEV +EPICS_DEV_SNAPSHOT= # No changes should be needed below here diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index 8aae1653b..3f8780e25 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -6,7 +6,7 @@ EPICS_CA_MAINTENANCE_VERSION = 8 # Development flag, set to zero for release versions -EPICS_CA_DEVELOPMENT_FLAG = 1 +EPICS_CA_DEVELOPMENT_FLAG = 0 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION index 56768f08d..c62f11daa 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -1,12 +1,12 @@ # Version number for the database APIs and shared library EPICS_DATABASE_MAJOR_VERSION = 3 -EPICS_DATABASE_MINOR_VERSION = 18 -EPICS_DATABASE_MAINTENANCE_VERSION = 2 +EPICS_DATABASE_MINOR_VERSION = 19 +EPICS_DATABASE_MAINTENANCE_VERSION = 0 # Development flag, set to zero for release versions -EPICS_DATABASE_DEVELOPMENT_FLAG = 1 +EPICS_DATABASE_DEVELOPMENT_FLAG = 0 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_LIBCOM_VERSION b/configure/CONFIG_LIBCOM_VERSION index 92aba5c11..27dc8d943 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -1,12 +1,12 @@ # Version number for the libcom APIs and shared library EPICS_LIBCOM_MAJOR_VERSION = 3 -EPICS_LIBCOM_MINOR_VERSION = 18 -EPICS_LIBCOM_MAINTENANCE_VERSION = 2 +EPICS_LIBCOM_MINOR_VERSION = 19 +EPICS_LIBCOM_MAINTENANCE_VERSION = 0 # Development flag, set to zero for release versions -EPICS_LIBCOM_DEVELOPMENT_FLAG = 1 +EPICS_LIBCOM_DEVELOPMENT_FLAG = 0 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 From ff5df5fbf3b2cfdf6ca9f2e5b454674546bafdec Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 20:21:41 -0600 Subject: [PATCH 21/52] Update version numbers after tagging --- configure/CONFIG_BASE_VERSION | 4 ++-- configure/CONFIG_CA_VERSION | 4 ++-- configure/CONFIG_DATABASE_VERSION | 4 ++-- configure/CONFIG_LIBCOM_VERSION | 4 ++-- documentation/RELEASE_NOTES.md | 9 +++++++++ 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index a32f28c54..b0c57b763 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -52,11 +52,11 @@ EPICS_MODIFICATION = 5 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included in the official EPICS version number if zero -EPICS_PATCH_LEVEL = 0 +EPICS_PATCH_LEVEL = 1 # Immediately after an official release the EPICS_PATCH_LEVEL is incremented # and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions) -EPICS_DEV_SNAPSHOT= +EPICS_DEV_SNAPSHOT=-DEV # No changes should be needed below here diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index 3f8780e25..af570b0e7 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -2,11 +2,11 @@ EPICS_CA_MAJOR_VERSION = 4 EPICS_CA_MINOR_VERSION = 13 -EPICS_CA_MAINTENANCE_VERSION = 8 +EPICS_CA_MAINTENANCE_VERSION = 9 # Development flag, set to zero for release versions -EPICS_CA_DEVELOPMENT_FLAG = 0 +EPICS_CA_DEVELOPMENT_FLAG = 1 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION index c62f11daa..2205a5386 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -2,11 +2,11 @@ EPICS_DATABASE_MAJOR_VERSION = 3 EPICS_DATABASE_MINOR_VERSION = 19 -EPICS_DATABASE_MAINTENANCE_VERSION = 0 +EPICS_DATABASE_MAINTENANCE_VERSION = 1 # Development flag, set to zero for release versions -EPICS_DATABASE_DEVELOPMENT_FLAG = 0 +EPICS_DATABASE_DEVELOPMENT_FLAG = 1 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_LIBCOM_VERSION b/configure/CONFIG_LIBCOM_VERSION index 27dc8d943..96f25ebaa 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -2,11 +2,11 @@ EPICS_LIBCOM_MAJOR_VERSION = 3 EPICS_LIBCOM_MINOR_VERSION = 19 -EPICS_LIBCOM_MAINTENANCE_VERSION = 0 +EPICS_LIBCOM_MAINTENANCE_VERSION = 1 # Development flag, set to zero for release versions -EPICS_LIBCOM_DEVELOPMENT_FLAG = 0 +EPICS_LIBCOM_DEVELOPMENT_FLAG = 1 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index dfb93e613..587b52448 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -11,6 +11,15 @@ release. The PVA submodules each have their own individual sets of release notes which should also be read to understand what has changed since earlier releases. +**This version of EPICS has not been released yet.** + +## Changes made on the 7.0 branch since 7.0.5 + + + + +----- + ## EPICS Release 7.0.5 ### Fix aai's Device Support Initialization From f8eb0be7a411ca689648dc994aaf423ce4f19052 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 28 Feb 2021 21:39:28 -0600 Subject: [PATCH 22/52] Update submodules after release --- modules/normativeTypes | 2 +- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/normativeTypes b/modules/normativeTypes index 1250a3c23..7a2d264f2 160000 --- a/modules/normativeTypes +++ b/modules/normativeTypes @@ -1 +1 @@ -Subproject commit 1250a3c236f0aa92e0b5bd73647fd71d8a09360d +Subproject commit 7a2d264f2cb107bfd10adb23bc2b73d8323a79e4 diff --git a/modules/pvAccess b/modules/pvAccess index 64c284cd4..e1c1a4bc1 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 64c284cd41f114ee07e999a94ff55ae53a87c7e0 +Subproject commit e1c1a4bc1bad6933e57b199d58f74468401218b3 diff --git a/modules/pvData b/modules/pvData index b1c830387..d3b4976ea 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit b1c8303870a04f1c3ee5a01a84aad2b2596e918c +Subproject commit d3b4976ea2b0d78075511f14d7f7bf9620dd4d14 diff --git a/modules/pvDatabase b/modules/pvDatabase index 09423edea..93a259cbd 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit 09423edeabc4b46c0ff3a6a09c8c1268e3de291f +Subproject commit 93a259cbde56668c1bbe495b15cc3ede8b42ce30 diff --git a/modules/pva2pva b/modules/pva2pva index b8389ac6a..ad8b77e19 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit b8389ac6a19679fe515fd74cddeb1e02467b1007 +Subproject commit ad8b77e19f7e2ae50c48b5d871bdbe7b0ee23b61 diff --git a/modules/pvaClient b/modules/pvaClient index bc9ac8422..efb263190 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit bc9ac8422cb94a38c27385c3c6781aea30c2c8b8 +Subproject commit efb2631905cd61cc06041f5aac5be9017383a004 From 3c46542630823a272001aaab4e6fc265c7e03046 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 Mar 2021 06:47:43 -0800 Subject: [PATCH 23/52] posix: epicsMutexOsdShowAll check for PI support --- modules/libcom/src/osi/os/posix/osdMutex.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/libcom/src/osi/os/posix/osdMutex.c b/modules/libcom/src/osi/os/posix/osdMutex.c index 83833f85c..18cd08d95 100644 --- a/modules/libcom/src/osi/os/posix/osdMutex.c +++ b/modules/libcom/src/osi/os/posix/osdMutex.c @@ -194,6 +194,7 @@ void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level) void epicsMutexOsdShowAll(void) { +#if defined _POSIX_THREAD_PRIO_INHERIT int proto = -1; int ret = pthread_mutexattr_getprotocol(&globalAttrRecursive, &proto); if(ret) { @@ -201,4 +202,7 @@ void epicsMutexOsdShowAll(void) } else { printf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not"); } +#else + printf("PI not supported\n"); +#endif } From f9e3e86401be19daf74744ca74622c02a97a7d1e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 2 Mar 2021 11:54:17 -0600 Subject: [PATCH 24/52] Support VxWorks 6.9.x before taskWait() was added We don't know exactly which version this was added in, but it is present in 6.9.4.1 so use that. Fixes lp: #1913699 --- modules/libcom/src/osi/os/vxWorks/osdThread.h | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.h b/modules/libcom/src/osi/os/vxWorks/osdThread.h index 259d358e5..25cce37ac 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.h +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.h @@ -1,5 +1,5 @@ /*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne +* Copyright (c) 2021 The University of Chicago, as Operator of Argonne * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. @@ -8,13 +8,22 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -#ifndef osdThreadh -#define osdThreadh +#ifndef INC_osdThread_H +#define INC_osdThread_H -/* VxWorks 6.9 and later can support joining threads */ +#include -#if (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR < 9) -#undef EPICS_THREAD_CAN_JOIN +#ifdef _WRS_VXWORKS_MAJOR +# define VXWORKS_VERSION_INT VERSION_INT(_WRS_VXWORKS_MAJOR, \ + _WRS_VXWORKS_MINOR, _WRS_VXWORKS_MAINT, _WRS_VXWORKS_SVCPK) +#else +/* Version not available at compile-time, assume... */ +# define VXWORKS_VERSION_INT VERSION_INT(5, 5, 0, 0) #endif -#endif /* osdThreadh */ +#if VXWORKS_VERSION_INT < VERSION_INT(6, 9, 4, 1) +/* VxWorks 6.9.4.1 and later can support joining threads */ +# undef EPICS_THREAD_CAN_JOIN +#endif + +#endif /* INC_osdThread_H */ From f41276bef8e1a98da18f146428ad2c1ada6a9b6b Mon Sep 17 00:00:00 2001 From: Brendan Chandler Date: Sun, 28 Feb 2021 20:07:33 -0600 Subject: [PATCH 25/52] epicPosicMutexInit: avoid calling with 0 which is platform dependent Different platforms (RTEMS5) can define different values for PTHREAD_MUTEX_DEFAULT, so we shouldn't pass 0 assuming its PTHREAD_MUTEX_DEFAULT. --- modules/libcom/src/osi/os/posix/osdEvent.c | 2 +- modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h | 2 +- modules/libcom/src/osi/os/posix/osdSpin.c | 2 +- modules/libcom/src/osi/os/posix/osdThread.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/osi/os/posix/osdEvent.c b/modules/libcom/src/osi/os/posix/osdEvent.c index db61c240b..b22a3430b 100644 --- a/modules/libcom/src/osi/os/posix/osdEvent.c +++ b/modules/libcom/src/osi/os/posix/osdEvent.c @@ -51,7 +51,7 @@ LIBCOM_API epicsEventId epicsEventCreate(epicsEventInitialState init) epicsEventId pevent = malloc(sizeof(*pevent)); if (pevent) { - int status = osdPosixMutexInit(&pevent->mutex, 0); + int status = osdPosixMutexInit(&pevent->mutex, PTHREAD_MUTEX_DEFAULT); pevent->isFull = (init == epicsEventFull); if (status) { diff --git a/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h b/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h index 2b6846c91..87289be5f 100644 --- a/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h +++ b/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h @@ -18,7 +18,7 @@ extern "C" { #endif /* Returns ENOTSUP if requested mutextype is not supported */ -/* At the moment, only 0 (default non recursive mutex) and PTHREAD_MUTEX_RECURSIVE are supported */ +/* At the moment, only PTHREAD_MUTEX_DEFAULT and PTHREAD_MUTEX_RECURSIVE are supported */ int osdPosixMutexInit(pthread_mutex_t *,int mutextype); #ifdef __cplusplus diff --git a/modules/libcom/src/osi/os/posix/osdSpin.c b/modules/libcom/src/osi/os/posix/osdSpin.c index f039e7c34..0b924ee3a 100644 --- a/modules/libcom/src/osi/os/posix/osdSpin.c +++ b/modules/libcom/src/osi/os/posix/osdSpin.c @@ -123,7 +123,7 @@ epicsSpinId epicsSpinCreate(void) { if (!spin) goto fail; - status = osdPosixMutexInit(&spin->lock, 0); + status = osdPosixMutexInit(&spin->lock, PTHREAD_MUTEX_DEFAULT); checkStatus(status, "osdPosixMutexInit"); if (status) goto fail; diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 45255881f..0eb5f5fd2 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -328,9 +328,9 @@ static void once(void) int status; pthread_key_create(&getpthreadInfo,0); - status = osdPosixMutexInit(&onceLock,0); + status = osdPosixMutexInit(&onceLock,PTHREAD_MUTEX_DEFAULT); checkStatusOnceQuit(status,"osdPosixMutexInit","epicsThreadInit"); - status = osdPosixMutexInit(&listLock,0); + status = osdPosixMutexInit(&listLock,PTHREAD_MUTEX_DEFAULT); checkStatusOnceQuit(status,"osdPosixMutexInit","epicsThreadInit"); pcommonAttr = calloc(1,sizeof(commonAttr)); if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit"); From bbb4d86f787b74579062aa77db9a98aee8e7ba80 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 25 Sep 2020 18:10:56 -0500 Subject: [PATCH 26/52] Enable RTEMS testing in modules/database/test/std/link --- modules/database/test/std/link/Makefile | 9 +++++++++ modules/database/test/std/link/lnkCalcTest.c | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/database/test/std/link/Makefile b/modules/database/test/std/link/Makefile index 2563fd591..fca089966 100644 --- a/modules/database/test/std/link/Makefile +++ b/modules/database/test/std/link/Makefile @@ -47,6 +47,8 @@ testHarness_SRCS += epicsRunLinkTests.c linkTestHarness_SRCS += $(testHarness_SRCS) linkTestHarness_SRCS_RTEMS += rtemsTestHarness.c +PROD_SRCS_RTEMS += rtemsTestData.c + PROD_vxWorks = linkTestHarness PROD_RTEMS = linkTestHarness @@ -54,9 +56,16 @@ TESTSPEC_vxWorks = linkTestHarness.munch; epicsRunLinkTests TESTSPEC_RTEMS = linkTestHarness.boot; epicsRunLinkTests TESTSCRIPTS_HOST += $(TESTS:%=%.t) +ifneq ($(filter $(T_A),$(CROSS_COMPILER_RUNTEST_ARCHS)),) + TESTPROD = $(TESTPROD_HOST) + TESTSCRIPTS_RTEMS += $(TESTS:%=%.t) +endif include $(TOP)/configure/RULES ioRecord$(DEP): $(COMMON_DIR)/ioRecord.h lnkStateTest$(DEP): $(COMMON_DIR)/ioRecord.h lnkCalcTest$(DEP): $(COMMON_DIR)/ioRecord.h + +rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl + $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) diff --git a/modules/database/test/std/link/lnkCalcTest.c b/modules/database/test/std/link/lnkCalcTest.c index 5297a53c5..b573e345d 100644 --- a/modules/database/test/std/link/lnkCalcTest.c +++ b/modules/database/test/std/link/lnkCalcTest.c @@ -157,7 +157,7 @@ static void testCalc() MAIN(lnkCalcTest) { - testPlan(0); + testPlan(30); testCalc(); From 4baf7912e1ba9cfdb5f88fe911020ffa2d418fcf Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Mar 2021 20:23:19 -0600 Subject: [PATCH 27/52] Tidying up in documentation directory --- documentation/Doxyfile@ | 21 --------------------- documentation/Makefile | 4 ++-- documentation/mainpage.dox | 1 - 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/documentation/Doxyfile@ b/documentation/Doxyfile@ index 482564264..442731a30 100644 --- a/documentation/Doxyfile@ +++ b/documentation/Doxyfile@ @@ -241,12 +241,6 @@ TAB_SIZE = 4 ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -2094,12 +2088,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2113,15 +2101,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. diff --git a/documentation/Makefile b/documentation/Makefile index 8148687cb..f94cd9d5f 100644 --- a/documentation/Makefile +++ b/documentation/Makefile @@ -5,7 +5,7 @@ ifdef T_A DOXYGEN=doxygen -EXPAND = Doxyfile +EXPAND = Doxyfile@ EXPAND_ME += EPICS_VERSION EXPAND_ME += EPICS_REVISION @@ -16,7 +16,7 @@ ME = documentation/O.$(T_A)/html install: doxygen -doxygen: Doxyfile +doxygen: Doxyfile ../mainpage.dox $(DOXYGEN) rsync -av $(TOP)/html/ html/ diff --git a/documentation/mainpage.dox b/documentation/mainpage.dox index f13fdcf97..472f1d999 100644 --- a/documentation/mainpage.dox +++ b/documentation/mainpage.dox @@ -3,7 +3,6 @@ Documentation index -@ul @li @ref releasenotes @li @ref install @li @ref recordrefmanual From 1fbbae73de69c15ae6389f1d029814ab2d8be26b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Mar 2021 20:27:45 -0600 Subject: [PATCH 28/52] Modify documentation/Doxyfile to parse include directory Excludes the include/pv and include/pva directories, which are processed separately in their own modules. --- documentation/Doxyfile@ | 53 +++++++---------------------------------- documentation/Makefile | 1 + 2 files changed, 10 insertions(+), 44 deletions(-) diff --git a/documentation/Doxyfile@ b/documentation/Doxyfile@ index 442731a30..44e09f69e 100644 --- a/documentation/Doxyfile@ +++ b/documentation/Doxyfile@ @@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = \ +STRIP_FROM_PATH = @TOP@/include \ ../ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the @@ -172,7 +172,8 @@ STRIP_FROM_PATH = \ # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = ../ +STRIP_FROM_INC_PATH = @TOP@/include \ + ../ # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -761,7 +762,8 @@ WARN_LOGFILE = INPUT = ../mainpage.dox \ ../RELEASE_NOTES.md \ ../README.md \ - ../RecordReference.md + ../RecordReference.md \ + @TOP@/include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -781,48 +783,10 @@ INPUT_ENCODING = UTF-8 # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.idl \ - *.ddl \ - *.odl \ - *.h \ - *.hh \ - *.hxx \ +FILE_PATTERNS = *.h \ *.hpp \ - *.h++ \ - *.cs \ - *.d \ - *.php \ - *.php4 \ - *.php5 \ - *.phtml \ - *.inc \ - *.m \ - *.markdown \ *.md \ - *.mm \ - *.dox \ - *.py \ - *.f90 \ - *.f \ - *.for \ - *.tcl \ - *.vhd \ - *.vhdl \ - *.ucf \ - *.qsf \ - *.as \ - *.js + *.dox # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -837,7 +801,8 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = @TOP@/include/pv \ + @TOP@/include/pva # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/documentation/Makefile b/documentation/Makefile index f94cd9d5f..d8e3b6a1d 100644 --- a/documentation/Makefile +++ b/documentation/Makefile @@ -11,6 +11,7 @@ EXPAND_ME += EPICS_VERSION EXPAND_ME += EPICS_REVISION EXPAND_ME += EPICS_MODIFICATION EXPAND_ME += EPICS_PATCH_LEVEL +EXPAND_ME += OS_CLASS CMPLR_CLASS ME = documentation/O.$(T_A)/html From 3ba778c08bfbf6364bdbefa41f16022b4c0f41d5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Mar 2021 21:35:07 -0600 Subject: [PATCH 29/52] documentation/Makefile tweaks --- documentation/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/documentation/Makefile b/documentation/Makefile index d8e3b6a1d..bd527e7db 100644 --- a/documentation/Makefile +++ b/documentation/Makefile @@ -1,7 +1,7 @@ TOP = .. include $(TOP)/configure/CONFIG -ifdef T_A +ifeq ($(T_A),$(EPICS_HOST_ARCH)) DOXYGEN=doxygen @@ -14,6 +14,7 @@ EXPAND_ME += EPICS_PATCH_LEVEL EXPAND_ME += OS_CLASS CMPLR_CLASS ME = documentation/O.$(T_A)/html +GH_FILES = $(ME)/ $(ME)/.nojekyll $(ME)/*.* $(ME)/*/*.* install: doxygen @@ -25,10 +26,10 @@ doxygen: Doxyfile ../mainpage.dox commit: doxygen $(TOUCH) html/.nojekyll - (cd $(TOP) && $(CURDIR)/../commit-gh.sh $(ME)/ $(ME)/.nojekyll $(ME)/*.* $(ME)/*/*.*) + (cd $(TOP) && $(CURDIR)/../commit-gh.sh $(GH_FILES)) .PHONY: commit -endif # T_A +endif # EPICS_HOST_ARCH include $(TOP)/configure/RULES From 6786b2e7c2474cfe3c5e3821f9d18ad77f5a2d30 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Mar 2021 21:25:24 -0600 Subject: [PATCH 30/52] Modify the Doxyfile to match earlier settings --- documentation/Doxyfile@ | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/documentation/Doxyfile@ b/documentation/Doxyfile@ index 44e09f69e..bf53ee0ce 100644 --- a/documentation/Doxyfile@ +++ b/documentation/Doxyfile@ @@ -107,7 +107,7 @@ BRIEF_MEMBER_DESC = YES # brief descriptions will be completely suppressed. # The default value is: YES. -REPEAT_BRIEF = YES +REPEAT_BRIEF = NO # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found @@ -143,7 +143,7 @@ ALWAYS_DETAILED_SEC = NO # operators of the base classes will not be shown. # The default value is: NO. -INLINE_INHERITED_MEMB = NO +INLINE_INHERITED_MEMB = YES # If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the @@ -163,7 +163,7 @@ FULL_PATH_NAMES = YES # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = @TOP@/include \ - ../ + .. # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -173,7 +173,7 @@ STRIP_FROM_PATH = @TOP@/include \ # using the -I flag. STRIP_FROM_INC_PATH = @TOP@/include \ - ../ + .. # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -228,7 +228,7 @@ SEPARATE_MEMBER_PAGES = NO # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. -TAB_SIZE = 4 +TAB_SIZE = 8 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: @@ -415,7 +415,7 @@ LOOKUP_CACHE_SIZE = 0 # normally produced when WARNINGS is set to YES. # The default value is: NO. -EXTRACT_ALL = YES +EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class will # be included in the documentation. @@ -543,7 +543,7 @@ INLINE_INFO = YES # name. If set to NO the members will appear in declaration order. # The default value is: YES. -SORT_MEMBER_DOCS = YES +SORT_MEMBER_DOCS = NO # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member @@ -818,7 +818,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = O.* +EXCLUDE_PATTERNS = /O.*/ # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -1987,7 +1987,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = __cplusplus # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2006,7 +2006,7 @@ EXPAND_AS_DEFINED = # The default value is: YES. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -SKIP_FUNCTION_MACROS = YES +SKIP_FUNCTION_MACROS = NO #--------------------------------------------------------------------------- # Configuration options related to external references From f571c5950bfe476ef79d4c143f50e2f9e0d5edc7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 5 Aug 2018 00:12:54 -0500 Subject: [PATCH 31/52] Modify DBD processing scripts to output Doxygen comments --- modules/database/src/tools/DBD/Menu.pm | 5 ++++- modules/database/src/tools/DBD/Recfield.pm | 6 +++--- modules/database/src/tools/DBD/Recordtype.pm | 13 +++++++++---- modules/database/src/tools/dbdToMenuH.pl | 6 +++++- modules/database/src/tools/dbdToRecordtypeH.pl | 12 +++++++++--- modules/database/test/tools/Menu.plt | 6 ++++-- 6 files changed, 34 insertions(+), 14 deletions(-) diff --git a/modules/database/src/tools/DBD/Menu.pm b/modules/database/src/tools/DBD/Menu.pm index 38a2aba99..5480b3952 100644 --- a/modules/database/src/tools/DBD/Menu.pm +++ b/modules/database/src/tools/DBD/Menu.pm @@ -67,13 +67,16 @@ sub toDeclaration { my $name = $this->name; my $macro_name = "${name}_NUM_CHOICES"; my @choices = map { - sprintf " %-31s /* %s */", @{$_}[0], escapeCcomment(@{$_}[1]); + sprintf " %-31s /**< \@brief State string \"%s\" */", + @{$_}[0], escapeCcomment(@{$_}[1]); } $this->choices; my $num = scalar @choices; return "#ifndef $macro_name\n" . + "/** \@brief Enumerated type from menu $name */\n" . "typedef enum {\n" . join(",\n", @choices) . "\n} $name;\n" . + "/** \@brief Number of states defined for menu $name */\n" . "#define $macro_name $num\n" . "#endif\n\n"; } diff --git a/modules/database/src/tools/DBD/Recfield.pm b/modules/database/src/tools/DBD/Recfield.pm index cc49bcc46..b4bd5d318 100644 --- a/modules/database/src/tools/DBD/Recfield.pm +++ b/modules/database/src/tools/DBD/Recfield.pm @@ -185,7 +185,7 @@ sub toDeclaration { my $name = $this->C_name; my $result = sprintf " %-19s %-12s", $ctype, "$name;"; my $prompt = $this->attribute('prompt'); - $result .= "/* $prompt */" if defined $prompt; + $result .= "/**< \@brief $prompt */" if defined $prompt; return $result; } @@ -217,7 +217,7 @@ sub toDeclaration { my $size = $this->attribute('size'); my $result = sprintf " %-19s %-12s", 'char', "${name}[${size}];"; my $prompt = $this->attribute('prompt'); - $result .= "/* $prompt */" if defined $prompt; + $result .= "/**< \@brief $prompt */" if defined $prompt; return $result; } @@ -540,7 +540,7 @@ sub toDeclaration { my $extra = $this->attribute('extra'); my $result = sprintf " %-31s ", "$extra;"; my $prompt = $this->attribute('prompt'); - $result .= "/* $prompt */" if defined $prompt; + $result .= "/**< \@brief $prompt */" if defined $prompt; return $result; } diff --git a/modules/database/src/tools/DBD/Recordtype.pm b/modules/database/src/tools/DBD/Recordtype.pm index a602f5da4..1e626fdf8 100644 --- a/modules/database/src/tools/DBD/Recordtype.pm +++ b/modules/database/src/tools/DBD/Recordtype.pm @@ -132,10 +132,15 @@ sub toDeclaration { $_->toDeclaration } $this->fields; my $name = $this->name; - $name .= "Record" unless $name eq "dbCommon"; - return "typedef struct $name {\n" . - join("\n", @fields) . - "\n} $name;\n\n"; + my $doc = $name; + if ($name ne 'dbCommon') { + $name .= 'Record'; + $doc .= ' record type.'; + } + return "/** \@brief Declaration of $doc */\n" . + "typedef struct $name {\n" . + join("\n", @fields) . + "\n} $name;\n\n"; } 1; diff --git a/modules/database/src/tools/dbdToMenuH.pl b/modules/database/src/tools/dbdToMenuH.pl index 10f1904fb..71352edff 100644 --- a/modules/database/src/tools/dbdToMenuH.pl +++ b/modules/database/src/tools/dbdToMenuH.pl @@ -11,6 +11,8 @@ use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); +use strict; + use EPICS::Getopts; use File::Basename; use DBD; @@ -57,7 +59,9 @@ if ($opt_D) { print map { "$_:\n" } @uniqfiles; } else { open OUTFILE, ">$outfile" or die "$tool: Can't open $outfile: $!\n"; - print OUTFILE "/* $outbase generated from $inbase */\n\n", + print OUTFILE "/** \@file $outbase\n", + " * \@brief Declarations generated from $inbase\n", + " */\n\n", "#ifndef $guard_name\n", "#define $guard_name\n\n"; my $menus = $dbd->menus; diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl index 76bae7fbf..0bb3839fe 100644 --- a/modules/database/src/tools/dbdToRecordtypeH.pl +++ b/modules/database/src/tools/dbdToRecordtypeH.pl @@ -61,13 +61,19 @@ if ($opt_D) { # Output dependencies only, to stdout print "$outfile: ", join(" \\\n ", @uniqfiles), "\n\n"; print map { "$_:\n" } @uniqfiles; } else { + our ($rn, $rtyp) = each %{$rtypes}; + my $rtn = $rn; + $rtn .= 'Record' if $rn ne 'dbCommon'; + open OUTFILE, ">$outfile" or die "$tool: Can't open $outfile: $!\n"; - print OUTFILE "/* $outbase generated from $inbase */\n\n", + print OUTFILE "/** \@file $outbase\n", + " * \@brief Declarations for the \@ref $rtn \"$rn\" record type.\n", + " *\n", + " * This header was generated from $inbase\n", + " */\n\n", "#ifndef $guard_name\n", "#define $guard_name\n\n"; - our ($rn, $rtyp) = each %{$rtypes}; - print OUTFILE $rtyp->toCdefs; my @menu_fields = grep { diff --git a/modules/database/test/tools/Menu.plt b/modules/database/test/tools/Menu.plt index 25b0c2020..8e667c833 100644 --- a/modules/database/test/tools/Menu.plt +++ b/modules/database/test/tools/Menu.plt @@ -30,10 +30,12 @@ is_deeply $menu->choice(2), undef, 'Third choice undefined'; like $menu->toDeclaration, qr/ ^ \s* \# \s* ifndef \s+ test_NUM_CHOICES \s* \n + \s* \/\*\* [^*]* \*\/ \s* \n \s* typedef \s+ enum \s+ \{ \s* \n - \s* ch1 \s+ \/\* [^*]* \*\/, \s* \n - \s* ch2 \s+ \/\* [^*]* \*\/ \s* \n + \s* ch1 \s+ \/\*\* [^*]* \*\/, \s* \n + \s* ch2 \s+ \/\*\* [^*]* \*\/ \s* \n \s* \} \s* test \s* ; \s* \n + \s* \/\*\* [^*]* \*\/ \s* \n \s* \# \s* define \s+ test_NUM_CHOICES \s+ 2 \s* \n \s* \# \s* endif \s* \n \s* $ /x, 'C declaration'; From 2ea0994507e748eb0cf5df166d3ff4ad12be4ec2 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Tue, 9 Mar 2021 13:04:57 +0000 Subject: [PATCH 32/52] tests passing --- src/libCom/osi/os/WIN32/osdStrtod.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libCom/osi/os/WIN32/osdStrtod.h b/src/libCom/osi/os/WIN32/osdStrtod.h index 4edb444ee..9a2e8d75e 100644 --- a/src/libCom/osi/os/WIN32/osdStrtod.h +++ b/src/libCom/osi/os/WIN32/osdStrtod.h @@ -13,10 +13,6 @@ extern "C" { #endif -/* - * epicsStrtod() for systems with broken strtod() routine - */ -epicsShareFunc double epicsStrtod(const char *str, char **endp); /* * Microsoft apparently added strto[u]ll() in VS2013 @@ -28,6 +24,15 @@ epicsShareFunc double epicsStrtod(const char *str, char **endp); # define strtoull _strtoui64 #endif +#if (_MSC_VER < 1800) && defined(_MINGW) +/* + * epicsStrtod() for systems with broken strtod() routine + */ +epicsShareFunc double epicsStrtod(const char *str, char **endp); +#else +# define epicsStrtod strtod +#endif + #ifdef __cplusplus } #endif From 30172226f9ea5a413526749cd24f812e19817634 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Tue, 9 Mar 2021 13:13:16 +0000 Subject: [PATCH 33/52] whoops, MSVC 1900 not 1800 --- src/libCom/osi/os/WIN32/osdStrtod.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libCom/osi/os/WIN32/osdStrtod.h b/src/libCom/osi/os/WIN32/osdStrtod.h index 9a2e8d75e..a7df57002 100644 --- a/src/libCom/osi/os/WIN32/osdStrtod.h +++ b/src/libCom/osi/os/WIN32/osdStrtod.h @@ -24,7 +24,11 @@ extern "C" { # define strtoull _strtoui64 #endif -#if (_MSC_VER < 1800) && defined(_MINGW) +/* + * strtod works in MSVC 1900 and mingw, use + * the OS version in those and our own otherwise + */ +#if (_MSC_VER < 1900) && !defined(_MINGW) /* * epicsStrtod() for systems with broken strtod() routine */ From 979445c8fe557116dbd3c2fa8c552e5514a5e820 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 9 Mar 2021 08:48:27 -0800 Subject: [PATCH 34/52] ci: add gcc-9 build --- .github/workflows/ci-scripts-build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 83bdd9dde..f14f5ef66 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -98,6 +98,12 @@ jobs: configuration: default name: "Ub-20 gcc-8" + - os: ubuntu-20.04 + cmp: gcc-9 + utoolchain: "9" + configuration: default + name: "Ub-20 gcc-9" + - os: ubuntu-20.04 cmp: clang configuration: default From 09820d799e7a1020b1b88268f1f28ce54e19256c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 10 Mar 2021 01:11:04 -0600 Subject: [PATCH 35/52] Fix POD-generated HTML anchor IDs --- src/tools/EPICS/PodHtml.pm | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/tools/EPICS/PodHtml.pm b/src/tools/EPICS/PodHtml.pm index 785372159..a02fc9cc9 100644 --- a/src/tools/EPICS/PodHtml.pm +++ b/src/tools/EPICS/PodHtml.pm @@ -46,17 +46,20 @@ sub do_pod_link { return $ret; } -# Generate the same section IDs as Pod::Simple::XHTML +# Generate legal section IDs sub section_name_tidy { - my($self, $section) = @_; - $section =~ s/^\s+//; - $section =~ s/\s+$//; - $section =~ tr/ /-/; - $section =~ s/[[:cntrl:][:^ascii:]]//g; # drop crazy characters - $section = $self->unicode_escape_url($section); - $section = '_' unless length $section; - return $section; + my($self, $t) = @_; + for ($t) { + s/<[^>]+>//g; # Strip HTML. + s/&[^;]+;//g; # Strip entities. + s/^\s+//; s/\s+$//; # Strip white space. + s/^([^a-zA-Z]+)$/pod$1/; # Prepend "pod" if no valid chars. + s/^[^a-zA-Z]+//; # First char must be a letter. + s/[^-a-zA-Z0-9_:.]+/-/g; # All other chars must be valid. + s/[-:.]+$//; # Strip trailing punctuation. + } + return $t; } 1; From 436a5e7fa282fb4c324bfeeabba43fb872516ebe Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 10 Mar 2021 01:12:55 -0600 Subject: [PATCH 36/52] Fix markdown link in Release Notes Found by Kathryn Baker --- documentation/RELEASE_NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 587b52448..49cdd74ef 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -457,7 +457,7 @@ work with older Base releases. This would also be a good time to modify the device support to use the type-safe device support entry tables that were introduced in Base-3.16.2 -- see -[#type-safe-device-and-driver-support-tables](this entry below) for the +[this entry below](#type-safe-device-and-driver-support-tables) for the description of that change, which is also optional for now. Look at the aiRecord for example. Near the top of the generated `aiRecord.h` From 6ac10d43b1bc3f8ae475abd448a6c62bdb12f158 Mon Sep 17 00:00:00 2001 From: Gabriel Fedel Date: Wed, 10 Mar 2021 09:42:56 +0100 Subject: [PATCH 37/52] Fix type comparision on msi.cpp This change fix the comparision of different signedess (int and long unsigned int). --- src/ioc/dbtemplate/msi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/dbtemplate/msi.cpp b/src/ioc/dbtemplate/msi.cpp index 462869cb3..34afaabd5 100644 --- a/src/ioc/dbtemplate/msi.cpp +++ b/src/ioc/dbtemplate/msi.cpp @@ -300,7 +300,7 @@ static void makeSubstitutions(inputData * const inputPvt, char *pstart; char *pend; int cmdind=-1; - int i; + long unsigned int i; for (i = 0; i < NELEMENTS(cmdNames); i++) { if (strstr(command, cmdNames[i])) { From 8e7702c8a569b212ffd5df44a430384e3ec37fc3 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Wed, 10 Mar 2021 11:29:45 +0000 Subject: [PATCH 38/52] Use epicsStrtod, remove some warnings --- src/libCom/yajl/yajl_parser.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index bbcf80880..b57b1b40d 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -45,6 +45,8 @@ #include "yajl_encode.h" #include "yajl_bytestack.h" +#include + unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, unsigned int jsonTextLen, int verbose) @@ -67,14 +69,14 @@ yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, } { - unsigned int memneeded = 0; + size_t memneeded = 0; memneeded += strlen(errorType); memneeded += strlen(" error"); if (errorText != NULL) { memneeded += strlen(": "); memneeded += strlen(errorText); } - str = (unsigned char *) YA_MALLOC(&(hand->alloc), memneeded + 2); + str = (unsigned char *) YA_MALLOC(&(hand->alloc), (unsigned int)(memneeded + 2)); str[0] = 0; strcat((char *) str, errorType); strcat((char *) str, " error"); @@ -263,7 +265,7 @@ yajl_do_parse(yajl_handle hand, const unsigned char * jsonText, yajl_buf_clear(hand->decodeBuf); yajl_buf_append(hand->decodeBuf, buf, bufLen); buf = yajl_buf_data(hand->decodeBuf); - d = strtod((char *) buf, NULL); + d = epicsStrtod((char *) buf, NULL); if ((d == HUGE_VAL || d == -HUGE_VAL) && errno == ERANGE) { From 0bc2a3e99930974199940b0d50e2c92401c980d3 Mon Sep 17 00:00:00 2001 From: Gabriel Fedel Date: Wed, 10 Mar 2021 14:37:14 +0100 Subject: [PATCH 39/52] Fix variable type and cast on msi.cpp This way the attribution of i to cmdind is a valid value. --- src/ioc/dbtemplate/msi.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ioc/dbtemplate/msi.cpp b/src/ioc/dbtemplate/msi.cpp index 34afaabd5..6b899830f 100644 --- a/src/ioc/dbtemplate/msi.cpp +++ b/src/ioc/dbtemplate/msi.cpp @@ -300,11 +300,11 @@ static void makeSubstitutions(inputData * const inputPvt, char *pstart; char *pend; int cmdind=-1; - long unsigned int i; + size_t i; for (i = 0; i < NELEMENTS(cmdNames); i++) { if (strstr(command, cmdNames[i])) { - cmdind = i; + cmdind = (int)i; } } if (cmdind < 0) goto endcmd; From c359b49aedbbb2e91c1c5e6c38904ee1a3d7363f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 10 Mar 2021 22:05:39 -0600 Subject: [PATCH 40/52] Fix the 3.15 'make inc' build target Now generates and installs dbd, header and html files. No compilation involved/required. --- configure/RULES.Db | 3 ++- configure/RULES_BUILD | 6 ++++-- configure/RULES_TOP | 2 +- src/ioc/bpt/Makefile | 3 +++ src/tools/Makefile | 2 ++ 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/configure/RULES.Db b/configure/RULES.Db index 8c5d99ed7..7cf50322b 100644 --- a/configure/RULES.Db +++ b/configure/RULES.Db @@ -187,7 +187,8 @@ endif ##################################################### build dependancies, clean rule -inc : $(COMMON_INC) $(INSTALL_INC) +inc : $(COMMON_INC) $(INSTALL_INC) $(COMMON_DBDS) $(COMMON_DBDCATS) \ + $(INSTALL_DBDS) $(INSTALL_DBD_INSTALLS) build : $(COMMON_DBDS) $(COMMON_DBS) $(COMMON_DBDCATS) \ $(INSTALL_DBDS) $(INSTALL_DBS) \ diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 3dcbcaa74..96603d26b 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -93,10 +93,12 @@ include $(CONFIG)/RULES_TARGET #--------------------------------------------------------------- # Read dependency files +ifneq (inc,$(strip $(MAKECMDGOALS))) ifneq (,$(strip $(HDEPENDS_FILES))) $(filter-out $(wildcard *$(DEP)), $(HDEPENDS_FILES)): | $(COMMON_INC) -include $(HDEPENDS_FILES) endif +endif #--------------------------------------------------------------- # Products and Object libraries @@ -144,14 +146,14 @@ build: inc build: $(OBJSNAME) $(LIBTARGETS) $(PRODTARGETS) $(TESTPRODTARGETS) \ $(TARGETS) $(TESTSCRIPTS) $(INSTALL_LIB_INSTALLS) -inc : $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS) +inc : $(COMMON_INC) $(INSTALL_INC) $(INSTALL_CONFIGS) \ + $(INSTALL_HTMLS) buildInstall : \ $(INSTALL_SCRIPTS) $(INSTALL_PROD) $(INSTALL_MUNCHS) \ $(INSTALL_TCLLIBS) $(INSTALL_TCLINDEX) \ $(INSTALL_OBJS) \ $(INSTALL_DOCS) \ - $(INSTALL_HTMLS) \ $(INSTALL_TEMPLATE) \ $(INSTALL_BIN_INSTALLS) diff --git a/configure/RULES_TOP b/configure/RULES_TOP index abcd75cb8..012d7f9ad 100644 --- a/configure/RULES_TOP +++ b/configure/RULES_TOP @@ -45,7 +45,7 @@ help: @echo "Usage: gnumake [options] [target] ..." @echo "Targets supported by all Makefiles:" @echo " all - Same as install (default rule)" - @echo " inc - Installs header files" + @echo " inc - Installs header, dbd and html files" @echo " build - Builds and installs all targets" @echo " install - Builds and installs all targets" @echo " buildInstall - Same as install (deprecated)" diff --git a/src/ioc/bpt/Makefile b/src/ioc/bpt/Makefile index b8d73345f..d6367bfe3 100644 --- a/src/ioc/bpt/Makefile +++ b/src/ioc/bpt/Makefile @@ -19,7 +19,10 @@ BPT_DBD += bptTypeJdegC.dbd BPT_DBD += bptTypeJdegF.dbd BPT_DBD += bptTypeKdegC.dbd BPT_DBD += bptTypeKdegF.dbd + +ifneq (inc,$(strip $(MAKECMDGOALS))) DBD += $(BPT_DBD) +endif PROD_HOST += makeBpt diff --git a/src/tools/Makefile b/src/tools/Makefile index faa08abbf..1d9991d2b 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -86,6 +86,8 @@ CLEANS += epics-base-$(T_A).pc@ include $(TOP)/configure/RULES +inc: $(INSTALLS_PERL_MODULES) $(INSTALL_SCRIPTS) + epics-base-$(T_A).pc@: ../epics-base-arch.pc@ @$(RM) $@ @$(CP) $< $@ From 3c7fb7990f3558948a4a418bceafed412f29cb6b Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Thu, 11 Mar 2021 15:08:00 +0000 Subject: [PATCH 41/52] Use --- src/libCom/yajl/yajl_parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/yajl/yajl_parser.c b/src/libCom/yajl/yajl_parser.c index b57b1b40d..7a27f29d8 100644 --- a/src/libCom/yajl/yajl_parser.c +++ b/src/libCom/yajl/yajl_parser.c @@ -45,7 +45,7 @@ #include "yajl_encode.h" #include "yajl_bytestack.h" -#include +#include unsigned char * yajl_render_error_string(yajl_handle hand, const unsigned char * jsonText, From f30e9533c49b50cbdddc361b327f97e5e3d9612c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 11 Mar 2021 08:09:34 -0800 Subject: [PATCH 42/52] epicsLoadTest use INSTALL_LOCATION --- modules/libcom/test/Makefile | 7 +++++++ modules/libcom/test/epicsLoadTest.cpp | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index 3ad869afb..ef8605002 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -337,3 +337,10 @@ include $(TOP)/configure/RULES rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) + +epicsLoadTest$(DEP): epicsInstallDir.h + +# use INSTALL_LOCATION instead of FINAL_LOCATION since test executables are not installed. +epicsInstallDir.h: $(TOP)/configure/CONFIG_SITE* + $(ECHO) "INSTALL_LOCATION=$(INSTALL_LOCATION)" + $(PERL) $(TOP)/modules/database/src/std/softIoc/makeInstallDir.pl "$(INSTALL_LOCATION)" > $@ diff --git a/modules/libcom/test/epicsLoadTest.cpp b/modules/libcom/test/epicsLoadTest.cpp index 304c42d73..3ffc89949 100644 --- a/modules/libcom/test/epicsLoadTest.cpp +++ b/modules/libcom/test/epicsLoadTest.cpp @@ -16,6 +16,8 @@ #include "epicsFindSymbol.h" #include "epicsThread.h" +#include "epicsInstallDir.h" + namespace { void loadBad() @@ -52,9 +54,9 @@ void loadCA() std::ostringstream strm; // running in eg. modules/libcom/test/O.linux-x86_64-debug #ifdef _WIN32 - strm<<"..\\..\\..\\..\\bin\\"< Date: Thu, 11 Mar 2021 18:13:44 -0600 Subject: [PATCH 43/52] Minor fixes in configure/RULES files --- configure/RULES.Db | 2 +- configure/RULES_BUILD | 5 +++-- configure/RULES_TARGET | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/configure/RULES.Db b/configure/RULES.Db index 8c5d99ed7..61b548386 100644 --- a/configure/RULES.Db +++ b/configure/RULES.Db @@ -159,7 +159,7 @@ cleanArchTargets = $(foreach arch,$(BUILD_ARCHS), clean$(DIVIDER)$(arch)) -include $(TOP)/configure/CONFIG_APP_INCLUDE all: install -ifeq ($(EPICS_HOST_ARCH),$T_A) +ifeq ($(EPICS_HOST_ARCH),$(T_A)) host: install else # Do nothing diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 3dcbcaa74..13428d846 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -86,9 +86,10 @@ endif #--------------------------------------------------------------- # Include defines and rules for prod, library and test* targets -#ifneq (,$(strip $(PROD) $(TESTPROD) $(LIBRARY) $(TESTLIBRARY) $(LOADABLE_LIBRARY) )) +ifneq (,$(strip $(PROD) $(TESTPROD) $(LIBRARY) $(TESTLIBRARY) \ + $(LOADABLE_LIBRARY))) include $(CONFIG)/RULES_TARGET -#endif +endif #--------------------------------------------------------------- # Read dependency files diff --git a/configure/RULES_TARGET b/configure/RULES_TARGET index 4e9cb6e05..ece7e10bc 100644 --- a/configure/RULES_TARGET +++ b/configure/RULES_TARGET @@ -26,7 +26,6 @@ $(foreach target, $(PROD) $(TESTPROD) $(LIBRARY) $(TESTLIBRARY) $(LOADABLE_LIBRA #----------------------------------------------------------------------- -# This define block requires GNU make 3.81 define PROD_template ifeq ($$(strip $$($(1)_OBJS) $$($(1)_SRCS) $$(PRODUCT_OBJS)),) $(1)_OBJS = $(1)$$(OBJ) From ca3ef9c61e57a7413ad9626f17ce9205cdabdc5f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 12 Mar 2021 08:06:31 -0800 Subject: [PATCH 44/52] dbUnitTest use dbChannel Allows testing of server side filters --- modules/database/src/ioc/db/dbUnitTest.c | 101 ++++++++++++++++------- 1 file changed, 73 insertions(+), 28 deletions(-) diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c index 65c817bbb..0b40d929c 100644 --- a/modules/database/src/ioc/db/dbUnitTest.c +++ b/modules/database/src/ioc/db/dbUnitTest.c @@ -112,12 +112,13 @@ union anybuf { long testdbVPutField(const char* pv, short dbrType, va_list ap) { - DBADDR addr; + dbChannel *chan = dbChannelCreate(pv); union anybuf pod; + long ret = S_dbLib_recNotFound; - if (dbNameToAddr(pv, &addr)) { - testFail("Missing PV \"%s\"", pv); - return S_dbLib_recNotFound; + if(!chan || (ret=dbChannelOpen(chan))) { + testFail("Channel error (%p, %ld) : %s", chan, ret, pv); + goto done; } switch(dbrType) { @@ -125,14 +126,18 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap) const char *uarg = va_arg(ap,char*); strncpy(pod.valStr, uarg, sizeof(pod.valStr)); pod.valStr[sizeof(pod.valStr)-1] = '\0'; - return dbPutField(&addr, dbrType, pod.valStr, 1); + ret = dbChannelPutField(chan, dbrType, pod.valStr, 1); + break; } /* The Type parameter takes into consideration * the C language rules for promotion of argument types * in variadic functions. */ -#define OP(DBR,Type,mem) case DBR: {pod.val.mem = va_arg(ap,Type); break;} +#define OP(DBR,Type,mem) case DBR: \ + pod.val.mem = va_arg(ap,Type); \ + ret = dbChannelPutField(chan, dbrType, pod.bytes, 1); \ + break; OP(DBR_CHAR, int, int8); OP(DBR_UCHAR, int, uInt8); OP(DBR_SHORT, int, int16); @@ -147,11 +152,15 @@ long testdbVPutField(const char* pv, short dbrType, va_list ap) #undef OP default: testFail("invalid DBR: dbPutField(\"%s\", %d, ...)", - addr.precord->name, dbrType); - return S_db_badDbrtype; + dbChannelName(chan), dbrType); + ret = S_db_badDbrtype; + break; } - return dbPutField(&addr, dbrType, pod.bytes, 1); +done: + if(chan) + dbChannelDelete(chan); + return ret; } void testdbPutFieldOk(const char* pv, int dbrType, ...) @@ -190,23 +199,35 @@ void testdbGetFieldEqual(const char* pv, int dbrType, ...) void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap) { - DBADDR addr; + dbChannel *chan = dbChannelCreate(pv); + db_field_log *pfl = NULL; long nReq = 1; union anybuf pod; - long status; + long status = S_dbLib_recNotFound; - if(dbNameToAddr(pv, &addr)) { - testFail("Missing PV \"%s\"", pv); - return; + if(!chan || (status=dbChannelOpen(chan))) { + testFail("Channel error (%p, %ld) : %s", chan, status, pv); + goto done; } - status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL); + if(ellCount(&chan->filters)) { + pfl = db_create_read_log(chan); + if (!pfl) { + testFail("can't db_create_read_log w/ %s", pv); + goto done; + } + + pfl = dbChannelRunPreChain(chan, pfl); + pfl = dbChannelRunPostChain(chan, pfl); + } + + status = dbChannelGetField(chan, dbrType, pod.bytes, NULL, &nReq, pfl); if (status) { testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status)); - return; + goto done; } else if(nReq==0) { testFail("dbGetField(\"%s\", %d, ...) -> zero length", pv, dbrType); - return; + goto done; } switch(dbrType) { @@ -236,35 +257,56 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap) default: testFail("dbGetField(\"%s\", %d) -> unsupported dbf", pv, dbrType); } + +done: + db_delete_field_log(pfl); + if(chan) + dbChannelDelete(chan); } void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf) { - DBADDR addr; + dbChannel *chan = dbChannelCreate(pv); long status; - if (dbNameToAddr(pv, &addr)) { - testFail("Missing PV \"%s\"", pv); - return; + if(!chan || (status=dbChannelOpen(chan))) { + testFail("Channel error (%p, %ld) : %s", chan, status, pv); + goto done; } - status = dbPutField(&addr, dbrType, pbuf, count); + status = dbChannelPutField(chan, dbrType, pbuf, count); testOk(status==0, "dbPutField(\"%s\", dbr=%d, count=%lu, ...) -> %ld", pv, dbrType, count, status); + +done: + if(chan) + dbChannelDelete(chan); } void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsigned long cnt, const void *pbufraw) { - DBADDR addr; + dbChannel *chan = dbChannelCreate(pv); + db_field_log *pfl = NULL; const long vSize = dbValueSize(dbfType); const long nStore = vSize * nRequest; - long status; + long status = S_dbLib_recNotFound; char *gbuf, *gstore; const char *pbuf = pbufraw; - if(dbNameToAddr(pv, &addr)) { - testFail("Missing PV \"%s\"", pv); - return; + if(!chan || (status=dbChannelOpen(chan))) { + testFail("Channel error (%p, %ld) : %s", chan, status, pv); + goto done; + } + + if(ellCount(&chan->filters)) { + pfl = db_create_read_log(chan); + if (!pfl) { + testFail("can't db_create_read_log w/ %s", pv); + goto done; + } + + pfl = dbChannelRunPreChain(chan, pfl); + pfl = dbChannelRunPostChain(chan, pfl); } gbuf = gstore = malloc(nStore); @@ -273,7 +315,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign return; } - status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL); + status = dbChannelGetField(chan, dbfType, gbuf, NULL, &nRequest, pfl); if (status) { testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status); @@ -318,7 +360,10 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign testOk(match, "dbGetField(\"%s\", dbrType=%d, nRequest=%ld ...) match", pv, dbfType, nRequest); } +done: free(gstore); + if(chan) + dbChannelDelete(chan); } dbCommon* testdbRecordPtr(const char* pv) From 1fcbdad5e991af5b8c7a4f6996c9a301e849bfc1 Mon Sep 17 00:00:00 2001 From: Dominic Oram Date: Mon, 8 Mar 2021 19:25:26 +0000 Subject: [PATCH 45/52] Adds doxygen annotations to epicsType.h --- modules/libcom/src/misc/epicsTypes.h | 64 ++++++++++++++++++---------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/modules/libcom/src/misc/epicsTypes.h b/modules/libcom/src/misc/epicsTypes.h index 1beb5d2e4..09e550d78 100644 --- a/modules/libcom/src/misc/epicsTypes.h +++ b/modules/libcom/src/misc/epicsTypes.h @@ -8,9 +8,11 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* - * Author: Jeff Hill - * Date: 5-95 +/** + * \file epicsTypes.h + * \author: Jeff Hill + * + * \brief The core data types used by epics */ #ifndef INC_epicsTypes_H @@ -32,9 +34,12 @@ typedef enum { epicsTrue = 1 } epicsBoolean EPICS_DEPRECATED; -/* +/** + * \name epicsTypes * Architecture Independent Data Types + * * These are sufficient for all our current archs + * @{ */ typedef char epicsInt8; typedef unsigned char epicsUInt8; @@ -49,25 +54,28 @@ typedef epicsUInt16 epicsEnum16; typedef float epicsFloat32; typedef double epicsFloat64; typedef epicsInt32 epicsStatus; + /** @} */ +#define MAX_STRING_SIZE 40 +/** + * \brief !! Dont use this - it may vanish in the future !! + */ typedef struct { unsigned length; char *pString; } epicsString; -/* - * !! Dont use this - it may vanish in the future !! +/** + * \brief !! Dont use this - it may vanish in the future !! * * Provided only for backwards compatibility with * db_access.h - * */ -#define MAX_STRING_SIZE 40 typedef char epicsOldString[MAX_STRING_SIZE]; -/* - * union of all types +/** + * \brief Union of all types * * Strings included here as pointers only so that we support * large string types. @@ -90,11 +98,11 @@ typedef union epics_any { epicsString string; } epicsAny; -/* - * Corresponding Type Codes +/** + * \brief Corresponding Type Codes * (this enum must start at zero) * - * !! Update epicsTypeToDBR_XXXX[] and DBR_XXXXToEpicsType + * !! Update \ref epicsTypeToDBR_XXXX[] and \ref DBR_XXXXToEpicsType * in db_access.h if you edit this enum !! */ typedef enum { @@ -116,8 +124,9 @@ typedef enum { #define invalidEpicsType(x) ((xlastEpicsType)) -/* - * The enumeration "epicsType" is an index to this array +/** + * \brief An array providing the names for each type + * The enumeration \ref epicsType is an index to this array * of type name strings. */ #ifdef epicsTypesGLOBAL @@ -138,8 +147,9 @@ const char *epicsTypeNames [lastEpicsType+1] = { LIBCOM_API extern const char *epicsTypeNames [lastEpicsType+1]; #endif /* epicsTypesGLOBAL */ -/* - * The enumeration "epicsType" is an index to this array +/** + * \brief An array providing the names for each type code + * The enumeration \ref epicsType is an index to this array * of type code name strings. */ #ifdef epicsTypesGLOBAL @@ -160,6 +170,11 @@ const char *epicsTypeCodeNames [lastEpicsType+1] = { LIBCOM_API extern const char *epicsTypeCodeNames [lastEpicsType+1]; #endif /* epicsTypesGLOBAL */ +/** + * \brief An array providing the sizes for each type + * The enumeration \ref epicsType is an index to this array + * of type code name strings. + */ #ifdef epicsTypesGLOBAL const unsigned epicsTypeSizes [lastEpicsType+1] = { sizeof (epicsInt8), @@ -178,10 +193,6 @@ const unsigned epicsTypeSizes [lastEpicsType+1] = { LIBCOM_API extern const unsigned epicsTypeSizes [lastEpicsType+1]; #endif /* epicsTypesGLOBAL */ -/* - * The enumeration "epicsType" is an index to this array - * of type class identifiers. - */ typedef enum { epicsIntC, epicsUIntC, @@ -191,6 +202,11 @@ typedef enum { epicsOldStringC } epicsTypeClass; +/** + * \brief An array providing the class of each type + * The enumeration \ref epicsType is an index to this array + * of type class identifiers. + */ #ifdef epicsTypesGLOBAL const epicsTypeClass epicsTypeClasses [lastEpicsType+1] = { epicsIntC, @@ -209,7 +225,11 @@ const epicsTypeClass epicsTypeClasses [lastEpicsType+1] = { LIBCOM_API extern const epicsTypeClass epicsTypeClasses [lastEpicsType+1]; #endif /* epicsTypesGLOBAL */ - +/** + * \brief An array providing the field name for each type + * The enumeration \ref epicsType is an index to this array + * of type code name strings. + */ #ifdef epicsTypesGLOBAL const char *epicsTypeAnyFieldName [lastEpicsType+1] = { "int8", From ef878808ce68189be36c927cbb104eedede873d8 Mon Sep 17 00:00:00 2001 From: Matthew Pearson Date: Tue, 9 Mar 2021 10:55:49 -0500 Subject: [PATCH 46/52] errlog.h: added doxygen comments. --- modules/libcom/src/error/errlog.h | 166 +++++++++++++++++++++++++++++- 1 file changed, 164 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/error/errlog.h b/modules/libcom/src/error/errlog.h index 425e78ac6..02f2c0816 100644 --- a/modules/libcom/src/error/errlog.h +++ b/modules/libcom/src/error/errlog.h @@ -11,6 +11,20 @@ #ifndef INC_errlog_H #define INC_errlog_H +/** \file errlog.h + * \brief Functions for interacting with the errlog task + * + * This file contains functions for passing error messages with varying severity, + * registering and un-registering listeners and modifying the log buffer size and + * max message size. + * + * Some of these functions are similar to the standard C library functions printf + * and vprintf. For details on the arguments and return codes it is useful to consult + * any book that describes the standard C library such as + * `The C Programming Language ANSI C Edition` by Kernighan and Ritchie. + * + */ + #include #include #include @@ -22,8 +36,15 @@ extern "C" { #endif +/** + * errlogListener function type. + * + * This is used when adding or removing log listeners in ::errlogAddListener + * and ::errlogRemoveListeners. + */ typedef void (*errlogListener)(void *pPrivate, const char *message); +/** errlog severity enums */ typedef enum { errlogInfo, errlogMinor, @@ -45,37 +66,171 @@ LIBCOM_API extern int errVerbose; LIBCOM_API extern const char * errlogSevEnumString[]; #endif -/* errMessage is a macro so it can get the file and line number */ +/** + * errMessage is a macro so it can get the file and line number. It prints the message, + * the status symbol and string values, and the name of the task which invoked errMessage. + * It also prints the name of the source file and the line number from which the call was issued. + * + * The status code used for the 1st argument is: + * - 0: Find latest vxWorks or Unix error (errno value). + * - -1: Don’t report status. + * - Other: Use this status code and lookup the string value + * + * \param S Status code + * \param PM The message to print + */ #define errMessage(S, PM) \ errPrintf(S, __FILE__, __LINE__, "%s", PM) -/* epicsPrintf and epicsVprintf are old names for errlog routines*/ + +/** epicsPrintf is an old name for errlog routines */ #define epicsPrintf errlogPrintf + +/** epicsVprintf is an old name for errlog routines */ #define epicsVprintf errlogVprintf +/** + * errlogPrintf is like the printf function provided by the standard C library, except + * that the output is sent to the errlog task. Unless configured not to, the output + * will appear on the console as well. + */ LIBCOM_API int errlogPrintf(const char *pformat, ...) EPICS_PRINTF_STYLE(1,2); + +/** + * errlogVprintf is like the vprintf function provided by the standard C library, except + * that the output is sent to the errlog task. Unless configured not to, the output + * will appear on the console as well. + */ LIBCOM_API int errlogVprintf(const char *pformat, va_list pvar); + +/** + * This function is like ::errlogPrintf except that it adds the severity to the beginning + * of the message in the form `sevr=` where value is one of the enumerated + * severities in ::errlogSevEnum. Also the message is suppressed if severity is less than + * the current severity to suppress. + * + * \param severity One of the severity enums from ::errlogSevEnum + * \param pFormat The message to log or print + * \return int Consult printf documentation in C standard library + */ LIBCOM_API int errlogSevPrintf(const errlogSevEnum severity, const char *pformat, ...) EPICS_PRINTF_STYLE(2,3); + +/** + * This function is like ::errlogVprintf except that it adds the severity to the beginning + * of the message in the form `sevr=` where value is one of the enumerated + * severities in ::errlogSevEnum. Also the message is suppressed if severity is less than + * the current severity to suppress. If epicsThreadIsOkToBlock is true, which is + * true during iocInit, errlogSevVprintf does NOT send output to the + * errlog task. + * + * \param severity One of the severity enums from ::errlogSevEnum + * \param pFormat The message to log or print + * \param pvar va_list + * \return int Consult printf documentation in C standard library + */ LIBCOM_API int errlogSevVprintf(const errlogSevEnum severity, const char *pformat, va_list pvar); + +/** + * Sends message to the errlog task. + * + * \param message The message to send + */ LIBCOM_API int errlogMessage(const char *message); +/** + * Gets the string value of severity. + * + * \param severity The severity from ::errlogSevEnum + * \return The string value + */ LIBCOM_API const char * errlogGetSevEnumString(errlogSevEnum severity); + +/** + * Sets the severity to log + * + * \param severity The severity from ::errlogSevEnum + */ LIBCOM_API void errlogSetSevToLog(errlogSevEnum severity); + +/** + * Gets the current severity to log + * + * \return ::errlogSevEnum + */ LIBCOM_API errlogSevEnum errlogGetSevToLog(void); +/** + * Any code can receive errlog message. This function will add a listener callback. + * + * \param listener Function pointer of type ::errlogListener + * \param pPrivate This will be passed as the first argument of listener() + */ LIBCOM_API void errlogAddListener(errlogListener listener, void *pPrivate); + +/** + * This function will remove a listener callback. + * + * \param listener Function pointer of type ::errlogListener + * \param pPrivate This will be passed as the first argument of listener() + */ LIBCOM_API int errlogRemoveListeners(errlogListener listener, void *pPrivate); +/** + * Normally the errlog system displays all messages on the console. + * During error message storms this function can be used to suppress console messages. + * A argument of 0 suppresses the messages, any other value lets messages go to the console. + * + * \param yesno (0=No, 1=Yes) + * \return 0 + */ LIBCOM_API int eltc(int yesno); + +/** + * Sets a new stream to write the messages to + * + * \param stream Pointer to file handle + * \return 0 + */ LIBCOM_API int errlogSetConsole(FILE *stream); +/** + * Can be used to initialize the error logging system with a larger buffer. The default buffer size is 1280 bytes. + * + * \param bufsize The desired buffer size + */ LIBCOM_API int errlogInit(int bufsize); + +/** + * errlogInit2 can be used to initialize the error logging system with a larger buffer and maximum message size. + * The default buffer size is 1280 bytes, and the default maximum message size is 256. + * + * \param bufsize The desired buffer size + * \param maxMsgSize The desired max message size + */ LIBCOM_API int errlogInit2(int bufsize, int maxMsgSize); + +/** Wakes up the errlog task and then waits until all messages are flushed from the queue. */ LIBCOM_API void errlogFlush(void); +/** + * Routine errPrintf is normally called as follows: + * `errPrintf(status, __FILE__, __LINE__,"",...); ` + * + * Where status is defined as: + * - 0: Find latest vxWorks or Unix error. + * - -1: Don’t report status. + * - Other: Use this status code and lookup the string value + * + * \param status See above + * \param __FILE__ As shown or NULL if the file name and line number should not be printed. + * \param __LINE__ As shown + * + * The remaining arguments are just like the arguments to the C printf routine. + * ::errVerbose determines if the filename and line number are shown. + */ LIBCOM_API void errPrintf(long status, const char *pFileName, int lineno, const char *pformat, ...) EPICS_PRINTF_STYLE(4,5); @@ -83,6 +238,13 @@ LIBCOM_API int errlogPrintfNoConsole(const char *pformat, ...) EPICS_PRINTF_STYLE(1,2); LIBCOM_API int errlogVprintfNoConsole(const char *pformat,va_list pvar); +/** + * Lookup the status code and return the string value in pBuf + * + * \param status The status code to lookup + * \param pBuf The char buffer to write the string value into + * \param bufLength The max size of pBuf + */ LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength); #ifdef __cplusplus From 5daf4fc932feda6468ca0141b354cc8b6c0e217c Mon Sep 17 00:00:00 2001 From: Matthew Pearson Date: Thu, 11 Mar 2021 10:09:05 -0500 Subject: [PATCH 47/52] epicsStdlib.h: add doxygen comments. --- modules/libcom/src/misc/epicsStdlib.h | 128 +++++++++++++++++++++++++- 1 file changed, 126 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/misc/epicsStdlib.h b/modules/libcom/src/misc/epicsStdlib.h index 219a1fb0a..e3cb69f91 100644 --- a/modules/libcom/src/misc/epicsStdlib.h +++ b/modules/libcom/src/misc/epicsStdlib.h @@ -13,6 +13,20 @@ #ifndef INC_epicsStdlib_H #define INC_epicsStdlib_H +/** + * \file epicsStdlib.h + * \brief Functions to convert strings to primative types + * + * These routines convert a string into an integer of the indicated type and + * number base, or into a floating point type. The units pointer argument may + * be NULL, but if not it will be left pointing to the first non-whitespace + * character following the numeric string, or to the terminating zero byte. + * + * The return value from these routines is a status code, zero meaning OK. + * For the macro functions beginning with `epicsScan` the return code is 0 + * or 1 (0=failure or 1=success, similar to the sscanf() function). + */ + #include #include @@ -25,57 +39,167 @@ extern "C" { #endif +/** Return code for `No digits to convert` */ #define S_stdlib_noConversion (M_stdlib | 1) /* No digits to convert */ +/** Return code for `Extraneous characters` */ #define S_stdlib_extraneous (M_stdlib | 2) /* Extraneous characters */ +/** Return code for `Too small to represent` */ #define S_stdlib_underflow (M_stdlib | 3) /* Too small to represent */ +/** Return code for `Too large to represent` */ #define S_stdlib_overflow (M_stdlib | 4) /* Too large to represent */ +/** Return code for `Number base not supported` */ #define S_stdlib_badBase (M_stdlib | 5) /* Number base not supported */ - -LIBCOM_API int +/** + * \brief Convert a string to a long type + * + * \param str Pointer to a constant character array + * \param to Pointer to the specified type (this will be set during the conversion) + * \param base The number base to use + * \param units Pointer to a char * (this will be set with the units string) + * \return Status code (0=OK, see macro definitions for possible errors) + */ +LIBCOM_API int epicsParseLong(const char *str, long *to, int base, char **units); + +/** + * \brief Convert a string to a unsigned long type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseULong(const char *str, unsigned long *to, int base, char **units); + +/** + * \brief Convert a string to a long long type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseLLong(const char *str, long long *to, int base, char **units); + +/** + * \brief Convert a string to a unsigned long long type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseULLong(const char *str, unsigned long long *to, int base, char **units); + +/** + * \brief Convert a string to a double type + * + * \param str Pointer to a constant character array + * \param to Pointer to the specified type (this will be set during the conversion) + * \param units Pointer to a char * (this will be set with the units string) + * \return Status code (0=OK, see macro definitions for possible errors) + */ LIBCOM_API int epicsParseDouble(const char *str, double *to, char **units); +/** + * \brief Convert a string to a float type + * \copydetails epicsParseDouble + */ LIBCOM_API int epicsParseFloat(const char *str, float *to, char **units); +/** + * \brief Convert a string to an epicsInt8 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseInt8(const char *str, epicsInt8 *to, int base, char **units); + +/** + * \brief Convert a string to an epicsUInt8 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseUInt8(const char *str, epicsUInt8 *to, int base, char **units); + +/** + * \brief Convert a string to an epicsInt16 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseInt16(const char *str, epicsInt16 *to, int base, char **units); + +/** + * \brief Convert a string to an epicsUInt16 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseUInt16(const char *str, epicsUInt16 *to, int base, char **units); +/** + * \brief Convert a string to an epicsInt32 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseInt32(const char *str, epicsInt32 *to, int base, char **units); + +/** + * \brief Convert a string to an epicsUInt32 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseUInt32(const char *str, epicsUInt32 *to, int base, char **units); +/** + * \brief Convert a string to an epicsInt64 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseInt64(const char *str, epicsInt64 *to, int base, char **units); + +/** + * \brief Convert a string to an epicsUInt64 type + * \copydetails epicsParseLong + */ LIBCOM_API int epicsParseUInt64(const char *str, epicsUInt64 *to, int base, char **units); +/** Macro utilizing ::epicsParseFloat to convert */ #define epicsParseFloat32(str, to, units) epicsParseFloat(str, to, units) +/** Macro utilizing ::epicsParseDouble to convert */ #define epicsParseFloat64(str, to, units) epicsParseDouble(str, to, units) /* These macros return 1 if successful, 0 on failure. * This is analagous to the return value from sscanf() */ + +/** + * Macro utilizing ::epicsParseLong to convert + * \return 0=failure, 1=success + */ #define epicsScanLong(str, to, base) (!epicsParseLong(str, to, base, NULL)) + +/** + * Macro utilizing ::epicsParseULong to convert + * \return 0=failure, 1=success + */ #define epicsScanULong(str, to, base) (!epicsParseULong(str, to, base, NULL)) + +/** + * Macro utilizing ::epicsParseLLong to convert + * \return 0=failure, 1=success + */ #define epicsScanLLong(str, to, base) (!epicsParseLLong(str, to, base, NULL)) + +/** + * Macro utilizing ::epicsParseULLong to convert + * \return 0=failure, 1=success + */ #define epicsScanULLong(str, to, base) (!epicsParseULLong(str, to, base, NULL)) + +/** + * Macro utilizing ::epicsParseFloat to convert + * \return 0=failure, 1=success + */ #define epicsScanFloat(str, to) (!epicsParseFloat(str, to, NULL)) + +/** + * Macro utilizing ::epicsParseDouble to convert + * \return 0=failure, 1=success + */ #define epicsScanDouble(str, to) (!epicsParseDouble(str, to, NULL)) #ifdef __cplusplus From 7eb7988e55e2bc572030984b03f12d864eb6017e Mon Sep 17 00:00:00 2001 From: Oksana Ivashkevych Date: Tue, 9 Mar 2021 14:56:51 -0500 Subject: [PATCH 48/52] Add usage to miscIocRegister.c and dbStaticIocRegister.c --- .../src/ioc/dbStatic/dbStaticIocRegister.c | 55 +++++++++++++------ .../database/src/ioc/misc/miscIocRegister.c | 24 ++++++-- 2 files changed, 56 insertions(+), 23 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c index 1a1960636..2f33ccff4 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c +++ b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c @@ -34,8 +34,10 @@ static void dbDumpPathCallFunc(const iocshArgBuf *args) static const iocshArg dbDumpRecordArg2 = { "interest level",iocshArgInt}; static const iocshArg * const dbDumpRecordArgs[] = {&argPdbbase, &argRecType, &dbDumpRecordArg2}; -static const iocshFuncDef dbDumpRecordFuncDef = - {"dbDumpRecord",3,dbDumpRecordArgs}; +static const iocshFuncDef dbDumpRecordFuncDef = {"dbDumpRecord",3,dbDumpRecordArgs, + "Dump information about the recordTypeName with 'interest level' details.\n" + "Example: dbDumpRecord ai 2\n" + "If last argument(s) are missing, dump all recordType information in the database.\n"}; static void dbDumpRecordCallFunc(const iocshArgBuf *args) { dbDumpRecord(*iocshPpdbbase,args[1].sval,args[2].ival); @@ -45,7 +47,10 @@ static void dbDumpRecordCallFunc(const iocshArgBuf *args) static const iocshArg dbDumpMenuArg1 = { "menuName",iocshArgString}; static const iocshArg * const dbDumpMenuArgs[] = { &argPdbbase, &dbDumpMenuArg1}; -static const iocshFuncDef dbDumpMenuFuncDef = {"dbDumpMenu",2,dbDumpMenuArgs}; +static const iocshFuncDef dbDumpMenuFuncDef = {"dbDumpMenu",2,dbDumpMenuArgs, + "Dump information about the available menuNames and choices defined withing each menuName.\n" + "Example: dbDumpMenu pdbbase menuAlarmStat \n" + "If last argument(s) are missing, dump all menuNames information in the database.\n"}; static void dbDumpMenuCallFunc(const iocshArgBuf *args) { dbDumpMenu(*iocshPpdbbase,args[1].sval); @@ -54,8 +59,10 @@ static void dbDumpMenuCallFunc(const iocshArgBuf *args) /* dbDumpRecordType */ static const iocshArg * const dbDumpRecordTypeArgs[] = {&argPdbbase, &argRecType}; -static const iocshFuncDef dbDumpRecordTypeFuncDef = - {"dbDumpRecordType",2,dbDumpRecordTypeArgs}; +static const iocshFuncDef dbDumpRecordTypeFuncDef = {"dbDumpRecordType",2,dbDumpRecordTypeArgs, + "Dump information about available fields in the recortTypeName sorted by index and name.\n" + "Example: dbDumpRecordType pdbbase calcout\n" + "If last argument(s) are missing, dump fields information for all records in the database.\n"}; static void dbDumpRecordTypeCallFunc(const iocshArgBuf *args) { dbDumpRecordType(*iocshPpdbbase,args[1].sval); @@ -65,7 +72,11 @@ static void dbDumpRecordTypeCallFunc(const iocshArgBuf *args) static const iocshArg dbDumpFieldArg2 = { "fieldName",iocshArgString}; static const iocshArg * const dbDumpFieldArgs[] = {&argPdbbase, &argRecType,&dbDumpFieldArg2}; -static const iocshFuncDef dbDumpFieldFuncDef = {"dbDumpField",3,dbDumpFieldArgs}; +static const iocshFuncDef dbDumpFieldFuncDef = {"dbDumpField",3,dbDumpFieldArgs, + "Dump information about the fieldName in the recordTypeName.\n" + "Example: dbDumpField pdbbase calcout A\n" + "If last argument(s) are missing, dump information\n" + "about all fieldName in all recordTypeName in the database.\n"}; static void dbDumpFieldCallFunc(const iocshArgBuf *args) { dbDumpField(*iocshPpdbbase,args[1].sval,args[2].sval); @@ -74,7 +85,11 @@ static void dbDumpFieldCallFunc(const iocshArgBuf *args) /* dbDumpDevice */ static const iocshArg * const dbDumpDeviceArgs[] = { &argPdbbase, &argRecType}; -static const iocshFuncDef dbDumpDeviceFuncDef = {"dbDumpDevice",2,dbDumpDeviceArgs}; +static const iocshFuncDef dbDumpDeviceFuncDef = {"dbDumpDevice",2,dbDumpDeviceArgs, + "Dump device support information for the recordTypeName.\n" + "Example: dbDumpDevice pdbbase ai\n" + "If last argument(s) are missing, dump device support\n" + "information for all records in the database.\n"}; static void dbDumpDeviceCallFunc(const iocshArgBuf *args) { dbDumpDevice(*iocshPpdbbase,args[1].sval); @@ -82,7 +97,9 @@ static void dbDumpDeviceCallFunc(const iocshArgBuf *args) /* dbDumpDriver */ static const iocshArg * const dbDumpDriverArgs[] = { &argPdbbase}; -static const iocshFuncDef dbDumpDriverFuncDef = {"dbDumpDriver",1,dbDumpDriverArgs}; +static const iocshFuncDef dbDumpDriverFuncDef = {"dbDumpDriver",1,dbDumpDriverArgs, + "Dump device support information.\n" + "Example: dbDumpDriver pdbbase\n"}; static void dbDumpDriverCallFunc(const iocshArgBuf *args) { dbDumpDriver(*iocshPpdbbase); @@ -98,7 +115,10 @@ static void dbDumpLinkCallFunc(const iocshArgBuf *args) /* dbDumpRegistrar */ static const iocshArg * const dbDumpRegistrarArgs[] = { &argPdbbase}; -static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs}; +static const iocshFuncDef dbDumpRegistrarFuncDef = {"dbDumpRegistrar",1,dbDumpRegistrarArgs, + "Dump list of registered functions including ones for subroutine records,\n" + "and ones that can be invoked from iocsh.\n" + "Example: dbDumpRegistrar pdbbase\n"}; static void dbDumpRegistrarCallFunc(const iocshArgBuf *args) { dbDumpRegistrar(*iocshPpdbbase); @@ -106,7 +126,9 @@ static void dbDumpRegistrarCallFunc(const iocshArgBuf *args) /* dbDumpFunction */ static const iocshArg * const dbDumpFunctionArgs[] = { &argPdbbase}; -static const iocshFuncDef dbDumpFunctionFuncDef = {"dbDumpFunction",1,dbDumpFunctionArgs}; +static const iocshFuncDef dbDumpFunctionFuncDef = {"dbDumpFunction",1,dbDumpFunctionArgs, + "Dump list of registered subroutine functions.\n" + "Example: dbDumpFunction pddbase\n"}; static void dbDumpFunctionCallFunc(const iocshArgBuf *args) { dbDumpFunction(*iocshPpdbbase); @@ -114,7 +136,9 @@ static void dbDumpFunctionCallFunc(const iocshArgBuf *args) /* dbDumpVariable */ static const iocshArg * const dbDumpVariableArgs[] = { &argPdbbase}; -static const iocshFuncDef dbDumpVariableFuncDef = {"dbDumpVariable",1,dbDumpVariableArgs}; +static const iocshFuncDef dbDumpVariableFuncDef = {"dbDumpVariable",1,dbDumpVariableArgs, + "Dump list of variables used in the database.\n" + "Example: dbDumpVariable pddbase\n"}; static void dbDumpVariableCallFunc(const iocshArgBuf *args) { dbDumpVariable(*iocshPpdbbase); @@ -124,8 +148,7 @@ static void dbDumpVariableCallFunc(const iocshArgBuf *args) static const iocshArg dbDumpBreaktableArg1 = { "tableName",iocshArgString}; static const iocshArg * const dbDumpBreaktableArgs[] = {&argPdbbase,&dbDumpBreaktableArg1}; -static const iocshFuncDef dbDumpBreaktableFuncDef = - {"dbDumpBreaktable",2,dbDumpBreaktableArgs}; +static const iocshFuncDef dbDumpBreaktableFuncDef = {"dbDumpBreaktable",2,dbDumpBreaktableArgs}; static void dbDumpBreaktableCallFunc(const iocshArgBuf *args) { dbDumpBreaktable(*iocshPpdbbase,args[1].sval); @@ -145,8 +168,7 @@ static void dbPvdDumpCallFunc(const iocshArgBuf *args) static const iocshArg dbPvdTableSizeArg0 = { "size",iocshArgInt}; static const iocshArg * const dbPvdTableSizeArgs[1] = {&dbPvdTableSizeArg0}; -static const iocshFuncDef dbPvdTableSizeFuncDef = - {"dbPvdTableSize",1,dbPvdTableSizeArgs}; +static const iocshFuncDef dbPvdTableSizeFuncDef = {"dbPvdTableSize",1,dbPvdTableSizeArgs}; static void dbPvdTableSizeCallFunc(const iocshArgBuf *args) { dbPvdTableSize(args[0].ival); @@ -154,8 +176,7 @@ static void dbPvdTableSizeCallFunc(const iocshArgBuf *args) /* dbReportDeviceConfig */ static const iocshArg * const dbReportDeviceConfigArgs[] = {&argPdbbase}; -static const iocshFuncDef dbReportDeviceConfigFuncDef = { - "dbReportDeviceConfig",1,dbReportDeviceConfigArgs}; +static const iocshFuncDef dbReportDeviceConfigFuncDef = {"dbReportDeviceConfig",1,dbReportDeviceConfigArgs}; static void dbReportDeviceConfigCallFunc(const iocshArgBuf *args) { dbReportDeviceConfig(*iocshPpdbbase,stdout); diff --git a/modules/database/src/ioc/misc/miscIocRegister.c b/modules/database/src/ioc/misc/miscIocRegister.c index f88db7586..8c1180402 100644 --- a/modules/database/src/ioc/misc/miscIocRegister.c +++ b/modules/database/src/ioc/misc/miscIocRegister.c @@ -20,35 +20,43 @@ #include "miscIocRegister.h" /* iocInit */ -static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL}; +static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL, + "Initializes the various epics components and starts the IOC running.\n"}; static void iocInitCallFunc(const iocshArgBuf *args) { iocshSetError(iocInit()); } /* iocBuild */ -static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL}; +static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL, + "First step of the IOC initialization, puts the IOC into a ready-to-run (quiescent) state.\n" + "Needs iocRun() to make the IOC live.\n"}; static void iocBuildCallFunc(const iocshArgBuf *args) { iocshSetError(iocBuild()); } /* iocRun */ -static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL}; +static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL, + "Bring the IOC out of its initial quiescent state to the running state.\n" + "See more: iocBuild, iocPause"}; static void iocRunCallFunc(const iocshArgBuf *args) { iocshSetError(iocRun()); } /* iocPause */ -static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL}; +static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL, + "Brings a running IOC to a quiescent state with all record processing frozen.\n" + "See more: iocBuild, iocRub, iocInit"}; static void iocPauseCallFunc(const iocshArgBuf *args) { iocshSetError(iocPause()); } /* coreRelease */ -static const iocshFuncDef coreReleaseFuncDef = {"coreRelease",0,NULL}; +static const iocshFuncDef coreReleaseFuncDef = {"coreRelease",0,NULL, + "Print release information for iocCore.\n"}; static void coreReleaseCallFunc(const iocshArgBuf *args) { coreRelease (); @@ -75,7 +83,11 @@ void miscIocRegister(void) #ifndef SYSTEM_UNAVAILABLE static const iocshArg systemArg0 = { "command string",iocshArgString}; static const iocshArg * const systemArgs[] = {&systemArg0}; -static const iocshFuncDef systemFuncDef = {"system",1,systemArgs}; +static const iocshFuncDef systemFuncDef = {"system",1,systemArgs, + "Send command string to the system command interpreter for execution.\n" + "Not available on all OSs.\n" + "To enable this command, add registrar(iocshSystemCommand) to an application dbd file,\n" + "or include system.dbd\n"}; static void systemCallFunc(const iocshArgBuf *args) { iocshSetError(system(args[0].sval)); From 746d21c71de52e0a2a5c09cfaf9f4ee53ced09fc Mon Sep 17 00:00:00 2001 From: Ziga Oven Date: Mon, 8 Mar 2021 12:46:34 +0100 Subject: [PATCH 49/52] Add usage messages --- modules/database/src/ioc/as/asIocRegister.c | 4 +- .../database/src/ioc/rsrv/rsrvIocRegister.c | 7 +- modules/libcom/src/iocsh/iocsh.cpp | 21 +++- modules/libcom/src/iocsh/libComRegister.c | 100 +++++++++++++----- modules/libcom/src/osi/osiClockTime.c | 16 ++- modules/libcom/src/osi/osiNTPTime.c | 11 +- 6 files changed, 122 insertions(+), 37 deletions(-) diff --git a/modules/database/src/ioc/as/asIocRegister.c b/modules/database/src/ioc/as/asIocRegister.c index 200da3e00..8efb4c9eb 100644 --- a/modules/database/src/ioc/as/asIocRegister.c +++ b/modules/database/src/ioc/as/asIocRegister.c @@ -120,7 +120,9 @@ static void ascarCallFunc(const iocshArgBuf *args) } /* asDumpHash */ -static const iocshFuncDef asDumpHashFuncDef = {"asDumpHash",0,0}; +static const iocshFuncDef asDumpHashFuncDef = {"asDumpHash",0,0, + "Show the contents of the hash table used " + "to locate UAGs and HAGs.\n"}; static void asDumpHashCallFunc(const iocshArgBuf *args) { asDumpHash(); diff --git a/modules/database/src/ioc/rsrv/rsrvIocRegister.c b/modules/database/src/ioc/rsrv/rsrvIocRegister.c index 05b2e7d6b..533d67b52 100644 --- a/modules/database/src/ioc/rsrv/rsrvIocRegister.c +++ b/modules/database/src/ioc/rsrv/rsrvIocRegister.c @@ -20,7 +20,12 @@ /* casr */ static const iocshArg casrArg0 = { "level",iocshArgInt}; static const iocshArg * const casrArgs[1] = {&casrArg0}; -static const iocshFuncDef casrFuncDef = {"casr",1,casrArgs}; +static const iocshFuncDef casrFuncDef = {"casr",1,casrArgs, + "Channel Access Server Report with following levels:\n" + " 0 - server’s protocol version level and summary for each attached client\n" + " 1 - extends report with information about connected clients and beacons\n" + " 2 - extends report with specific channel names and UDP search requests\n" + " 3+ - expert\n"}; static void casrCallFunc(const iocshArgBuf *args) { casr(args[0].ival); diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index b626e1530..474436c72 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -163,7 +163,12 @@ const iocshCmdDef * epicsStdCall iocshFindCommand(const char *name) static const iocshArg varCmdArg0 = { "[variable", iocshArgString}; static const iocshArg varCmdArg1 = { "[value]]", iocshArgString}; static const iocshArg *varCmdArgs[2] = {&varCmdArg0, &varCmdArg1}; -static const iocshFuncDef varFuncDef = {"var", 2, varCmdArgs}; +static const iocshFuncDef varFuncDef = {"var", 2, varCmdArgs, + "Print all, print single variable or set value to single variable\n" + " (default) - print all variables and their values" + " defined in database definitions files\n" + " variable - if only parameter print value for this variable\n" + " value - set the value to variable\n"}; void epicsStdCall iocshRegisterVariable (const iocshVarDef *piocshVarDef) { @@ -1139,7 +1144,10 @@ static void varCallFunc(const iocshArgBuf *args) /* iocshCmd */ static const iocshArg iocshCmdArg0 = { "command",iocshArgString}; static const iocshArg *iocshCmdArgs[1] = {&iocshCmdArg0}; -static const iocshFuncDef iocshCmdFuncDef = {"iocshCmd",1,iocshCmdArgs}; +static const iocshFuncDef iocshCmdFuncDef = {"iocshCmd",1,iocshCmdArgs, + "Takes a single IOC shell command and executes it\n" + " * This function is most useful to execute a single IOC shell command\n" + " from vxWorks or RTEMS startup script (or command line)\n"}; static void iocshCmdCallFunc(const iocshArgBuf *args) { iocshCmd(args[0].sval); @@ -1149,7 +1157,9 @@ static void iocshCmdCallFunc(const iocshArgBuf *args) static const iocshArg iocshLoadArg0 = { "pathname",iocshArgString}; static const iocshArg iocshLoadArg1 = { "macros", iocshArgString}; static const iocshArg *iocshLoadArgs[2] = {&iocshLoadArg0, &iocshLoadArg1}; -static const iocshFuncDef iocshLoadFuncDef = {"iocshLoad",2,iocshLoadArgs}; +static const iocshFuncDef iocshLoadFuncDef = {"iocshLoad",2,iocshLoadArgs, + "Execute IOC shell commands provided in file from first parameter\n" + " * (optional) replace macros within the file with provided values\n"}; static void iocshLoadCallFunc(const iocshArgBuf *args) { iocshLoad(args[0].sval, args[1].sval); @@ -1159,7 +1169,10 @@ static void iocshLoadCallFunc(const iocshArgBuf *args) static const iocshArg iocshRunArg0 = { "command",iocshArgString}; static const iocshArg iocshRunArg1 = { "macros", iocshArgString}; static const iocshArg *iocshRunArgs[2] = {&iocshRunArg0, &iocshRunArg1}; -static const iocshFuncDef iocshRunFuncDef = {"iocshRun",2,iocshRunArgs}; +static const iocshFuncDef iocshRunFuncDef = {"iocshRun",2,iocshRunArgs, + "Takes a single IOC shell command, replaces macros and executes it\n" + " * This function is most useful to execute a single IOC shell command\n" + " from vxWorks or RTEMS startup script (or command line)\n"}; static void iocshRunCallFunc(const iocshArgBuf *args) { iocshRun(args[0].sval, args[1].sval); diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index 12ec7a9fe..1846bcee3 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -46,7 +46,9 @@ void date(const char *format) static const iocshArg dateArg0 = { "format",iocshArgString}; static const iocshArg * const dateArgs[] = {&dateArg0}; -static const iocshFuncDef dateFuncDef = {"date", 1, dateArgs}; +static const iocshFuncDef dateFuncDef = {"date", 1, dateArgs, + "Print current date and time\n" + " (default) - '%Y/%m/%d %H:%M:%S.%06f'\n"}; static void dateCallFunc (const iocshArgBuf *args) { date(args[0].sval); @@ -64,7 +66,8 @@ IOCSH_STATIC_FUNC void echo(char* str) static const iocshArg echoArg0 = { "string",iocshArgString}; static const iocshArg * const echoArgs[1] = {&echoArg0}; -static const iocshFuncDef echoFuncDef = {"echo",1,echoArgs}; +static const iocshFuncDef echoFuncDef = {"echo",1,echoArgs, + "Print string after expanding macros and environment variables\n"}; static void echoCallFunc(const iocshArgBuf *args) { echo(args[0].sval); @@ -73,7 +76,8 @@ static void echoCallFunc(const iocshArgBuf *args) /* chdir */ static const iocshArg chdirArg0 = { "directory name",iocshArgString}; static const iocshArg * const chdirArgs[1] = {&chdirArg0}; -static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs}; +static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs, + "Change directory to new directory provided as parameter\n"}; static void chdirCallFunc(const iocshArgBuf *args) { if (args[0].sval == NULL || @@ -83,7 +87,8 @@ static void chdirCallFunc(const iocshArgBuf *args) } /* print current working directory */ -static const iocshFuncDef pwdFuncDef = { "pwd", 0, 0 }; +static const iocshFuncDef pwdFuncDef = {"pwd", 0, 0, + "Print name of current/working directory\n"}; static void pwdCallFunc (const iocshArgBuf *args) { char buf[256]; @@ -97,7 +102,8 @@ static void pwdCallFunc (const iocshArgBuf *args) static const iocshArg epicsEnvSetArg0 = { "name",iocshArgString}; static const iocshArg epicsEnvSetArg1 = { "value",iocshArgString}; static const iocshArg * const epicsEnvSetArgs[2] = {&epicsEnvSetArg0,&epicsEnvSetArg1}; -static const iocshFuncDef epicsEnvSetFuncDef = {"epicsEnvSet",2,epicsEnvSetArgs}; +static const iocshFuncDef epicsEnvSetFuncDef = {"epicsEnvSet",2,epicsEnvSetArgs, + "Set environment variable name to value\n"}; static void epicsEnvSetCallFunc(const iocshArgBuf *args) { char *name = args[0].sval; @@ -117,7 +123,8 @@ static void epicsEnvSetCallFunc(const iocshArgBuf *args) /* epicsEnvUnset */ static const iocshArg epicsEnvUnsetArg0 = { "name",iocshArgString}; static const iocshArg * const epicsEnvUnsetArgs[1] = {&epicsEnvUnsetArg0}; -static const iocshFuncDef epicsEnvUnsetFuncDef = {"epicsEnvUnset",1,epicsEnvUnsetArgs}; +static const iocshFuncDef epicsEnvUnsetFuncDef = {"epicsEnvUnset",1,epicsEnvUnsetArgs, + "Remove variable name from the environment\n"}; static void epicsEnvUnsetCallFunc(const iocshArgBuf *args) { char *name = args[0].sval; @@ -135,14 +142,16 @@ IOCSH_STATIC_FUNC void epicsParamShow() epicsPrtEnvParams (); } -static const iocshFuncDef epicsParamShowFuncDef = {"epicsParamShow",0,NULL}; +static const iocshFuncDef epicsParamShowFuncDef = {"epicsParamShow",0,NULL, + "Show the environment variable parameters used by iocCore\n"}; static void epicsParamShowCallFunc(const iocshArgBuf *args) { epicsParamShow (); } /* epicsPrtEnvParams */ -static const iocshFuncDef epicsPrtEnvParamsFuncDef = {"epicsPrtEnvParams",0,0}; +static const iocshFuncDef epicsPrtEnvParamsFuncDef = {"epicsPrtEnvParams",0,0, + "Show the environment variable parameters used by iocCore\n"}; static void epicsPrtEnvParamsCallFunc(const iocshArgBuf *args) { epicsPrtEnvParams (); @@ -151,21 +160,29 @@ static void epicsPrtEnvParamsCallFunc(const iocshArgBuf *args) /* epicsEnvShow */ static const iocshArg epicsEnvShowArg0 = { "[name]",iocshArgString}; static const iocshArg * const epicsEnvShowArgs[1] = {&epicsEnvShowArg0}; -static const iocshFuncDef epicsEnvShowFuncDef = {"epicsEnvShow",1,epicsEnvShowArgs}; +static const iocshFuncDef epicsEnvShowFuncDef = {"epicsEnvShow",1,epicsEnvShowArgs, + "Show environment variables on your system\n" + " (default) - show all environment variables\n" + " name - show value of specific environment variable\n"}; static void epicsEnvShowCallFunc(const iocshArgBuf *args) { epicsEnvShow (args[0].sval); } /* registryDump */ -static const iocshFuncDef registryDumpFuncDef = {"registryDump",0,NULL}; +static const iocshFuncDef registryDumpFuncDef = {"registryDump",0,NULL, + "Dump a hash table of EPICS registry\n"}; static void registryDumpCallFunc(const iocshArgBuf *args) { registryDump (); } /* iocLogInit */ -static const iocshFuncDef iocLogInitFuncDef = {"iocLogInit",0}; +static const iocshFuncDef iocLogInitFuncDef = {"iocLogInit",0,0, + "Initialize IOC logging\n" + " * EPICS environment variable 'EPICS_IOC_LOG_INET' has to be defined\n" + " * Logging controled via 'iocLogDisable' variable\n" + " see 'setIocLogDisable' command\n"}; static void iocLogInitCallFunc(const iocshArgBuf *args) { iocLogInit (); @@ -179,7 +196,10 @@ IOCSH_STATIC_FUNC void setIocLogDisable(int val) static const iocshArg iocLogDisableArg0 = {"(0,1)=>(false,true)",iocshArgInt}; static const iocshArg * const iocLogDisableArgs[1] = {&iocLogDisableArg0}; -static const iocshFuncDef iocLogDisableFuncDef = {"setIocLogDisable",1,iocLogDisableArgs}; +static const iocshFuncDef iocLogDisableFuncDef = {"setIocLogDisable",1,iocLogDisableArgs, + "Controls the 'iocLogDisable' variable\n" + " 0 - enable logging\n" + " 1 - disable logging\n"}; static void iocLogDisableCallFunc(const iocshArgBuf *args) { setIocLogDisable(args[0].ival); @@ -188,7 +208,8 @@ static void iocLogDisableCallFunc(const iocshArgBuf *args) /* iocLogShow */ static const iocshArg iocLogShowArg0 = {"level",iocshArgInt}; static const iocshArg * const iocLogShowArgs[1] = {&iocLogShowArg0}; -static const iocshFuncDef iocLogShowFuncDef = {"iocLogShow",1,iocLogShowArgs}; +static const iocshFuncDef iocLogShowFuncDef = {"iocLogShow",1,iocLogShowArgs, + "Determine if a IOC Log Prefix has been set\n"}; static void iocLogShowCallFunc(const iocshArgBuf *args) { iocLogShow (args[0].ival); @@ -197,17 +218,22 @@ static void iocLogShowCallFunc(const iocshArgBuf *args) /* eltc */ static const iocshArg eltcArg0 = {"(0,1)=>(false,true)",iocshArgInt}; static const iocshArg * const eltcArgs[1] = {&eltcArg0}; -static const iocshFuncDef eltcFuncDef = {"eltc",1,eltcArgs}; +static const iocshFuncDef eltcFuncDef = {"eltc",1,eltcArgs, + "Control display of error log messages on console\n" + " 0 - no\n" + " 1 - yes (default)\n"}; static void eltcCallFunc(const iocshArgBuf *args) { eltc(args[0].ival); } /* errlogInit */ -static const iocshArg errlogInitArg0 = { "bufsize",iocshArgInt}; +static const iocshArg errlogInitArg0 = { "bufSize",iocshArgInt}; static const iocshArg * const errlogInitArgs[1] = {&errlogInitArg0}; static const iocshFuncDef errlogInitFuncDef = - {"errlogInit",1,errlogInitArgs}; + {"errlogInit",1,errlogInitArgs, + "Initialize error log client buffer size\n" + " bufSize - size of circular buffer (default = 1280 bytes)\n"}; static void errlogInitCallFunc(const iocshArgBuf *args) { errlogInit(args[0].ival); @@ -219,7 +245,10 @@ static const iocshArg errlogInit2Arg1 = { "maxMsgSize",iocshArgInt}; static const iocshArg * const errlogInit2Args[] = {&errlogInit2Arg0, &errlogInit2Arg1}; static const iocshFuncDef errlogInit2FuncDef = - {"errlogInit2", 2, errlogInit2Args}; + {"errlogInit2", 2, errlogInit2Args, + "Initialize error log client buffer size and maximum message size\n" + " bufSize - size of circular buffer (default = 1280 bytes)\n" + " maxMsgSize - maximum size of error message (default = 256 bytes)\n"}; static void errlogInit2CallFunc(const iocshArgBuf *args) { errlogInit2(args[0].ival, args[1].ival); @@ -233,7 +262,8 @@ IOCSH_STATIC_FUNC void errlog(const char *message) static const iocshArg errlogArg0 = { "message",iocshArgString}; static const iocshArg * const errlogArgs[1] = {&errlogArg0}; -static const iocshFuncDef errlogFuncDef = {"errlog",1,errlogArgs}; +static const iocshFuncDef errlogFuncDef = {"errlog",1,errlogArgs, + "Send message to errlog\n"}; static void errlogCallFunc(const iocshArgBuf *args) { errlog(args[0].sval); @@ -243,7 +273,8 @@ static void errlogCallFunc(const iocshArgBuf *args) /* iocLogPrefix */ static const iocshArg iocLogPrefixArg0 = { "prefix",iocshArgString}; static const iocshArg * const iocLogPrefixArgs[1] = {&iocLogPrefixArg0}; -static const iocshFuncDef iocLogPrefixFuncDef = {"iocLogPrefix",1,iocLogPrefixArgs}; +static const iocshFuncDef iocLogPrefixFuncDef = {"iocLogPrefix",1,iocLogPrefixArgs, + "Create the prefix for all messages going into IOC log\n"}; static void iocLogPrefixCallFunc(const iocshArgBuf *args) { iocLogPrefix(args[0].sval); @@ -253,7 +284,8 @@ static void iocLogPrefixCallFunc(const iocshArgBuf *args) static const iocshArg epicsThreadShowAllArg0 = { "level",iocshArgInt}; static const iocshArg * const epicsThreadShowAllArgs[1] = {&epicsThreadShowAllArg0}; static const iocshFuncDef epicsThreadShowAllFuncDef = - {"epicsThreadShowAll",1,epicsThreadShowAllArgs}; + {"epicsThreadShowAll",1,epicsThreadShowAllArgs, + "Display info about all threads\n"}; static void epicsThreadShowAllCallFunc(const iocshArgBuf *args) { epicsThreadShowAll(args[0].ival); @@ -262,7 +294,8 @@ static void epicsThreadShowAllCallFunc(const iocshArgBuf *args) /* epicsThreadShow */ static const iocshArg threadArg0 = { "[-level] [thread ...]", iocshArgArgv}; static const iocshArg * const threadArgs[1] = { &threadArg0 }; -static const iocshFuncDef threadFuncDef = {"epicsThreadShow",1,threadArgs}; +static const iocshFuncDef threadFuncDef = {"epicsThreadShow",1,threadArgs, + "Display info about the specified thread\n"}; static void threadCallFunc(const iocshArgBuf *args) { int i = 1; @@ -308,7 +341,8 @@ static void threadCallFunc(const iocshArgBuf *args) static const iocshArg taskwdShowArg0 = { "level",iocshArgInt}; static const iocshArg * const taskwdShowArgs[1] = {&taskwdShowArg0}; static const iocshFuncDef taskwdShowFuncDef = - {"taskwdShow",1,taskwdShowArgs}; + {"taskwdShow",1,taskwdShowArgs, + "Show number of tasks and monitors registered\n"}; static void taskwdShowCallFunc(const iocshArgBuf *args) { taskwdShow(args[0].ival); @@ -320,7 +354,10 @@ static const iocshArg epicsMutexShowAllArg1 = { "level",iocshArgInt}; static const iocshArg * const epicsMutexShowAllArgs[2] = {&epicsMutexShowAllArg0,&epicsMutexShowAllArg1}; static const iocshFuncDef epicsMutexShowAllFuncDef = - {"epicsMutexShowAll",2,epicsMutexShowAllArgs}; + {"epicsMutexShowAll",2,epicsMutexShowAllArgs, + "Display information about all epicsMutex semaphores\n" + " onlyLocked - non-zero to show only locked semaphores\n" + " level - desired information level to report\n"}; static void epicsMutexShowAllCallFunc(const iocshArgBuf *args) { epicsMutexShowAll(args[0].ival,args[1].ival); @@ -330,7 +367,8 @@ static void epicsMutexShowAllCallFunc(const iocshArgBuf *args) static const iocshArg epicsThreadSleepArg0 = { "seconds",iocshArgDouble}; static const iocshArg * const epicsThreadSleepArgs[1] = {&epicsThreadSleepArg0}; static const iocshFuncDef epicsThreadSleepFuncDef = - {"epicsThreadSleep",1,epicsThreadSleepArgs}; + {"epicsThreadSleep",1,epicsThreadSleepArgs, + "Pause execution of IOC shell for seconds\n"}; static void epicsThreadSleepCallFunc(const iocshArgBuf *args) { epicsThreadSleep(args[0].dval); @@ -339,7 +377,10 @@ static void epicsThreadSleepCallFunc(const iocshArgBuf *args) /* epicsThreadResume */ static const iocshArg epicsThreadResumeArg0 = { "[thread ...]", iocshArgArgv}; static const iocshArg * const epicsThreadResumeArgs[1] = { &epicsThreadResumeArg0 }; -static const iocshFuncDef epicsThreadResumeFuncDef = {"epicsThreadResume",1,epicsThreadResumeArgs}; +static const iocshFuncDef epicsThreadResumeFuncDef = {"epicsThreadResume",1,epicsThreadResumeArgs, + "Resume a suspended thread.\n" + "Only do this if you know that it is safe to " + "resume a suspended thread\n"}; static void epicsThreadResumeCallFunc(const iocshArgBuf *args) { int i; @@ -381,14 +422,19 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args) /* generalTimeReport */ static const iocshArg generalTimeReportArg0 = { "interest_level", iocshArgArgv}; static const iocshArg * const generalTimeReportArgs[1] = { &generalTimeReportArg0 }; -static const iocshFuncDef generalTimeReportFuncDef = {"generalTimeReport",1,generalTimeReportArgs}; +static const iocshFuncDef generalTimeReportFuncDef = {"generalTimeReport",1,generalTimeReportArgs, + "Display time providers and their priority levels" + " for current and event times\n"}; static void generalTimeReportCallFunc(const iocshArgBuf *args) { generalTimeReport(args[0].ival); } /* installLastResortEventProvider */ -static const iocshFuncDef installLastResortEventProviderFuncDef = {"installLastResortEventProvider", 0, NULL}; +static const iocshFuncDef installLastResortEventProviderFuncDef = {"installLastResortEventProvider", 0, NULL, + "Installs the optional Last Resort event provider" + " at priority 999,\nwhich returns the current time" + " for every event number\n"}; static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) { installLastResortEventProvider(); diff --git a/modules/libcom/src/osi/osiClockTime.c b/modules/libcom/src/osi/osiClockTime.c index 5368898d7..8b9dfd77b 100644 --- a/modules/libcom/src/osi/osiClockTime.c +++ b/modules/libcom/src/osi/osiClockTime.c @@ -58,14 +58,26 @@ static void ClockTimeSync(void *dummy); /* ClockTime_Report iocsh command */ static const iocshArg ReportArg0 = { "interest_level", iocshArgArgv}; static const iocshArg * const ReportArgs[1] = { &ReportArg0 }; -static const iocshFuncDef ReportFuncDef = {"ClockTime_Report", 1, ReportArgs}; +static const iocshFuncDef ReportFuncDef = {"ClockTime_Report", 1, ReportArgs, + "Reports clock synchronization status:\n" + " - On vxWorks and RTEMS:\n" + " * synchronization state\n" + " * last synchronization time with provider\n" + " * synchronization interval\n" + " - On workstation (WIN,*NIX):\n" + " * minimal report\n"}; static void ReportCallFunc(const iocshArgBuf *args) { ClockTime_Report(args[0].ival); } /* ClockTime_Shutdown iocsh command */ -static const iocshFuncDef ShutdownFuncDef = {"ClockTime_Shutdown", 0, NULL}; +static const iocshFuncDef ShutdownFuncDef = {"ClockTime_Shutdown", 0, NULL, + "Stops the OS synchronization thread\n" + " - On vxWorks and RTEMS:\n" + " * OS clock will free run\n" + " - On workstation (WIN,*NIX):\n" + " * no change\n"}; static void ShutdownCallFunc(const iocshArgBuf *args) { ClockTime_Shutdown(NULL); diff --git a/modules/libcom/src/osi/osiNTPTime.c b/modules/libcom/src/osi/osiNTPTime.c index fa5217faf..bd9821e4c 100644 --- a/modules/libcom/src/osi/osiNTPTime.c +++ b/modules/libcom/src/osi/osiNTPTime.c @@ -64,14 +64,21 @@ static void NTPTimeSync(void *dummy); /* NTPTime_Report iocsh command */ static const iocshArg ReportArg0 = { "interest_level", iocshArgArgv}; static const iocshArg * const ReportArgs[1] = { &ReportArg0 }; -static const iocshFuncDef ReportFuncDef = {"NTPTime_Report", 1, ReportArgs}; +static const iocshFuncDef ReportFuncDef = {"NTPTime_Report", 1, ReportArgs, + "Display time provider synchronization state\n" + " interest_level - with level 1 it also shows:\n" + " * synchronization interval\n" + " * time when last synchronized\n" + " * nominal and measured system tick rates\n" + " * server address (vxWorks only)\n"}; static void ReportCallFunc(const iocshArgBuf *args) { NTPTime_Report(args[0].ival); } /* NTPTime_Shutdown iocsh command */ -static const iocshFuncDef ShutdownFuncDef = {"NTPTime_Shutdown", 0, NULL}; +static const iocshFuncDef ShutdownFuncDef = {"NTPTime_Shutdown", 0, NULL, + "Shuts down NTP time synchronization thread\n"}; static void ShutdownCallFunc(const iocshArgBuf *args) { NTPTime_Shutdown(NULL); From 7e01cdacacb819f35a6d2d95c9b47e5e496cb9ee Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 18 Mar 2021 12:24:42 -0700 Subject: [PATCH 50/52] ci: GHA always upload tapfiles --- .github/workflows/ci-scripts-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index f14f5ef66..07eb8b01e 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -150,6 +150,7 @@ jobs: - name: Run main module tests run: python .ci/cue.py test - name: Upload tapfiles Artifact + if: ${{ always() }} uses: actions/upload-artifact@v2 with: name: tapfiles ${{ matrix.name }} From 54e9d3f5d1256edf8e6eca06191f51ba0aaf4cf2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 17 Mar 2021 09:47:35 -0700 Subject: [PATCH 51/52] ci: github actions add mingw --- .github/workflows/ci-scripts-build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 07eb8b01e..5ad79311e 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -124,6 +124,11 @@ jobs: configuration: static name: "Win2019 MSC-19, static" + - os: windows-2019 + cmp: gcc + configuration: default + name: "Win2019 mingw" + steps: - uses: actions/checkout@v2 with: From f9ea6a5bff695c5f88bb95dce38a3fd349738907 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 25 Mar 2021 14:46:28 -0500 Subject: [PATCH 52/52] CI config and git export tweaks Add paths-ignore filters for GHA PRs Stop .tools/ and .gitattributes commits from triggering CI Exclude CI files from git exports --- .appveyor.yml | 2 ++ .appveyor/epics-base-7.yml | 2 ++ .gitattributes | 3 ++- .github/workflows/ci-scripts-build.yml | 10 ++++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index f384361fc..c6151850f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -31,6 +31,8 @@ skip_commits: - 'documentation/*' - 'startup/*' - '.github/*' + - '.tools/*' + - '.gitattributes' - '**/*.html' - '**/*.md' diff --git a/.appveyor/epics-base-7.yml b/.appveyor/epics-base-7.yml index 410989d78..1a01b35d5 100644 --- a/.appveyor/epics-base-7.yml +++ b/.appveyor/epics-base-7.yml @@ -38,6 +38,8 @@ skip_commits: - 'documentation/*' - 'startup/*' - '.github/*' + - '.tools/*' + - '.gitattributes' - '**/*.html' - '**/*.md' diff --git a/.gitattributes b/.gitattributes index 5842dd19a..d71c782e0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ .ci/ export-ignore .tools/ export-ignore +.github/ export-ignore +.appveyor/ export-ignore .appveyor.yml export-ignore -.travis.yml export-ignore README export-subst diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 5ad79311e..0afcc3b11 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -14,9 +14,19 @@ on: - 'documentation/*' - 'startup/*' - '.appveyor/*' + - '.tools/*' + - '.gitattributes' - '**/*.html' - '**/*.md' pull_request: + paths-ignore: + - 'documentation/*' + - 'startup/*' + - '.appveyor/*' + - '.tools/*' + - '.gitattributes' + - '**/*.html' + - '**/*.md' env: SETUP_PATH: .ci-local:.ci