From ead8b7e82b32f84e06a5c6f74555c66b47c1e1c1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 9 Dec 2024 16:52:59 -0800 Subject: [PATCH 01/36] doc getIocState() --- modules/database/src/ioc/misc/iocInit.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/database/src/ioc/misc/iocInit.h b/modules/database/src/ioc/misc/iocInit.h index 6b4c944d4..1acd8ee8f 100644 --- a/modules/database/src/ioc/misc/iocInit.h +++ b/modules/database/src/ioc/misc/iocInit.h @@ -22,6 +22,9 @@ enum iocStateEnum { extern "C" { #endif +/** Query present IOC run state + * @since 3.15.8 + */ DBCORE_API enum iocStateEnum getIocState(void); DBCORE_API int iocInit(void); DBCORE_API int iocBuild(void); From 5143258011e8180ba51d97f8915618576cc9048e Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 29 Nov 2024 10:42:07 +0100 Subject: [PATCH 02/36] fix support for link 0 --- modules/database/src/std/rec/seqRecord.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/database/src/std/rec/seqRecord.c b/modules/database/src/std/rec/seqRecord.c index cd6212da1..76890e286 100644 --- a/modules/database/src/std/rec/seqRecord.c +++ b/modules/database/src/std/rec/seqRecord.c @@ -282,7 +282,7 @@ static void processCallback(epicsCallback *arg) static long get_units(DBADDR *paddr, char *units) { seqRecord *prec = (seqRecord *) paddr->precord; - int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); + int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); if (fieldOffset >= 0) switch (fieldOffset & 2) { @@ -299,7 +299,7 @@ static long get_units(DBADDR *paddr, char *units) static long get_precision(const DBADDR *paddr, long *pprecision) { seqRecord *prec = (seqRecord *) paddr->precord; - int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); + int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); short precision; if (fieldOffset >= 0) @@ -321,7 +321,7 @@ static long get_precision(const DBADDR *paddr, long *pprecision) static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) { seqRecord *prec = (seqRecord *) paddr->precord; - int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); + int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); if (fieldOffset >= 0) switch (fieldOffset & 2) { @@ -341,7 +341,7 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) { - int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); + int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); if (fieldOffset >= 0 && (fieldOffset & 2) == 0) { /* DLYn */ pcd->lower_ctrl_limit = 0.0; @@ -355,7 +355,7 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad) { seqRecord *prec = (seqRecord *) paddr->precord; - int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY1); + int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); if (fieldOffset >= 0 && (fieldOffset & 2) == 2) /* DOn */ dbGetAlarmLimits(get_dol(prec, fieldOffset), From 4ee766b6b1ef87ca8ea9152137718d254bad0fae Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 29 Nov 2024 10:47:03 +0100 Subject: [PATCH 03/36] correct mask for finding field in linkGrp It worked before because the get_xxx functions are never called for the links (bit0 = 1), but checking both bits looks cleaner. --- modules/database/src/std/rec/seqRecord.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/database/src/std/rec/seqRecord.c b/modules/database/src/std/rec/seqRecord.c index 76890e286..44d8599c4 100644 --- a/modules/database/src/std/rec/seqRecord.c +++ b/modules/database/src/std/rec/seqRecord.c @@ -285,7 +285,7 @@ static long get_units(DBADDR *paddr, char *units) int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); if (fieldOffset >= 0) - switch (fieldOffset & 2) { + switch (fieldOffset & 3) { case 0: /* DLYn */ strcpy(units, "s"); break; @@ -303,7 +303,7 @@ static long get_precision(const DBADDR *paddr, long *pprecision) short precision; if (fieldOffset >= 0) - switch (fieldOffset & 2) { + switch (fieldOffset & 3) { case 0: /* DLYn */ *pprecision = seqDLYprecision; return 0; @@ -324,7 +324,7 @@ static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); if (fieldOffset >= 0) - switch (fieldOffset & 2) { + switch (fieldOffset & 3) { case 0: /* DLYn */ pgd->lower_disp_limit = 0.0; pgd->lower_disp_limit = 10.0; @@ -343,7 +343,7 @@ static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) { int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); - if (fieldOffset >= 0 && (fieldOffset & 2) == 0) { /* DLYn */ + if (fieldOffset >= 0 && (fieldOffset & 3) == 0) { /* DLYn */ pcd->lower_ctrl_limit = 0.0; pcd->upper_ctrl_limit = seqDLYlimit; } @@ -357,7 +357,7 @@ static long get_alarm_double(DBADDR *paddr, struct dbr_alDouble *pad) seqRecord *prec = (seqRecord *) paddr->precord; int fieldOffset = dbGetFieldIndex(paddr) - indexof(DLY0); - if (fieldOffset >= 0 && (fieldOffset & 2) == 2) /* DOn */ + if (fieldOffset >= 0 && (fieldOffset & 3) == 2) /* DOn */ dbGetAlarmLimits(get_dol(prec, fieldOffset), &pad->lower_alarm_limit, &pad->lower_warning_limit, &pad->upper_warning_limit, &pad->upper_alarm_limit); From dac620a70800e9288e98a8e9a46d036655d2ebcc Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 29 Nov 2024 13:07:30 +0100 Subject: [PATCH 04/36] loop safe wrapper for dbGet added --- modules/database/src/ioc/db/dbDbLink.c | 62 ++++++++++++------------ modules/database/src/ioc/dbStatic/link.h | 1 + 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c index 77d926630..619b2ca9e 100644 --- a/modules/database/src/ioc/db/dbDbLink.c +++ b/modules/database/src/ioc/db/dbDbLink.c @@ -232,19 +232,41 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, return status; } +/* Some records get options (precsision, units, ...) for some fields + * from an input link. We need to catch the case that this link + * points back to the same field or we will end in an infinite recursion. +*/ +static long dbDbGetOptionLoopSafe(const struct link *plink, short dbrType, + void *pbuffer, long option) +{ + /* We need to cast away const to set the flags. + That's ok because we know that plink is never actually readonly. + And we reset everything to its original state. + */ + struct link *mutable_plink = (struct link *)plink; + long status = S_dbLib_badLink; + dbChannel *chan = linkChannel(plink); + DBADDR *paddr = &chan->addr; + long number_elements = 0; + + dbScanLock(paddr->precord); + if (!(mutable_plink->flags & DBLINK_FLAG_VISITED)) { + mutable_plink->flags |= DBLINK_FLAG_VISITED; + status = dbGet(paddr, dbrType, pbuffer, &option, &number_elements, NULL); + mutable_plink->flags &= ~DBLINK_FLAG_VISITED; + } + dbScanUnlock(paddr->precord); + return status; +} + static long dbDbGetControlLimits(const struct link *plink, double *low, double *high) { - dbChannel *chan = linkChannel(plink); - DBADDR *paddr = &chan->addr; struct buffer { DBRctrlDouble double value; } buffer; - long options = DBR_CTRL_DOUBLE; - long number_elements = 0; - long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, - NULL); + long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_CTRL_DOUBLE); if (status) return status; @@ -257,16 +279,11 @@ static long dbDbGetControlLimits(const struct link *plink, double *low, static long dbDbGetGraphicLimits(const struct link *plink, double *low, double *high) { - dbChannel *chan = linkChannel(plink); - DBADDR *paddr = &chan->addr; struct buffer { DBRgrDouble double value; } buffer; - long options = DBR_GR_DOUBLE; - long number_elements = 0; - long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, - NULL); + long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_GR_DOUBLE); if (status) return status; @@ -279,16 +296,11 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low, static long dbDbGetAlarmLimits(const struct link *plink, double *lolo, double *low, double *high, double *hihi) { - dbChannel *chan = linkChannel(plink); - DBADDR *paddr = &chan->addr; struct buffer { DBRalDouble double value; } buffer; - long options = DBR_AL_DOUBLE; - long number_elements = 0; - long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, - 0); + long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_AL_DOUBLE); if (status) return status; @@ -302,16 +314,11 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo, static long dbDbGetPrecision(const struct link *plink, short *precision) { - dbChannel *chan = linkChannel(plink); - DBADDR *paddr = &chan->addr; struct buffer { DBRprecision double value; } buffer; - long options = DBR_PRECISION; - long number_elements = 0; - long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, - 0); + long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_PRECISION); if (status) return status; @@ -322,16 +329,11 @@ static long dbDbGetPrecision(const struct link *plink, short *precision) static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize) { - dbChannel *chan = linkChannel(plink); - DBADDR *paddr = &chan->addr; struct buffer { DBRunits double value; } buffer; - long options = DBR_UNITS; - long number_elements = 0; - long status = dbGet(paddr, DBR_DOUBLE, &buffer, &options, &number_elements, - 0); + long status = dbDbGetOptionLoopSafe(plink, DBR_DOUBLE, &buffer, DBR_UNITS); if (status) return status; diff --git a/modules/database/src/ioc/dbStatic/link.h b/modules/database/src/ioc/dbStatic/link.h index a4aab8dd8..6cd3ccd92 100644 --- a/modules/database/src/ioc/dbStatic/link.h +++ b/modules/database/src/ioc/dbStatic/link.h @@ -72,6 +72,7 @@ DBCORE_API extern const maplinkType pamaplinkType[LINK_NTYPES]; /* DBLINK Flag bits */ #define DBLINK_FLAG_INITIALIZED 1 /* dbInitLink() called */ #define DBLINK_FLAG_TSELisTIME 2 /* Use TSEL to get timeStamp */ +#define DBLINK_FLAG_VISITED 4 /* Used in loop detection */ struct macro_link { char *macroStr; From f4aee8e6b7e42310436e370442ca54ecf6d8ae82 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Mon, 25 Nov 2024 10:12:19 +0100 Subject: [PATCH 05/36] Add debug build configuration for os x mX arch --- configure/os/CONFIG.darwin-aarch64-debug.Common | 11 +++++++++++ .../os/CONFIG.darwin-aarch64.darwin-aarch64-debug | 14 ++++++++++++++ configure/os/CONFIG.darwin-x86-debug.Common | 11 +++++++++++ 3 files changed, 36 insertions(+) create mode 100644 configure/os/CONFIG.darwin-aarch64-debug.Common create mode 100644 configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug create mode 100644 configure/os/CONFIG.darwin-x86-debug.Common diff --git a/configure/os/CONFIG.darwin-aarch64-debug.Common b/configure/os/CONFIG.darwin-aarch64-debug.Common new file mode 100644 index 000000000..49b58c879 --- /dev/null +++ b/configure/os/CONFIG.darwin-aarch64-debug.Common @@ -0,0 +1,11 @@ +# CONFIG.darwin-aarch64-debug.Common +# +# Definitions for darwin-aarch64-debug host builds - darwin-aarch64 target build with debug compiler flags +# Sites may override these definitions in CONFIG_SITE.darwin-aarch64-debug.Common +#------------------------------------------------------- + +include $(CONFIG)/os/CONFIG.darwin-aarch64.Common + +# Removes -O optimization and adds -g compile option +HOST_OPT=NO + diff --git a/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug b/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug new file mode 100644 index 000000000..21db17445 --- /dev/null +++ b/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug @@ -0,0 +1,14 @@ +# CONFIG.darwin-aarch64.darwin-aarch64-debug +# +# Definitions for darwin-aarch64 host - darwin-aarch64-debug target build with debug compiler flags +# Sites may override these definitions in CONFIG_SITE.darwin-aarch64.darwin-aarch64-debug +#------------------------------------------------------- + +-include $(CONFIG)/os/CONFIG.Common.darwin-aarch64 +-include $(CONFIG)/os/CONFIG.darwin-aarch64.darwin-aarch64 +-include $(CONFIG)/os/CONFIG_SITE.Common.darwin-aarch46 +-include $(CONFIG)/os/CONFIG_SITE.darwin-aarch64.darwin-aarch64 + + +BUILD_CLASS=HOST +HOST_OPT = NO diff --git a/configure/os/CONFIG.darwin-x86-debug.Common b/configure/os/CONFIG.darwin-x86-debug.Common new file mode 100644 index 000000000..4e9aca82b --- /dev/null +++ b/configure/os/CONFIG.darwin-x86-debug.Common @@ -0,0 +1,11 @@ +# CONFIG.darwin-x86-debug.Common +# +# Definitions for darwin-x86-debug host builds - darwin-x86 target build with debug compiler flags +# Sites may override these definitions in CONFIG_SITE.darwin-x86-debug.Common +#------------------------------------------------------- + +include $(CONFIG)/os/CONFIG.darwin-x86.Common + +# Removes -O optimization and adds -g compile option +HOST_OPT=NO + From d0cf47cd6f38a0fc8995510ea849111e4253615c Mon Sep 17 00:00:00 2001 From: Jure Varlec Date: Tue, 19 Nov 2024 16:25:09 +0100 Subject: [PATCH 06/36] Propagate AMSG through MSS links MS and MSI links do not propagate STAT and therefore do not propagate AMSG, either. CA, CP and CPP links also do not propagate AMSG, but the reason is technical: the message is not available over Channel Access. --- modules/database/src/ioc/db/dbDbLink.c | 9 +++++---- modules/database/src/ioc/db/recGbl.c | 12 +++++++++--- modules/database/src/ioc/db/recGbl.h | 2 ++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c index 619b2ca9e..16cc33279 100644 --- a/modules/database/src/ioc/db/dbDbLink.c +++ b/modules/database/src/ioc/db/dbDbLink.c @@ -226,9 +226,10 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, } if (!status && precord != dbChannelRecord(chan)) - recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode, + recGblInheritSevrMsg(plink->value.pv_link.pvlMask & pvlOptMsMode, plink->precord, - dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr); + dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr, + dbChannelRecord(chan)->amsg); return status; } @@ -378,8 +379,8 @@ static long dbDbPutValue(struct link *plink, short dbrType, dbCommon *pdest = dbChannelRecord(chan); long status = dbPut(paddr, dbrType, pbuffer, nRequest); - recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta, - psrce->nsev); + recGblInheritSevrMsg(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta, + psrce->nsev, psrce->namsg); if (status) return status; diff --git a/modules/database/src/ioc/db/recGbl.c b/modules/database/src/ioc/db/recGbl.c index bf6ea7e88..002a7aebc 100644 --- a/modules/database/src/ioc/db/recGbl.c +++ b/modules/database/src/ioc/db/recGbl.c @@ -260,8 +260,8 @@ int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr) return recGblSetSevrMsg(precord, new_stat, new_sevr, NULL); } -void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, - epicsEnum16 sevr) +void recGblInheritSevrMsg(int msMode, void *precord, epicsEnum16 stat, + epicsEnum16 sevr, const char *msg) { switch (msMode) { case pvlOptNMS: @@ -274,11 +274,17 @@ void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, recGblSetSevr(precord, LINK_ALARM, sevr); break; case pvlOptMSS: - recGblSetSevr(precord, stat, sevr); + /* Only MSS inherits msg */ + recGblSetSevrMsg(precord, stat, sevr, "%s", msg); break; } } +void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, + epicsEnum16 sevr) +{ + recGblInheritSevrMsg(msMode, precord, stat, sevr, NULL); +} void recGblFwdLink(void *precord) { diff --git a/modules/database/src/ioc/db/recGbl.h b/modules/database/src/ioc/db/recGbl.h index cf3db4bc5..4a21e7f34 100644 --- a/modules/database/src/ioc/db/recGbl.h +++ b/modules/database/src/ioc/db/recGbl.h @@ -73,6 +73,8 @@ DBCORE_API int recGblSetSevr(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr); DBCORE_API void recGblInheritSevr(int msMode, void *precord, epicsEnum16 stat, epicsEnum16 sevr); +DBCORE_API void recGblInheritSevrMsg(int msMode, void *precord, epicsEnum16 stat, + epicsEnum16 sevr, const char *msg); DBCORE_API int recGblSetSevrMsg(void *precord, epicsEnum16 new_stat, epicsEnum16 new_sevr, EPICS_PRINTF_FMT(const char *msg), ...) EPICS_PRINTF_STYLE(4,5); From 9f8a8b9c1fc96dcbb18a35b627530428f74aaa62 Mon Sep 17 00:00:00 2001 From: Jure Varlec Date: Tue, 19 Nov 2024 16:45:18 +0100 Subject: [PATCH 07/36] Update RELEASE_NOTES with AMSG propagation --- documentation/RELEASE_NOTES.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 5f3176b6a..4f011dc2c 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,6 +22,16 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.8.1 +### The AMSG error message propagates through MSS links + +A database link with the MSS attribute will now propagate not only SEVR and +STAT, but also AMSG. This field contains additional information that complements +STAT. Links with MS or MSI attributes do not propagate STAT, and therefore do +not propagate AMSG, either. + +Channel Access links do not propagate AMSG, regardless of the MSS attribute, +because the message is not available over Channel Access. + ### DBE_PROPERTY event rate changed Updating property fields now only post DBE_PROPERTY events if the From 5a11954c5180a40861ec6dca3a0d551a97af5179 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 26 Dec 2024 18:44:23 +0100 Subject: [PATCH 08/36] Add documentation for the UDFS field --- modules/database/src/ioc/db/dbCommon.dbd.pod | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbCommon.dbd.pod b/modules/database/src/ioc/db/dbCommon.dbd.pod index 5366d477a..8d7c1a0ca 100644 --- a/modules/database/src/ioc/db/dbCommon.dbd.pod +++ b/modules/database/src/ioc/db/dbCommon.dbd.pod @@ -285,7 +285,11 @@ Inf (Infinite) value. UDF defaults to TRUE but can be set in a database file. Record and device support routines which write to the VAL field are generally responsible for setting and clearing UDF. -=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF +The B field specifies the alarm severity that the record will be set to +whenever its value is undefined (i.e., the UDF field is 1). This includes the +initial severity of the record being undefined after the IOC boots. + +=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF, UDFS =cut From 333be085c0fc7326273312807971caba3dbd25ca Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Sun, 22 Dec 2024 12:20:39 -0800 Subject: [PATCH 09/36] Fix compile error in tsSLList.h --- modules/libcom/src/cxxTemplates/tsSLList.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/cxxTemplates/tsSLList.h b/modules/libcom/src/cxxTemplates/tsSLList.h index 6d375af55..895ec7dde 100644 --- a/modules/libcom/src/cxxTemplates/tsSLList.h +++ b/modules/libcom/src/cxxTemplates/tsSLList.h @@ -311,13 +311,13 @@ inline bool tsSLIterConst::valid () const template < class T > inline bool tsSLIterConst::operator == ( const tsSLIterConst &rhs ) const { - return this->pEntry == rhs.pConstEntry; + return this->pEntry == rhs.pEntry; } template < class T > inline bool tsSLIterConst::operator != (const tsSLIterConst &rhs) const { - return this->pEntry != rhs.pConstEntry; + return this->pEntry != rhs.pEntry; } template < class T > From b90ab7de139bd5ec13b2cbd9069e00a507fa7a62 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Mon, 4 Nov 2024 15:30:46 +0100 Subject: [PATCH 10/36] Improve relative path check for msi For posix-ish systems, we previously checked that a path was relative by simpy checking if it included a '/' character. This meant that you could not, for example, do ``` $ cat foo.substitutions file rel/to/bar.template { } $ msi -I /some/path foo.substitutions ``` where our template file is located at `/some/path/rel/to/bar.template`. Note that relateive paths work differently on Windows, so we carve out an exception there. --- modules/database/src/ioc/dbtemplate/Makefile | 1 + modules/database/src/ioc/dbtemplate/msi.cpp | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/dbtemplate/Makefile b/modules/database/src/ioc/dbtemplate/Makefile index 99c46530f..1013c0abf 100644 --- a/modules/database/src/ioc/dbtemplate/Makefile +++ b/modules/database/src/ioc/dbtemplate/Makefile @@ -14,6 +14,7 @@ SRC_DIRS += $(IOCDIR)/dbtemplate PROD_HOST += msi msi_SRCS = msi.cpp +msi_SYS_LIBS_WIN32 = shlwapi DOCS += msi.md INC += dbLoadTemplate.h diff --git a/modules/database/src/ioc/dbtemplate/msi.cpp b/modules/database/src/ioc/dbtemplate/msi.cpp index 88c5d160d..f107f2460 100644 --- a/modules/database/src/ioc/dbtemplate/msi.cpp +++ b/modules/database/src/ioc/dbtemplate/msi.cpp @@ -27,6 +27,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + #define MAX_BUFFER_SIZE 4096 #define MAX_DEPS 1024 @@ -493,6 +497,14 @@ static void inputErrPrint(const inputData *const pinputData) EXIT; } +static int isPathRelative(const char * const path) { +#ifdef _WIN32 + return path && PathIsRelativeA(path); +#else + return path && path[0] != '/'; +#endif +} + static void inputOpenFile(inputData *pinputData, const char * const filename) { std::list& pathList = pinputData->pathList; @@ -505,7 +517,7 @@ static void inputOpenFile(inputData *pinputData, const char * const filename) STEP("Using stdin"); fp = stdin; } - else if (pathList.empty() || strchr(filename, '/')){ + else if (pathList.empty() || !isPathRelative(filename)){ STEPS("Opening ", filename); fp = fopen(filename, "r"); } From 018683644966d1297cac9d6f874fb898d3254bd3 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Tue, 5 Nov 2024 09:47:43 +0100 Subject: [PATCH 11/36] Reading a file from the command-line should not use include paths --- documentation/RELEASE_NOTES.md | 24 +++++++++++++++++++ modules/database/src/ioc/dbtemplate/msi.cpp | 26 +++++++++++---------- modules/database/src/ioc/dbtemplate/msi.md | 12 ++++++++++ 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 4f011dc2c..94fd41388 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -37,6 +37,30 @@ because the message is not available over Channel Access. Updating property fields now only post DBE_PROPERTY events if the field actually changed. +### Changes to msi related to include paths + +There are two changes to `msi` included here. + +`msi` now treats files included by .template or .substutiions files in a more +consistent way: for relative paths, it will always look relative to the current +working directory if no `-I` flags are passed, and if they are passed then it +will search for the _relative_ path from each of those flags. That is, the +following will now find the file `bar.template` located at +`/some/path/rel/path/bar.template` +``` +$ cat foo.substitutions +file rel/path/bar.template { + # contents +} +$ msi -I /some/path foo.substitutions +``` + +Note that this does provide one change from previous behaviour: when opening a +file from the command line, `msi` will not use the `-I`-specified paths to +search for the file, but will only work relative to the current working +directory, consistent with most commandline utilities. + + ### Allow users to delete previously created records from the database From this release, record instances and aliases that have already been loaded diff --git a/modules/database/src/ioc/dbtemplate/msi.cpp b/modules/database/src/ioc/dbtemplate/msi.cpp index f107f2460..0da488cba 100644 --- a/modules/database/src/ioc/dbtemplate/msi.cpp +++ b/modules/database/src/ioc/dbtemplate/msi.cpp @@ -65,7 +65,7 @@ typedef struct inputData inputData; static void inputConstruct(inputData **ppvt); static void inputDestruct(inputData * const pvt); static void inputAddPath(inputData * const pvt, const char * const pval); -static void inputBegin(inputData * const pvt, const char * const fileName); +static void inputBegin(inputData * const pvt, const char * const fileName, bool fromCmdLine); static char *inputNextLine(inputData * const pvt); static void inputNewIncludeFile(inputData * const pvt, const char * const name); static void inputErrPrint(const inputData * const pvt); @@ -87,7 +87,8 @@ static void addMacroReplacements(MAC_HANDLE * const macPvt, const char * const pval); static void makeSubstitutions(inputData * const inputPvt, MAC_HANDLE * const macPvt, - const char * const templateName); + const char * const templateName, + bool fromCmdLine); /*Global variables */ static int opt_V = 0; @@ -175,7 +176,7 @@ int main(int argc,char **argv) if (substitutionName.empty()) { STEP("Single template+substitutions file"); - makeSubstitutions(inputPvt, macPvt, templateName); + makeSubstitutions(inputPvt, macPvt, templateName, true); } else { subInfo *substitutePvt; @@ -207,7 +208,7 @@ int main(int argc,char **argv) macPushScope(macPvt); addMacroReplacements(macPvt, macStr); - makeSubstitutions(inputPvt, macPvt, filename); + makeSubstitutions(inputPvt, macPvt, filename, false); if (localScope) macPopScope(macPvt); @@ -280,14 +281,15 @@ static const char *cmdNames[] = {"include","substitute"}; static void makeSubstitutions(inputData * const inputPvt, MAC_HANDLE * const macPvt, - const char * const templateName) + const char * const templateName, + bool fromCmdLine) { char *input; static char buffer[MAX_BUFFER_SIZE]; int n; ENTER; - inputBegin(inputPvt, templateName); + inputBegin(inputPvt, templateName, fromCmdLine); while ((input = inputNextLine(inputPvt))) { int expand=1; char *p; @@ -382,7 +384,7 @@ struct inputData { inputData() { memset(inputBuffer, 0, sizeof(inputBuffer) * sizeof(inputBuffer[0])); }; }; -static void inputOpenFile(inputData *pinputData, const char * const filename); +static void inputOpenFile(inputData *pinputData, const char * const filename, bool fromCmdLine); static void inputCloseFile(inputData *pinputData); static void inputCloseAllFiles(inputData *pinputData); @@ -435,11 +437,11 @@ static void inputAddPath(inputData * const pinputData, const char * const path) EXIT; } -static void inputBegin(inputData * const pinputData, const char * const fileName) +static void inputBegin(inputData * const pinputData, const char * const fileName, bool fromCmdLine) { ENTER; inputCloseAllFiles(pinputData); - inputOpenFile(pinputData, fileName); + inputOpenFile(pinputData, fileName, fromCmdLine); EXIT; } @@ -466,7 +468,7 @@ static void inputNewIncludeFile(inputData * const pinputData, const char * const name) { ENTER; - inputOpenFile(pinputData,name); + inputOpenFile(pinputData, name, false); EXIT; } @@ -505,7 +507,7 @@ static int isPathRelative(const char * const path) { #endif } -static void inputOpenFile(inputData *pinputData, const char * const filename) +static void inputOpenFile(inputData *pinputData, const char * const filename, bool fromCmdLine) { std::list& pathList = pinputData->pathList; std::list::iterator pathIt = pathList.end(); @@ -517,7 +519,7 @@ static void inputOpenFile(inputData *pinputData, const char * const filename) STEP("Using stdin"); fp = stdin; } - else if (pathList.empty() || !isPathRelative(filename)){ + else if (fromCmdLine || pathList.empty() || !isPathRelative(filename)){ STEPS("Opening ", filename); fp = fopen(filename, "r"); } diff --git a/modules/database/src/ioc/dbtemplate/msi.md b/modules/database/src/ioc/dbtemplate/msi.md index 1b536cb67..bbe5273ef 100644 --- a/modules/database/src/ioc/dbtemplate/msi.md +++ b/modules/database/src/ioc/dbtemplate/msi.md @@ -60,6 +60,18 @@ Switches have the following meanings: 2. . (the current directory) 3. .. (the parent of the current directory) + Note that relative path searching is handled as + + $ cat foo.substitutions + file rel/path/bar.template { + # contents + } + $ msi -I . -I /some/path foo.substitutions + + which will try to find `bar.template` at the path `./rel/path/` followed by + `/some/path/rel/path`. + + - **-M _substitutions_** This parameter specifies macro values for the template instance. From 721e9cc3a7e388903567eb0490293857f53db159 Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Tue, 12 Nov 2024 17:13:16 -0800 Subject: [PATCH 12/36] Add ABORT_ON_ASSERT flag to CONFIG_SITE This flag causes EPICS to call abort() on assertion failures rather than suspend the executing thread. With the epicsThreadSuspendSelf() behavior, an IOC can end up in a difficult to detect error state where one or more threads has essentially crashed due to an assertion failure. This also matches the C behavior of assert(3) --- configure/CONFIG_SITE_ENV | 3 +++ modules/libcom/src/env/envDefs.h | 1 + modules/libcom/src/osi/os/default/osdAssert.c | 13 +++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV index bacbc14a5..bcc3bdf7a 100644 --- a/configure/CONFIG_SITE_ENV +++ b/configure/CONFIG_SITE_ENV @@ -92,3 +92,6 @@ EPICS_IOC_LOG_FILE_NAME= EPICS_IOC_LOG_FILE_COMMAND= EPICS_IOC_LOG_FILE_LIMIT=1000000 +# Set to 'YES' to call abort() rather than suspend the current thread +# when an assert() fails +EPICS_ABORT_ON_ASSERT=NO diff --git a/modules/libcom/src/env/envDefs.h b/modules/libcom/src/env/envDefs.h index 3bf64c861..c54a781c7 100644 --- a/modules/libcom/src/env/envDefs.h +++ b/modules/libcom/src/env/envDefs.h @@ -76,6 +76,7 @@ LIBCOM_API extern const ENV_PARAM EPICS_IOC_LOG_FILE_COMMAND; LIBCOM_API extern const ENV_PARAM IOCSH_PS1; LIBCOM_API extern const ENV_PARAM IOCSH_HISTSIZE; LIBCOM_API extern const ENV_PARAM IOCSH_HISTEDIT_DISABLE; +LIBCOM_API extern const ENV_PARAM EPICS_ABORT_ON_ASSERT; LIBCOM_API extern const ENV_PARAM *env_param_list[]; struct in_addr; diff --git a/modules/libcom/src/osi/os/default/osdAssert.c b/modules/libcom/src/osi/os/default/osdAssert.c index 2d62bc820..23263df4e 100644 --- a/modules/libcom/src/osi/os/default/osdAssert.c +++ b/modules/libcom/src/osi/os/default/osdAssert.c @@ -20,12 +20,14 @@ #include "epicsTime.h" #include "cantProceed.h" #include "epicsStackTrace.h" +#include "envDefs.h" void epicsAssert (const char *pFile, const unsigned line, const char *pExp, const char *pAuthorName) { epicsTimeStamp current; + int shouldAbort = 0; errlogPrintf("\n\n\n" "A call to 'assert(%s)'\n" @@ -50,6 +52,13 @@ void epicsAssert (const char *pFile, const unsigned line, errlogPrintf("Please E-mail this message to %s or to tech-talk@aps.anl.gov\n", pAuthorName); - errlogPrintf("Calling epicsThreadSuspendSelf()\n"); - epicsThreadSuspendSelf (); + if (envGetBoolConfigParam(&EPICS_ABORT_ON_ASSERT, &shouldAbort) == 0 && shouldAbort) { + errlogPrintf("Calling abort()\n"); + errlogFlush(); + abort(); + } + else { + errlogPrintf("Calling epicsThreadSuspendSelf()\n"); + epicsThreadSuspendSelf (); + } } From 9fb820b46e772a249324a1b125dc11f1639311c1 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Thu, 14 Nov 2024 16:12:35 +0100 Subject: [PATCH 13/36] Add tests for relative include paths --- modules/database/test/ioc/dbtemplate/msi.plt | 8 +++++++- modules/database/test/ioc/dbtemplate/t13-result.txt | 2 ++ modules/database/test/ioc/dbtemplate/t13-substitute.txt | 3 +++ modules/database/test/ioc/dbtemplate/t13-template.txt | 2 ++ modules/database/test/ioc/dbtemplate/t14-include.txt | 1 + modules/database/test/ioc/dbtemplate/t14-result.txt | 5 +++++ modules/database/test/ioc/dbtemplate/t14-template.txt | 5 +++++ 7 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 modules/database/test/ioc/dbtemplate/t13-result.txt create mode 100644 modules/database/test/ioc/dbtemplate/t13-substitute.txt create mode 100644 modules/database/test/ioc/dbtemplate/t13-template.txt create mode 100644 modules/database/test/ioc/dbtemplate/t14-include.txt create mode 100644 modules/database/test/ioc/dbtemplate/t14-result.txt create mode 100644 modules/database/test/ioc/dbtemplate/t14-template.txt diff --git a/modules/database/test/ioc/dbtemplate/msi.plt b/modules/database/test/ioc/dbtemplate/msi.plt index dc466be1f..09835d3ac 100644 --- a/modules/database/test/ioc/dbtemplate/msi.plt +++ b/modules/database/test/ioc/dbtemplate/msi.plt @@ -12,7 +12,7 @@ use strict; use Test; -BEGIN {plan tests => 12} +BEGIN {plan tests => 14} # Check include/substitute command model ok(msi('-I .. ../t1-template.txt'), slurp('../t1-result.txt')); @@ -56,6 +56,12 @@ my %envs = (TEST_NO => 12, PREFIX => 't'); ok(msi('-I. -I.. -S ../t12-substitute.txt'), slurp('../t12-result.txt')); delete @ENV{ keys %envs }; # Not really needed +# Substitution file, relative path includes +ok(msi('-I @TOP@/modules -S ../t13-substitute.txt'), slurp('../t13-result.txt')); + +# Template file, relative path includes +ok(msi('-I @TOP@/modules ../t14-template.txt'), slurp('../t14-result.txt')); + # Test support routines sub slurp { diff --git a/modules/database/test/ioc/dbtemplate/t13-result.txt b/modules/database/test/ioc/dbtemplate/t13-result.txt new file mode 100644 index 000000000..6cfcc57da --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t13-result.txt @@ -0,0 +1,2 @@ +# comment line +a=foo diff --git a/modules/database/test/ioc/dbtemplate/t13-substitute.txt b/modules/database/test/ioc/dbtemplate/t13-substitute.txt new file mode 100644 index 000000000..63d3fca1f --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t13-substitute.txt @@ -0,0 +1,3 @@ +file database/test/ioc/dbtemplate/t13-template.txt { + { a=foo } +} diff --git a/modules/database/test/ioc/dbtemplate/t13-template.txt b/modules/database/test/ioc/dbtemplate/t13-template.txt new file mode 100644 index 000000000..7958885a7 --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t13-template.txt @@ -0,0 +1,2 @@ +# comment line +a=$(a) diff --git a/modules/database/test/ioc/dbtemplate/t14-include.txt b/modules/database/test/ioc/dbtemplate/t14-include.txt new file mode 100644 index 000000000..7f69fca81 --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t14-include.txt @@ -0,0 +1 @@ +I'm a file! diff --git a/modules/database/test/ioc/dbtemplate/t14-result.txt b/modules/database/test/ioc/dbtemplate/t14-result.txt new file mode 100644 index 000000000..5d5dbda1b --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t14-result.txt @@ -0,0 +1,5 @@ +This is t14-template.txt + +I'm a file! + +End of t14-template.txt diff --git a/modules/database/test/ioc/dbtemplate/t14-template.txt b/modules/database/test/ioc/dbtemplate/t14-template.txt new file mode 100644 index 000000000..276663f7a --- /dev/null +++ b/modules/database/test/ioc/dbtemplate/t14-template.txt @@ -0,0 +1,5 @@ +This is t14-template.txt + +include "database/test/ioc/dbtemplate/t14-include.txt" + +End of t14-template.txt From 72026a27a04ec914cb70c4c3caff0224492a96b4 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 23 Aug 2024 12:15:03 +0200 Subject: [PATCH 14/36] allow to load the same alias multiple times (unless dbRecordsOnceOnly is set) --- documentation/RELEASE_NOTES.md | 7 +++ .../database/src/ioc/dbStatic/dbLexRoutines.c | 44 ++++++++++++++----- modules/database/test/ioc/db/Makefile | 6 +++ modules/database/test/ioc/db/dbStaticTest.c | 31 ++++++++++--- .../test/ioc/db/dbStaticTestAliasAgain1.db | 4 ++ .../test/ioc/db/dbStaticTestAliasAgain2.db | 2 + .../test/ioc/db/dbStaticTestAliasAgain3.db | 2 + .../ioc/db/dbStaticTestAliasAgainError1.db | 2 + .../ioc/db/dbStaticTestAliasAgainError2.db | 2 + 9 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 modules/database/test/ioc/db/dbStaticTestAliasAgain1.db create mode 100644 modules/database/test/ioc/db/dbStaticTestAliasAgain2.db create mode 100644 modules/database/test/ioc/db/dbStaticTestAliasAgain3.db create mode 100644 modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db create mode 100644 modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 94fd41388..19ca5559c 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -32,6 +32,13 @@ not propagate AMSG, either. Channel Access links do not propagate AMSG, regardless of the MSS attribute, because the message is not available over Channel Access. +### Allow to load the same alias multiple times + +Aliases can now be defined multiple times as long as they still refer to the +same record, unless the shell variable dbRecordsOnceOnly is set. +This allows to load database files multiple times, even if they contain +alias definitions. + ### DBE_PROPERTY event rate changed Updating property fields now only post DBE_PROPERTY events if the diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 1b60095fb..301bb5b98 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1263,24 +1263,50 @@ static void dbRecordInfo(char *name, char *value) } } +static long createAlias(DBENTRY *pdbentry, const char *alias) +{ + DBENTRY tempEntry; + long status; + dbRecordNode *precnode = pdbentry->precnode; + + if (precnode->aliasedRecnode) precnode = precnode->aliasedRecnode; + dbInitEntry(pdbentry->pdbbase, &tempEntry); + status = dbFindRecord(&tempEntry, alias); + if (status == 0) { + if (tempEntry.precnode->aliasedRecnode != precnode) { + if (tempEntry.precnode->aliasedRecnode) + fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by an alias for \"%s\"\n", + alias, dbGetRecordName(pdbentry), + tempEntry.precnode->aliasedRecnode->recordname); + else + fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by a record\n", + alias, dbGetRecordName(pdbentry)); + status = S_dbLib_recExists; + } else if (dbRecordsOnceOnly) { + fprintf(stderr, ERL_ERROR ": Alias \"%s\" already defined and dbRecordsOnceOnly set.\n", + alias); + status = S_dbLib_recExists; + } + } else { + status = dbCreateAlias(pdbentry, alias); + } + dbFinishEntry(&tempEntry); + return status; +} + static void dbRecordAlias(char *name) { DBENTRY *pdbentry; tempListNode *ptempListNode; - long status; - if(dbRecordNameValidate(name)) return; if (duplicate) return; ptempListNode = (tempListNode *)ellFirst(&tempList); pdbentry = ptempListNode->item; - status = dbCreateAlias(pdbentry, name); - if (status) { - fprintf(stderr, "Can't create alias \"%s\" for \"%s\"\n", - name, dbGetRecordName(pdbentry)); + + if (createAlias(pdbentry, name) != 0) { yyerror(NULL); - return; } } @@ -1298,9 +1324,7 @@ static void dbAlias(char *name, char *alias) alias, name); yyerror(NULL); } - else if (dbCreateAlias(pdbEntry, alias)) { - fprintf(stderr, "Can't create alias \"%s\" referring to \"%s\"\n", - alias, name); + else if (createAlias(pdbEntry, alias) != 0) { yyerror(NULL); } dbFinishEntry(pdbEntry); diff --git a/modules/database/test/ioc/db/Makefile b/modules/database/test/ioc/db/Makefile index f66d3db32..4395c291e 100644 --- a/modules/database/test/ioc/db/Makefile +++ b/modules/database/test/ioc/db/Makefile @@ -36,6 +36,7 @@ dbTestIoc_DBD += xLink.dbd dbTestIoc_DBD += devx.dbd dbTestIoc_DBD += jlinkz.dbd dbTestIoc_DBD += dbLinkdset.dbd +dbTestIoc_DBD += dbCore.dbd TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp @@ -183,6 +184,11 @@ testHarness_SRCS += dbStaticTest.c TESTFILES += ../dbStaticTest.db TESTFILES += ../dbStaticTestAlias1.db TESTFILES += ../dbStaticTestAlias2.db +TESTFILES += ../dbStaticTestAliasAgain1.db +TESTFILES += ../dbStaticTestAliasAgain2.db +TESTFILES += ../dbStaticTestAliasAgain3.db +TESTFILES += ../dbStaticTestAliasAgainError1.db +TESTFILES += ../dbStaticTestAliasAgainError2.db TESTFILES += ../dbStaticTestRemove.db TESTS += dbStaticTest diff --git a/modules/database/test/ioc/db/dbStaticTest.c b/modules/database/test/ioc/db/dbStaticTest.c index 0ead11803..695307659 100644 --- a/modules/database/test/ioc/db/dbStaticTest.c +++ b/modules/database/test/ioc/db/dbStaticTest.c @@ -14,6 +14,7 @@ #include #include #include +#include static void testEntryRemoved(const char *pv) @@ -321,16 +322,19 @@ static void testDbVerify(const char *record) dbFinishEntry(&entry); } -static void testWrongAliasRecord(const char *filename) +static void testReadDatabase(const char *filename, int expectToFail) { FILE *fp = NULL; + long status; dbPath(pdbbase,"." OSI_PATH_LIST_SEPARATOR ".."); dbOpenFile(pdbbase, filename, &fp); if(!fp) { - testAbort("Unable to read %s", filename); + testAbort("Unable to open %s", filename); } - testOk(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL) != 0, - "Wrong alias record in %s is expected to fail", filename); + status = dbReadDatabaseFP(&pdbbase, fp, NULL, NULL); + testOk(!status == !expectToFail, + "Reading %s%s", filename, + expectToFail ? " is expected to fail" : ""); } void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); @@ -341,7 +345,7 @@ MAIN(dbStaticTest) char *ldirDup; FILE *fp = NULL; - testPlan(340); + testPlan(350); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -370,8 +374,21 @@ MAIN(dbStaticTest) } free(ldirDup); - testWrongAliasRecord("dbStaticTestAlias1.db"); - testWrongAliasRecord("dbStaticTestAlias2.db"); + testReadDatabase("dbStaticTestAlias1.db", 1); + testReadDatabase("dbStaticTestAlias2.db", 1); + + /* Test re-defining aliases */ + testReadDatabase("dbStaticTestAliasAgain1.db", 0); + testReadDatabase("dbStaticTestAliasAgain1.db", 0); + testReadDatabase("dbStaticTestAliasAgain2.db", 0); + testReadDatabase("dbStaticTestAliasAgain2.db", 0); + testReadDatabase("dbStaticTestAliasAgain3.db", 0); + testReadDatabase("dbStaticTestAliasAgain3.db", 0); + testReadDatabase("dbStaticTestAliasAgainError1.db", 1); + testReadDatabase("dbStaticTestAliasAgainError2.db", 1); + iocshCmd("var dbRecordsOnceOnly 1"); + testReadDatabase("dbStaticTestAliasAgain2.db", 1); + testReadDatabase("dbStaticTestAliasAgain3.db", 1); testEntry("testrec.VAL"); testEntry("testalias.VAL"); diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgain1.db b/modules/database/test/ioc/db/dbStaticTestAliasAgain1.db new file mode 100644 index 000000000..bc7cc1b65 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgain1.db @@ -0,0 +1,4 @@ +# Test re-load alias in record +record(x, "testrecAgain") { + alias("testaliasAgain1") +} diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgain2.db b/modules/database/test/ioc/db/dbStaticTestAliasAgain2.db new file mode 100644 index 000000000..b6709f24f --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgain2.db @@ -0,0 +1,2 @@ +# Test re-load alias for record +alias("testrecAgain", "testaliasAgain2") diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgain3.db b/modules/database/test/ioc/db/dbStaticTestAliasAgain3.db new file mode 100644 index 000000000..8dcbc4057 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgain3.db @@ -0,0 +1,2 @@ +# Test re-load alias for alias +alias("testaliasAgain2", "testaliasAgain3") diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db b/modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db new file mode 100644 index 000000000..150c09e20 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db @@ -0,0 +1,2 @@ +# ERROR: alias using name of exising alias for different record +alias("testrec", "testaliasAgain1") diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db b/modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db new file mode 100644 index 000000000..0fb844777 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db @@ -0,0 +1,2 @@ +# ERROR: alias using name of exising record fails +alias("testrecAgain", "testrec") From 1cd141c540c5532f1618c538c3a81a62fc73c639 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 24 Feb 2022 10:07:08 -0800 Subject: [PATCH 15/36] dbLoadTemplate: error propagation and more context on .db syntax error --- .../src/ioc/dbtemplate/dbLoadTemplate.y | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y index a382459c1..f2fca00f8 100644 --- a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y +++ b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y @@ -41,6 +41,17 @@ static int var_count, sub_count; int dbTemplateMaxVars = 100; epicsExportAddress(int, dbTemplateMaxVars); +static +int msiLoadRecords(const char *fname, const char *subs) +{ + int ret = dbLoadRecords(fname, subs); + if(ret) { + fprintf(stderr, "dbLoadRecords(\"%s\", %s)\n", fname, subs); + yyerror("Error while reading included file"); + } + return ret; +} + %} %start substitution_file @@ -167,7 +178,7 @@ pattern_definition: global_definitions fprintf(stderr, "pattern_definition: pattern_values empty\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; } | O_BRACE pattern_values C_BRACE { @@ -175,7 +186,7 @@ pattern_definition: global_definitions fprintf(stderr, "pattern_definition:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; *sub_locals = '\0'; sub_count = 0; } @@ -190,7 +201,7 @@ pattern_definition: global_definitions fprintf(stderr, "pattern_definition:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; dbmfFree($1); *sub_locals = '\0'; sub_count = 0; @@ -250,7 +261,7 @@ variable_substitution: global_definitions fprintf(stderr, "variable_substitution: variable_definitions empty\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; } | O_BRACE variable_definitions C_BRACE { @@ -258,7 +269,7 @@ variable_substitution: global_definitions fprintf(stderr, "variable_substitution:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; *sub_locals = '\0'; } | WORD O_BRACE variable_definitions C_BRACE @@ -272,7 +283,7 @@ variable_substitution: global_definitions fprintf(stderr, "variable_substitution:\n"); fprintf(stderr, " dbLoadRecords(%s)\n", sub_collect+1); #endif - dbLoadRecords(db_file_name, sub_collect+1); + if(msiLoadRecords(db_file_name, sub_collect+1)) YYABORT; dbmfFree($1); *sub_locals = '\0'; } @@ -328,6 +339,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) { FILE *fp; int i; + int err; line_num = 1; @@ -377,7 +389,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) yyrestart(fp); } - yyparse(); + err = yyparse(); for (i = 0; i < var_count; i++) { dbmfFree(vars[i]); @@ -390,5 +402,5 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) dbmfFree(db_file_name); db_file_name = NULL; } - return 0; + return err; } From e4ad4becde5ebe76b2251bef0fdfccd4fd1101ea Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 30 Sep 2023 18:03:40 -0700 Subject: [PATCH 16/36] rationalize osdMutex Avoids split allocation. Eliminates special case free-list. win32: eliminate pre-XP rtems-score: eliminate non-fast --- modules/libcom/src/misc/epicsExit.c | 4 - modules/libcom/src/osi/epicsMutex.cpp | 203 +++++------------- modules/libcom/src/osi/epicsMutex.h | 15 -- modules/libcom/src/osi/epicsMutexImpl.h | 66 ++++++ .../libcom/src/osi/os/RTEMS-score/osdEvent.c | 28 +-- .../libcom/src/osi/os/RTEMS-score/osdMutex.c | 139 +++++------- .../libcom/src/osi/os/RTEMS-score/osdThread.c | 41 ++-- .../src/osi/os/RTEMS-score/rtemsNamePvt.h | 20 ++ modules/libcom/src/osi/os/WIN32/osdMutex.c | 146 +++---------- modules/libcom/src/osi/os/posix/osdMutex.c | 80 +++---- modules/libcom/src/osi/os/vxWorks/osdMutex.c | 40 +++- modules/libcom/src/osi/os/vxWorks/osdMutex.h | 10 - 12 files changed, 306 insertions(+), 486 deletions(-) create mode 100644 modules/libcom/src/osi/epicsMutexImpl.h create mode 100644 modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h diff --git a/modules/libcom/src/misc/epicsExit.c b/modules/libcom/src/misc/epicsExit.c index 4e22fd81d..a7e1e4757 100644 --- a/modules/libcom/src/misc/epicsExit.c +++ b/modules/libcom/src/misc/epicsExit.c @@ -35,8 +35,6 @@ #include "cantProceed.h" #include "epicsExit.h" -void epicsMutexCleanup(void); - typedef struct exitNode { ELLNODE node; epicsExitFunc func; @@ -115,8 +113,6 @@ LIBCOM_API void epicsExitCallAtExits(void) epicsExitCallAtExitsPvt ( pep ); destroyExitPvt ( pep ); } - /* Handle specially to avoid circular reference */ - epicsMutexCleanup(); } LIBCOM_API void epicsExitCallAtThreadExits(void) diff --git a/modules/libcom/src/osi/epicsMutex.cpp b/modules/libcom/src/osi/epicsMutex.cpp index 0a63a6f33..a97de6067 100644 --- a/modules/libcom/src/osi/epicsMutex.cpp +++ b/modules/libcom/src/osi/epicsMutex.cpp @@ -26,30 +26,23 @@ #include #include +#include "dbDefs.h" #include "epicsStdio.h" #include "epicsThread.h" -#include "valgrind/valgrind.h" #include "ellLib.h" #include "errlog.h" #include "epicsMutex.h" +#include "epicsMutexImpl.h" #include "epicsThread.h" +#include "cantProceed.h" -static epicsThreadOnceId epicsMutexOsiOnce = EPICS_THREAD_ONCE_INIT; -static ELLLIST mutexList; -static ELLLIST freeList; - -struct epicsMutexParm { - ELLNODE node; - epicsMutexOSD * id; -# ifdef LOG_LAST_OWNER - epicsThreadId lastOwner; -# endif - const char *pFileName; - int lineno; -}; - -static epicsMutexOSD * epicsMutexGlobalLock; +static ELLLIST mutexList = ELLLIST_INIT; +/* Specially initialized to bootstrap initialization. + * When supported (posix and !rtems) use statically initiallized mutex. + * Otherwise, initialize via epicsMutexOsdSetup(). + */ +struct epicsMutexParm epicsMutexGlobalLock = {ELLNODE_INIT, __FILE__, __LINE__}; // vxWorks 5.4 gcc fails during compile when I use std::exception using namespace std; @@ -76,176 +69,82 @@ const char * epicsMutex::invalidMutex::what () const throw () return "epicsMutex::invalidMutex()"; } -static void epicsMutexOsiInit(void *) { - ellInit(&mutexList); - ellInit(&freeList); - VALGRIND_CREATE_MEMPOOL(&freeList, 0, 0); - epicsMutexGlobalLock = epicsMutexOsdCreate(); -} - epicsMutexId epicsStdCall epicsMutexOsiCreate( const char *pFileName,int lineno) { - epicsMutexOSD * id; + epicsMutexOsdSetup(); - epicsThreadOnce(&epicsMutexOsiOnce, epicsMutexOsiInit, NULL); + epicsMutexId ret = (epicsMutexId)calloc(1, sizeof(*ret)); + if(ret) { + ret->pFileName = pFileName; + ret->lineno = lineno; + + if(!epicsMutexOsdPrepare(ret)) { + epicsMutexMustLock(&epicsMutexGlobalLock); + ellAdd(&mutexList, &ret->node); + (void)epicsMutexUnlock(&epicsMutexGlobalLock); + + } else { + free(ret); + ret = NULL; + } - id = epicsMutexOsdCreate(); - if(!id) { - return 0; } - epicsMutexLockStatus lockStat = - epicsMutexOsdLock(epicsMutexGlobalLock); - assert ( lockStat == epicsMutexLockOK ); - epicsMutexParm *pmutexNode = - reinterpret_cast < epicsMutexParm * > ( ellFirst(&freeList) ); - if(pmutexNode) { - ellDelete(&freeList,&pmutexNode->node); - VALGRIND_MEMPOOL_FREE(&freeList, pmutexNode); - } else { - pmutexNode = static_cast < epicsMutexParm * > ( calloc(1,sizeof(epicsMutexParm)) ); - } - VALGRIND_MEMPOOL_ALLOC(&freeList, pmutexNode, sizeof(epicsMutexParm)); - pmutexNode->id = id; -# ifdef LOG_LAST_OWNER - pmutexNode->lastOwner = 0; -# endif - pmutexNode->pFileName = pFileName; - pmutexNode->lineno = lineno; - ellAdd(&mutexList,&pmutexNode->node); - epicsMutexOsdUnlock(epicsMutexGlobalLock); - return(pmutexNode); + return ret; } epicsMutexId epicsStdCall epicsMutexOsiMustCreate( const char *pFileName,int lineno) { epicsMutexId id = epicsMutexOsiCreate(pFileName,lineno); - assert(id); - return(id ); + if(!id) { + cantProceed("epicsMutexOsiMustCreate() fails at %s:%d\n", + pFileName, lineno); + } + return id; } void epicsStdCall epicsMutexDestroy(epicsMutexId pmutexNode) { - epicsMutexLockStatus lockStat = - epicsMutexOsdLock(epicsMutexGlobalLock); - assert ( lockStat == epicsMutexLockOK ); - ellDelete(&mutexList,&pmutexNode->node); - epicsMutexOsdDestroy(pmutexNode->id); - VALGRIND_MEMPOOL_FREE(&freeList, pmutexNode); - VALGRIND_MEMPOOL_ALLOC(&freeList, &pmutexNode->node, sizeof(pmutexNode->node)); - ellAdd(&freeList,&pmutexNode->node); - epicsMutexOsdUnlock(epicsMutexGlobalLock); -} - -void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode) -{ - epicsMutexOsdUnlock(pmutexNode->id); -} - -epicsMutexLockStatus epicsStdCall epicsMutexLock( - epicsMutexId pmutexNode) -{ - epicsMutexLockStatus status = - epicsMutexOsdLock(pmutexNode->id); -# ifdef LOG_LAST_OWNER - if ( status == epicsMutexLockOK ) { - pmutexNode->lastOwner = epicsThreadGetIdSelf(); - } -# endif - return status; -} - -epicsMutexLockStatus epicsStdCall epicsMutexTryLock( - epicsMutexId pmutexNode) -{ - epicsMutexLockStatus status = - epicsMutexOsdTryLock(pmutexNode->id); -# ifdef LOG_LAST_OWNER - if ( status == epicsMutexLockOK ) { - pmutexNode->lastOwner = epicsThreadGetIdSelf(); - } -# endif - return status; -} - -/* Empty the freeList. - * Called from epicsExit.c, but not via epicsAtExit() - * to avoid the possibility of a circular reference. - */ -extern "C" -void epicsMutexCleanup(void) -{ - ELLNODE *cur; - epicsMutexLockStatus lockStat = - epicsMutexOsdLock(epicsMutexGlobalLock); - assert ( lockStat == epicsMutexLockOK ); - - while((cur=ellGet(&freeList))!=NULL) { - VALGRIND_MEMPOOL_FREE(&freeList, cur); - free(cur); + if(pmutexNode) { + epicsMutexMustLock(&epicsMutexGlobalLock); + ellDelete(&mutexList, &pmutexNode->node); + (void)epicsMutexUnlock(&epicsMutexGlobalLock); + epicsMutexOsdCleanup(pmutexNode); + free(pmutexNode); } - - epicsMutexOsdUnlock(epicsMutexGlobalLock); } void epicsStdCall epicsMutexShow( epicsMutexId pmutexNode, unsigned int level) { -# ifdef LOG_LAST_OWNER - char threadName [255]; - if ( pmutexNode->lastOwner ) { -# error currently not safe to fetch name for stale thread - epicsThreadGetName ( pmutexNode->lastOwner, - threadName, sizeof ( threadName ) ); - } - else { - strcpy ( threadName, "" ); - } - printf("epicsMutexId %p last owner \"%s\" source %s line %d\n", - (void *)pmutexNode, threadName, - pmutexNode->pFileName, pmutexNode->lineno); -# else - printf("epicsMutexId %p source %s line %d\n", - (void *)pmutexNode, pmutexNode->pFileName, - pmutexNode->lineno); -# endif + printf("epicsMutexId %p source %s line %d\n", + (void *)pmutexNode, pmutexNode->pFileName, + pmutexNode->lineno); if ( level > 0 ) { - epicsMutexOsdShow(pmutexNode->id,level-1); + epicsMutexOsdShow(pmutexNode,level-1); } } void epicsStdCall epicsMutexShowAll(int onlyLocked,unsigned int level) { - epicsMutexParm *pmutexNode; + epicsMutexOsdSetup(); - if (epicsMutexOsiOnce == EPICS_THREAD_ONCE_INIT) - return; - - printf("ellCount(&mutexList) %d ellCount(&freeList) %d\n", - ellCount(&mutexList),ellCount(&freeList)); + printf("ellCount(&mutexList) %d\n", ellCount(&mutexList)); epicsMutexOsdShowAll(); - epicsMutexLockStatus lockStat = - epicsMutexOsdLock(epicsMutexGlobalLock); - assert ( lockStat == epicsMutexLockOK ); - pmutexNode = reinterpret_cast < epicsMutexParm * > ( ellFirst(&mutexList) ); - while(pmutexNode) { + epicsMutexMustLock(&epicsMutexGlobalLock); + for(ELLNODE *cur =ellFirst(&mutexList); cur; cur = ellNext(cur)) { + epicsMutexParm *lock = CONTAINER(cur, epicsMutexParm, node); if(onlyLocked) { - epicsMutexLockStatus status; - status = epicsMutexOsdTryLock(pmutexNode->id); - if(status==epicsMutexLockOK) { - epicsMutexOsdUnlock(pmutexNode->id); - pmutexNode = - reinterpret_cast < epicsMutexParm * > - ( ellNext(&pmutexNode->node) ); - continue; + // cycle through to test state + if(epicsMutexTryLock(lock)==epicsMutexLockOK) { + epicsMutexUnlock(lock); + continue; // was not locked, skip } } - epicsMutexShow(pmutexNode, level); - pmutexNode = - reinterpret_cast < epicsMutexParm * > ( ellNext(&pmutexNode->node) ); + epicsMutexShow(lock, level); } - epicsMutexOsdUnlock(epicsMutexGlobalLock); + epicsMutexUnlock(&epicsMutexGlobalLock); } #if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8) diff --git a/modules/libcom/src/osi/epicsMutex.h b/modules/libcom/src/osi/epicsMutex.h index 41f73a4bc..117767a48 100644 --- a/modules/libcom/src/osi/epicsMutex.h +++ b/modules/libcom/src/osi/epicsMutex.h @@ -247,21 +247,6 @@ LIBCOM_API void epicsStdCall epicsMutexShow( LIBCOM_API void epicsStdCall epicsMutexShowAll( int onlyLocked,unsigned int level); -/**@privatesection - * The following are interfaces to the OS dependent - * implementation and should NOT be called directly by - * user code. - */ -struct epicsMutexOSD * epicsMutexOsdCreate(void); -void epicsMutexOsdDestroy(struct epicsMutexOSD *); -void epicsMutexOsdUnlock(struct epicsMutexOSD *); -epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD *); -epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD *); -void epicsMutexOsdShow(struct epicsMutexOSD *,unsigned int level); -#ifdef EPICS_PRIVATE_API -void epicsMutexOsdShowAll(void); -#endif - #ifdef __cplusplus } #endif diff --git a/modules/libcom/src/osi/epicsMutexImpl.h b/modules/libcom/src/osi/epicsMutexImpl.h new file mode 100644 index 000000000..91079e8c5 --- /dev/null +++ b/modules/libcom/src/osi/epicsMutexImpl.h @@ -0,0 +1,66 @@ +/*************************************************************************\ +* Copyright (c) 2002 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. +* Copyright (c) 2023 Michael Davidsaver +* SPDX-License-Identifier: EPICS +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* Only include from osdMutex.c */ + +#ifndef epicsMutexImpl_H +#define epicsMutexImpl_H + +#if defined(vxWorks) +# include +# include +#elif defined(_WIN32) +# define VC_EXTRALEAN +# define WIN32_LEAN_AND_MEAN +# include +#elif defined(__rtems__) +# include +# include +#else +# include +#endif + +#include "ellLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct epicsMutexParm { + /* global list of mutex */ + ELLNODE node; + /* location where mutex was allocated */ + const char *pFileName; + int lineno; +#if defined(vxWorks) + SEM_ID osd; +#elif defined(_WIN32) + CRITICAL_SECTION osd; +#elif defined(__RTEMS_MAJOR__) && __RTEMS_MAJOR__<5 + Semaphore_Control *osd; +#else + pthread_mutex_t osd; +#endif +}; + +void epicsMutexOsdSetup(void); +long epicsMutexOsdPrepare(struct epicsMutexParm *); +void epicsMutexOsdCleanup(struct epicsMutexParm *); +void epicsMutexOsdShow(struct epicsMutexParm *,unsigned int level); +void epicsMutexOsdShowAll(void); + +extern struct epicsMutexParm epicsMutexGlobalLock; + +#ifdef __cplusplus +} // extern "C +#endif + +#endif // epicsMutexImpl_H diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c b/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c index 277e7882f..9c726ad59 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdEvent.c @@ -26,6 +26,7 @@ #include "epicsEvent.h" #include "epicsThread.h" +#include "rtemsNamePvt.h" #include "errlog.h" /* #define EPICS_RTEMS_SEMAPHORE_STATS */ @@ -47,12 +48,9 @@ epicsEventCreate(epicsEventInitialState initialState) { rtems_status_code sc; rtems_id sid; - rtems_interrupt_level level; - static char c1 = 'a'; - static char c2 = 'a'; - static char c3 = 'a'; + static uint32_t name; - sc = rtems_semaphore_create (rtems_build_name ('B', c3, c2, c1), + sc = rtems_semaphore_create (next_rtems_name ('B', &name), initialState, RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, @@ -62,26 +60,6 @@ epicsEventCreate(epicsEventInitialState initialState) errlogPrintf ("Can't create binary semaphore: %s\n", rtems_status_text (sc)); return NULL; } - rtems_interrupt_disable (level); - if (c1 == 'z') { - if (c2 == 'z') { - if (c3 == 'z') { - c3 = 'a'; - } - else { - c3++; - } - c2 = 'a'; - } - else { - c2++; - } - c1 = 'a'; - } - else { - c1++; - } - rtems_interrupt_enable (level); return (epicsEventId)sid; } diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c b/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c index 44adf2f6e..74fad8f81 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdMutex.c @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -26,97 +27,84 @@ #include "epicsStdio.h" #include "epicsMutex.h" +#include "epicsMutexImpl.h" +#include "rtemsNamePvt.h" #include "epicsEvent.h" #include "errlog.h" -#define RTEMS_FAST_MUTEX -/* #define EPICS_RTEMS_SEMAPHORE_STATS */ -/* - * Some performance tuning instrumentation - */ -#ifdef EPICS_RTEMS_SEMAPHORE_STATS -unsigned long semMstat[4]; -#define SEMSTAT(i) semMstat[i]++; -#else -#define SEMSTAT(i) -#endif +uint32_t next_rtems_name(char prefix, uint32_t* counter) +{ + uint32_t next; + rtems_interrupt_level level; + char a, b, c; -struct epicsMutexOSD * -epicsMutexOsdCreate(void) + rtems_interrupt_disable (level); + next = *counter; + *counter = (next+1)%(26u*26u*26u); + rtems_interrupt_enable (level); + + a = 'a' + (next % 26u); + next /= 26u; + b = 'a' + (next % 26u); + next /= 26u; + c = 'a' + (next % 26u); // modulo should be redundant, but ... paranoia + + return rtems_build_name(prefix, a, b, c); +} + +void epicsMutexOsdSetup(void) +{ + // TODO: use RTEMS_SYSINIT_ITEM() ? + if(!epicsMutexGlobalLock.osd) { + epicsMutexOsdPrepare(&epicsMutexGlobalLock); + } +} + +long epicsMutexOsdPrepare(struct epicsMutexParm *mutex) { rtems_status_code sc; rtems_id sid; rtems_interrupt_level level; - static char c1 = 'a'; - static char c2 = 'a'; - static char c3 = 'a'; + static uint32_t name; - sc = rtems_semaphore_create (rtems_build_name ('M', c3, c2, c1), + sc = rtems_semaphore_create (next_rtems_name ('M', &name), 1, RTEMS_PRIORITY|RTEMS_BINARY_SEMAPHORE|RTEMS_INHERIT_PRIORITY|RTEMS_NO_PRIORITY_CEILING|RTEMS_LOCAL, 0, &sid); if (sc != RTEMS_SUCCESSFUL) { errlogPrintf ("Can't create mutex semaphore: %s\n", rtems_status_text (sc)); - return NULL; + return ENOMEM; } - rtems_interrupt_disable (level); - if (c1 == 'z') { - if (c2 == 'z') { - if (c3 == 'z') { - c3 = 'a'; - } - else { - c3++; - } - c2 = 'a'; - } - else { - c2++; - } - c1 = 'a'; - } - else { - c1++; - } - rtems_interrupt_enable (level); -#ifdef RTEMS_FAST_MUTEX { - Semaphore_Control *the_semaphore; - Objects_Locations location; + Objects_Locations location; - the_semaphore = _Semaphore_Get( sid, &location ); - _Thread_Enable_dispatch(); + mutex->osd = _Semaphore_Get( sid, &location ); + _Thread_Enable_dispatch(); /* _Semaphore_Get() disables */ - return (struct epicsMutexOSD *)the_semaphore; + return 0; } -#endif - return (struct epicsMutexOSD *)sid; } -void epicsMutexOsdDestroy(struct epicsMutexOSD * id) +void epicsMutexOsdCleanup(struct epicsMutexParm *mutex) { rtems_status_code sc; rtems_id sid; -#ifdef RTEMS_FAST_MUTEX - Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + Semaphore_Control *the_semaphore = mutex->osd; sid = the_semaphore->Object.id; -#else - sid = (rtems_id)id; -#endif sc = rtems_semaphore_delete (sid); if (sc == RTEMS_RESOURCE_IN_USE) { rtems_semaphore_release (sid); sc = rtems_semaphore_delete (sid); } if (sc != RTEMS_SUCCESSFUL) - errlogPrintf ("Can't destroy semaphore %p (%lx): %s\n", id, (unsigned long)sid, rtems_status_text (sc)); + errlogPrintf ("Can't destroy semaphore %p (%lx): %s\n", + mutex, (unsigned long)sid, rtems_status_text (sc)); } -void epicsMutexOsdUnlock(struct epicsMutexOSD * id) +void epicsMutexUnlock(struct epicsMutexParm *mutex) { -#ifdef RTEMS_FAST_MUTEX - Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + Semaphore_Control *the_semaphore = mutex->osd; _Thread_Disable_dispatch(); _CORE_mutex_Surrender ( &the_semaphore->Core_control.mutex, @@ -124,18 +112,13 @@ void epicsMutexOsdUnlock(struct epicsMutexOSD * id) NULL ); _Thread_Enable_dispatch(); -#else - epicsEventSignal (id); -#endif } -epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * id) +epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm *mutex) { -#ifdef RTEMS_FAST_MUTEX - Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + Semaphore_Control *the_semaphore = mutex->osd; ISR_Level level; - SEMSTAT(0) _ISR_Disable( level ); _CORE_mutex_Seize( &the_semaphore->Core_control.mutex, @@ -148,19 +131,12 @@ epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * id) return epicsMutexLockOK; else return epicsMutexLockError; -#else - SEMSTAT(0) - return((epicsEventWait (id) == epicsEventWaitOK) - ?epicsMutexLockOK : epicsMutexLockError); -#endif } -epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id) +epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm *mutex) { -#ifdef RTEMS_FAST_MUTEX - Semaphore_Control *the_semaphore = (Semaphore_Control *)id; + Semaphore_Control *the_semaphore = mutex->osd; ISR_Level level; - SEMSTAT(2) _ISR_Disable( level ); _CORE_mutex_Seize( &the_semaphore->Core_control.mutex, @@ -175,25 +151,12 @@ epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id) return epicsMutexLockTimeout; else return epicsMutexLockError; -#else - epicsEventWaitStatus status; - SEMSTAT(2) - status = epicsEventTryWait(id); - return((status==epicsEventWaitOK - ? epicsMutexLockOK - : (status==epicsEventWaitTimeout) - ? epicsMutexLockTimeout - : epicsMutexLockError)); -#endif } -LIBCOM_API void epicsMutexOsdShow(struct epicsMutexOSD * id,unsigned int level) +LIBCOM_API void epicsMutexOsdShow(struct epicsMutexParm *mutex,unsigned int level) { -#ifdef RTEMS_FAST_MUTEX - Semaphore_Control *the_semaphore = (Semaphore_Control *)id; - id = (struct epicsMutexOSD *)the_semaphore->Object.id; -#endif - epicsEventShow ((epicsEventId)id,level); + Semaphore_Control *the_semaphore = mutex->osd; + epicsEventShow ((epicsEventId)the_semaphore->Object.id,level); } void epicsMutexOsdShowAll(void) {} diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdThread.c b/modules/libcom/src/osi/os/RTEMS-score/osdThread.c index 7d37bbe48..e34717a36 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdThread.c @@ -31,6 +31,7 @@ #include "epicsStdio.h" #include "errlog.h" #include "epicsMutex.h" +#include "epicsMutexImpl.h" #include "epicsString.h" #include "epicsThread.h" #include "cantProceed.h" @@ -59,7 +60,7 @@ struct taskVar { unsigned int threadVariableCapacity; void **threadVariables; }; -static struct epicsMutexOSD *taskVarMutex; +static struct epicsMutexParm taskVarMutex = {ELLNODE_INIT, __FILE__, __LINE__}; static struct taskVar *taskVarHead; #define RTEMS_NOTEPAD_TASKVAR 11 @@ -67,15 +68,7 @@ static struct taskVar *taskVarHead; * Support for `once-only' execution */ static volatile int initialized = 0; /* strictly speaking 'volatile' is not enough here, but it shouldn't hurt */ -static struct epicsMutexOSD *onceMutex; - -static -void epicsMutexOsdMustLock(struct epicsMutexOSD * L) -{ - while(epicsMutexOsdLock(L)!=epicsMutexLockOK) { - cantProceed("epicsThreadOnce() mutex error"); - } -} +static struct epicsMutexParm onceMutex = {ELLNODE_INIT, __FILE__, __LINE__}; /* * Just map osi 0 to 99 into RTEMS 199 to 100 @@ -161,13 +154,13 @@ epicsThreadGetStackSize (epicsThreadStackSizeClass size) static void taskVarLock (void) { - epicsMutexOsdMustLock (taskVarMutex); + epicsMutexMustLock (&taskVarMutex); } static void taskVarUnlock (void) { - epicsMutexOsdUnlock (taskVarMutex); + epicsMutexUnlock (&taskVarMutex); } static @@ -243,7 +236,7 @@ setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr, v->threadVariables = NULL; v->isRunning = 1; if (joinable) { - char c[3]; + char c[3] = {0,0,0}; strncpy(c, v->name, 3); sc = rtems_barrier_create(rtems_build_name('~', c[0], c[1], c[2]), RTEMS_BARRIER_AUTOMATIC_RELEASE | RTEMS_LOCAL, @@ -288,10 +281,8 @@ epicsThreadInit (void) rtems_task_priority old; rtems_task_set_priority (RTEMS_SELF, epicsThreadGetOssPriorityValue(99), &old); - onceMutex = epicsMutexOsdCreate(); - taskVarMutex = epicsMutexOsdCreate(); - if (!onceMutex || !taskVarMutex) - cantProceed("epicsThreadInit() can't create global mutexes\n"); + epicsMutexOsdPrepare(&taskVarMutex); + epicsMutexOsdPrepare(&onceMutex); rtems_task_ident (RTEMS_SELF, 0, &tid); if(setThreadInfo (tid, "_main_", NULL, NULL, 0) != RTEMS_SUCCESSFUL) cantProceed("epicsThreadInit() unable to setup _main_"); @@ -317,7 +308,7 @@ epicsThreadCreateOpt ( unsigned int stackSize; rtems_id tid; rtems_status_code sc; - char c[4]; + char c[4] = {0,0,0,0}; if (!initialized) epicsThreadInit(); @@ -612,26 +603,26 @@ void epicsThreadOnce(epicsThreadOnceId *id, void(*func)(void *), void *arg) #define EPICS_THREAD_ONCE_DONE (epicsThreadId) 1 if (!initialized) epicsThreadInit(); - epicsMutexOsdMustLock(onceMutex); + epicsMutexMustLock(&onceMutex); if (*id != EPICS_THREAD_ONCE_DONE) { if (*id == EPICS_THREAD_ONCE_INIT) { /* first call */ *id = epicsThreadGetIdSelf(); /* mark active */ - epicsMutexOsdUnlock(onceMutex); + epicsMutexUnlock(&onceMutex); func(arg); - epicsMutexOsdMustLock(onceMutex); + epicsMutexMustLock(&onceMutex); *id = EPICS_THREAD_ONCE_DONE; /* mark done */ } else if (*id == epicsThreadGetIdSelf()) { - epicsMutexOsdUnlock(onceMutex); + epicsMutexUnlock(&onceMutex); cantProceed("Recursive epicsThreadOnce() initialization\n"); } else while (*id != EPICS_THREAD_ONCE_DONE) { /* Another thread is in the above func(arg) call. */ - epicsMutexOsdUnlock(onceMutex); + epicsMutexUnlock(&onceMutex); epicsThreadSleep(epicsThreadSleepQuantum()); - epicsMutexOsdMustLock(onceMutex); + epicsMutexMustLock(&onceMutex); } } - epicsMutexOsdUnlock(onceMutex); + epicsMutexUnlock(&onceMutex); } /* diff --git a/modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h b/modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h new file mode 100644 index 000000000..436728902 --- /dev/null +++ b/modules/libcom/src/osi/os/RTEMS-score/rtemsNamePvt.h @@ -0,0 +1,20 @@ +/*************************************************************************\ +* Copyright (c) 2023 Michael Davidsaver +* SPDX-License-Identifier: EPICS +* EPICS Base is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#ifndef RTEMSNAMEPVT_H +#define RTEMSNAMEPVT_H + +#include + +/* Compute rtems_build_name(prefix, A, B, C) where A, B, C are the letters a-z. + * eg. "Qaaa" + * + * 'counter' is incremented atomically during each call. + */ +uint32_t next_rtems_name(char prefix, uint32_t* counter); + +#endif // RTEMSNAMEPVT_H diff --git a/modules/libcom/src/osi/os/WIN32/osdMutex.c b/modules/libcom/src/osi/os/WIN32/osdMutex.c index b18e849f4..ce2c615eb 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMutex.c +++ b/modules/libcom/src/osi/os/WIN32/osdMutex.c @@ -20,147 +20,59 @@ #include #include -#define VC_EXTRALEAN -#define STRICT -#include -#if _WIN32_WINNT < 0x0501 -# error Minimum supported is Windows XP -#endif - #define EPICS_PRIVATE_API #include "libComAPI.h" #include "epicsMutex.h" +#include "epicsMutexImpl.h" +#include "epicsThread.h" #include "epicsAssert.h" #include "epicsStdio.h" -typedef struct epicsMutexOSD { - union { - HANDLE mutex; - CRITICAL_SECTION criticalSection; - } os; -} epicsMutexOSD; - -static BOOL thisIsNT = FALSE; -static LONG weHaveInitialized = 0; - -/* - * epicsMutexCreate () - */ -epicsMutexOSD * epicsMutexOsdCreate ( void ) +static epicsThreadOnceId epicsMutexOsdOnce = EPICS_THREAD_ONCE_INIT; +static void epicsMutexOsdInit(void* unused) { - epicsMutexOSD * pSem; - - if ( ! weHaveInitialized ) { - BOOL status; - OSVERSIONINFO osInfo; - osInfo.dwOSVersionInfoSize = sizeof ( OSVERSIONINFO ); - status = GetVersionEx ( & osInfo ); - thisIsNT = status && ( osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ); - weHaveInitialized = 1; - } - - pSem = malloc ( sizeof (*pSem) ); - if ( pSem ) { - if ( thisIsNT ) { - InitializeCriticalSection ( &pSem->os.criticalSection ); - } - else { - pSem->os.mutex = CreateMutex ( NULL, FALSE, NULL ); - if ( pSem->os.mutex == 0 ) { - free ( pSem ); - pSem = 0; - } - } - } - return pSem; + (void)unused; + InitializeCriticalSection(&epicsMutexGlobalLock.osd); } -/* - * epicsMutexOsdDestroy () - */ -void epicsMutexOsdDestroy ( epicsMutexOSD * pSem ) +void epicsMutexOsdSetup() { - if ( thisIsNT ) { - DeleteCriticalSection ( &pSem->os.criticalSection ); - } - else { - CloseHandle ( pSem->os.mutex ); - } - free ( pSem ); + epicsThreadOnce(&epicsMutexOsdOnce, &epicsMutexOsdInit, NULL); } -/* - * epicsMutexOsdUnlock () - */ -void epicsMutexOsdUnlock ( epicsMutexOSD * pSem ) +long epicsMutexOsdPrepare(struct epicsMutexParm *mutex) { - if ( thisIsNT ) { - LeaveCriticalSection ( &pSem->os.criticalSection ); - } - else { - BOOL success = ReleaseMutex ( pSem->os.mutex ); - assert ( success ); - } + InitializeCriticalSection(&mutex->osd); + return 0; } -/* - * epicsMutexOsdLock () - */ -epicsMutexLockStatus epicsMutexOsdLock ( epicsMutexOSD * pSem ) +void epicsMutexOsdCleanup(struct epicsMutexParm *mutex) { - if ( thisIsNT ) { - EnterCriticalSection ( &pSem->os.criticalSection ); - } - else { - DWORD status = WaitForSingleObject ( pSem->os.mutex, INFINITE ); - if ( status != WAIT_OBJECT_0 ) { - return epicsMutexLockError; - } - } + DeleteCriticalSection(&mutex->osd); +} + +void epicsStdCall epicsMutexUnlock ( struct epicsMutexParm *mutex ) +{ + LeaveCriticalSection ( &mutex->osd ); +} + +epicsMutexLockStatus epicsStdCall epicsMutexLock ( struct epicsMutexParm *mutex ) +{ + EnterCriticalSection ( &mutex->osd ); return epicsMutexLockOK; } -/* - * epicsMutexOsdTryLock () - */ -epicsMutexLockStatus epicsMutexOsdTryLock ( epicsMutexOSD * pSem ) +epicsMutexLockStatus epicsStdCall epicsMutexTryLock ( struct epicsMutexParm *mutex ) { - if ( thisIsNT ) { - if ( TryEnterCriticalSection ( &pSem->os.criticalSection ) ) { - return epicsMutexLockOK; - } - else { - return epicsMutexLockTimeout; - } - } - else { - DWORD status = WaitForSingleObject ( pSem->os.mutex, 0 ); - if ( status != WAIT_OBJECT_0 ) { - if (status == WAIT_TIMEOUT) { - return epicsMutexLockTimeout; - } - else { - return epicsMutexLockError; - } - } - } - return epicsMutexLockOK; + return TryEnterCriticalSection ( &mutex->osd ) ? epicsMutexLockOK : epicsMutexLockTimeout; } -/* - * epicsMutexOsdShow () - */ -void epicsMutexOsdShow ( epicsMutexOSD * pSem, unsigned level ) +void epicsMutexOsdShow ( struct epicsMutexParm *mutex, unsigned level ) { - if ( thisIsNT ) { - printf ("epicsMutex: win32 critical section at %p\n", - (void * ) & pSem->os.criticalSection ); - } - else { - printf ( "epicsMutex: win32 mutex at %p\n", - ( void * ) pSem->os.mutex ); - } + (void)level; + printf ("epicsMutex: win32 critical section at %p\n", + (void * ) & mutex->osd ); } void epicsMutexOsdShowAll(void) {} diff --git a/modules/libcom/src/osi/os/posix/osdMutex.c b/modules/libcom/src/osi/os/posix/osdMutex.c index 85040c5f4..4bd87cf88 100644 --- a/modules/libcom/src/osi/os/posix/osdMutex.c +++ b/modules/libcom/src/osi/os/posix/osdMutex.c @@ -25,14 +25,15 @@ #include #define EPICS_PRIVATE_API +#define epicsStdioStdStreams +#define epicsStdioStdPrintfEtc #include "epicsMutex.h" +#include "epicsMutexImpl.h" #include "osdPosixMutexPriv.h" #include "cantProceed.h" -#include "epicsTime.h" #include "errlog.h" #include "epicsStdio.h" -#include "epicsAssert.h" #define checkStatus(status,message) \ if((status)) { \ @@ -119,62 +120,62 @@ static int mutexLock(pthread_mutex_t *id) return status; } -typedef struct epicsMutexOSD { - pthread_mutex_t lock; -} epicsMutexOSD; +/* used if OS does not support statically allocated mutex */ +static pthread_once_t epicsMutexOsdOnce = PTHREAD_ONCE_INIT; -epicsMutexOSD * epicsMutexOsdCreate(void) { - epicsMutexOSD *pmutex; - int status; - - pmutex = calloc(1, sizeof(*pmutex)); - if(!pmutex) - return NULL; - - status = osdPosixMutexInit(&pmutex->lock, PTHREAD_MUTEX_RECURSIVE); - if (!status) - return pmutex; - - free(pmutex); - return NULL; +static void epicsMutexOsdInit(void) +{ + int ret = pthread_mutex_init(&epicsMutexGlobalLock.osd, NULL); + if(ret) { + /* something has gone wrong early. Not much can be done...*/ + fprintf(stderr, "osdMutex early init failure %d.\n", ret); + abort(); + } } -void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex) +void epicsMutexOsdSetup() { - int status; + int ret = pthread_once(&epicsMutexOsdOnce, &epicsMutexOsdInit); + if(ret) { + /* ditto...*/ + fprintf(stderr, "osdMutex early once failure %d.\n", ret); + abort(); + } +} - status = pthread_mutex_destroy(&pmutex->lock); +long epicsMutexOsdPrepare(struct epicsMutexParm *pmutex) { + return osdPosixMutexInit(&pmutex->osd, PTHREAD_MUTEX_RECURSIVE); +} + +void epicsMutexOsdCleanup(struct epicsMutexParm *pmutex) +{ + int status = pthread_mutex_destroy(&pmutex->osd); checkStatus(status, "pthread_mutex_destroy"); - free(pmutex); } -void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex) +void epicsMutexUnlock(struct epicsMutexParm * pmutex) { - int status; - - status = pthread_mutex_unlock(&pmutex->lock); + int status = pthread_mutex_unlock(&pmutex->osd); checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock"); } -epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * pmutex) +epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm * pmutex) { - int status; - - status = mutexLock(&pmutex->lock); + int status = mutexLock(&pmutex->osd); if (status == EINVAL) return epicsMutexLockError; if(status) { - errlogMessage("epicsMutex pthread_mutex_lock failed: error epicsMutexOsdLock\n"); + errlogMessage("epicsMutex pthread_mutex_lock failed: error epicsMutexLock\n"); return epicsMutexLockError; } return epicsMutexLockOK; } -epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex) +epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm * pmutex) { int status; if (!pmutex) return epicsMutexLockError; - status = pthread_mutex_trylock(&pmutex->lock); + status = pthread_mutex_trylock(&pmutex->osd); if (status == EINVAL) return epicsMutexLockError; if (status == EBUSY) return epicsMutexLockTimeout; if(status) { @@ -184,12 +185,13 @@ epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex) return epicsMutexLockOK; } -void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level) +void epicsMutexOsdShow(struct epicsMutexParm * pmutex, unsigned int level) { + (void)level; /* GLIBC w/ NTPL is passing the &lock.__data.__lock as the first argument (UADDR) * of the futex() syscall. __lock is at offset 0 of the enclosing structures. */ - printf(" pthread_mutex_t* uaddr=%p\n", &pmutex->lock); + epicsStdoutPrintf(" pthread_mutex_t* uaddr=%p\n", &pmutex->osd); } void epicsMutexOsdShowAll(void) @@ -198,11 +200,11 @@ void epicsMutexOsdShowAll(void) int proto = -1; int ret = pthread_mutexattr_getprotocol(&globalAttrRecursive, &proto); if(ret) { - printf("PI maybe not enabled: %d\n", ret); + epicsStdoutPrintf("PI maybe not enabled: %d\n", ret); } else { - printf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not"); + epicsStdoutPrintf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not"); } #else - printf("PI not supported\n"); + epicsStdoutPrintf("PI not supported\n"); #endif } diff --git a/modules/libcom/src/osi/os/vxWorks/osdMutex.c b/modules/libcom/src/osi/os/vxWorks/osdMutex.c index d772bf2dd..680f9e663 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMutex.c +++ b/modules/libcom/src/osi/os/vxWorks/osdMutex.c @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -23,30 +24,47 @@ int sysClkRateGet(void); #define EPICS_PRIVATE_API #include "epicsMutex.h" - -struct epicsMutexOSD * epicsMutexOsdCreate(void) +#include "epicsMutexImpl.h" + +void epicsMutexOsdSetup(void) { - return((struct epicsMutexOSD *) - semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY)); + if(!epicsMutexGlobalLock.osd) { + epicsMutexOsdPrepare(&epicsMutexGlobalLock); + } } -void epicsMutexOsdDestroy(struct epicsMutexOSD * id) +long epicsMutexOsdPrepare(struct epicsMutexParm *mutex) { - semDelete((SEM_ID)id); + mutex->osd = semMCreate(SEM_DELETE_SAFE|SEM_INVERSION_SAFE|SEM_Q_PRIORITY); + return mutex->osd ? 0 : ENOMEM; } -epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * id) +void epicsMutexOsdCleanup(struct epicsMutexParm *mutex) { - int status; - status = semTake((SEM_ID)id,NO_WAIT); + semDelete(mutex->osd); +} + +epicsMutexLockStatus epicsMutexLock(struct epicsMutexParm *mutex) +{ + return semTake(mutex->osd,WAIT_FOREVER)==OK ? epicsMutexLockOK : epicsMutexLockError; +} + +epicsMutexLockStatus epicsMutexTryLock(struct epicsMutexParm *mutex) +{ + int status = semTake(mutex->osd,NO_WAIT); if(status==OK) return(epicsMutexLockOK); if(errno==S_objLib_OBJ_UNAVAILABLE) return(epicsMutexLockTimeout); return(epicsMutexLockError); } -void epicsMutexOsdShow(struct epicsMutexOSD * id,unsigned int level) +void epicsMutexUnlock(struct epicsMutexParm *mutex) { - semShow((SEM_ID)id,level); + semGive(mutex->osd); +} + +void epicsMutexOsdShow(struct epicsMutexParm *mutex,unsigned int level) +{ + semShow(mutex->osd,level); } void epicsMutexOsdShowAll(void) {} diff --git a/modules/libcom/src/osi/os/vxWorks/osdMutex.h b/modules/libcom/src/osi/os/vxWorks/osdMutex.h index 2eb8b1ba2..f3f663622 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMutex.h +++ b/modules/libcom/src/osi/os/vxWorks/osdMutex.h @@ -13,13 +13,3 @@ #include #include - -/* If the macro is replaced by inline it is necessary to say - static __inline__ - but then a warning message appears everywhere osdMutex.h is included -*/ - -#define epicsMutexOsdUnlock(ID) semGive((SEM_ID)(ID)) - -#define epicsMutexOsdLock(ID) \ -(semTake((SEM_ID)(ID),WAIT_FOREVER)==OK ? epicsMutexLockOK : epicsMutexLockError) From 065fe7cab62bc6b88e32e61e022e910554b05c7f Mon Sep 17 00:00:00 2001 From: Timo Korhonen Date: Wed, 29 Jan 2025 00:05:55 +0100 Subject: [PATCH 17/36] Fix internal link --- modules/database/src/std/rec/aiRecord.dbd.pod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/src/std/rec/aiRecord.dbd.pod b/modules/database/src/std/rec/aiRecord.dbd.pod index 4515368b2..83a7c5c26 100644 --- a/modules/database/src/std/rec/aiRecord.dbd.pod +++ b/modules/database/src/std/rec/aiRecord.dbd.pod @@ -33,7 +33,7 @@ These fields control where the record will read data from when it is processed: The DTYP field selects which device support layer should be responsible for providing input data to the record. The ai device support layers provided by EPICS Base are documented in the -L section. +L section. External support modules may provide additional device support for this record type. If not set explicitly, the DTYP value defaults to the first device support that From dad0ee9c8911ef8e498ad30468bc43eacd5c4cc1 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 26 Jun 2024 11:45:26 -0500 Subject: [PATCH 18/36] Revert "Limit _FORTIFY_SOURCE <= 2" This reverts commit 5fe563bed8c9031c686d2d45559ef2ecf4a9357e. --- configure/toolchain.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/configure/toolchain.c b/configure/toolchain.c index af03f5246..0a5276045 100644 --- a/configure/toolchain.c +++ b/configure/toolchain.c @@ -64,7 +64,3 @@ COMMANDLINE_LIBRARY ?= EPICS #else COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS)) #endif - -#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE>2 -OP_SYS_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -#endif From 6fb40b02fe393f7bdac8bfbf2e1fbf6e50a0cd95 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 2 Feb 2025 20:16:38 -0800 Subject: [PATCH 19/36] update RELEASE_NOTES --- documentation/RELEASE_NOTES.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 19ca5559c..8130baa6c 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -84,6 +84,35 @@ For example this will remove the record named "unwanted": record("#", "unwanted") { } ``` +### Only keep readline history for interactive sessions + +Previously, all IOCsh commands were persisited in the libreadline history +(when readline support is included). +Going forward, only interactive commands are saved. + +### Type change to asTrap serverSpecific data + +Change `void*` to `dbChannel*` in `asTrapWriteBeforeWithData()` and +`asTrapWriteMessage::serverSpecific` to reflect the reality since +the `dbAddr*` to `dbChannel*` migration. +External code wishing to support both before and after 3.15 should +already be conditionally casting to/from the appropriate type. + +### Fix issues with `_FORTIFY_SOURCE=3` + +This release fixes the false positives failures whhen building with `_FORTIFY_SOURCE` level 3. +The override introduced with `7.0.8.1` is removed. + +### Other + +- genVersionHeader: work with git submodules and worktrees. +- avoid UB with self `pthread_join()` +- freebsd: Add support for x86 and amd64 builds +- Clear AMSG when SEVR becomes zero. +- `seqRecord` fix support for link `DLY0` +- Add `ABORT_ON_ASSERT` flag to `CONFIG_SITE_ENV` +- rationalize osdMutex + ## EPICS Release 7.0.8.1 ### Limit to `_FORTIFY_SOURCE=2` From c8eccfcb8ffcba80c7464982c3e6abbc9716d029 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 3 Feb 2025 11:36:37 -0600 Subject: [PATCH 20/36] Edit Release messages for English & Markdown --- documentation/RELEASE_NOTES.md | 46 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 8130baa6c..48623d7f8 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -30,18 +30,18 @@ STAT. Links with MS or MSI attributes do not propagate STAT, and therefore do not propagate AMSG, either. Channel Access links do not propagate AMSG, regardless of the MSS attribute, -because the message is not available over Channel Access. +because the message is not available as Channel metadata. -### Allow to load the same alias multiple times +### Reloading record aliases -Aliases can now be defined multiple times as long as they still refer to the -same record, unless the shell variable dbRecordsOnceOnly is set. -This allows to load database files multiple times, even if they contain +Aliases can now be defined more than once as long as they still refer to the +same record, unless the global variable `dbRecordsOnceOnly` is non-zero. +This allows database files to be loaded multiple times, even if they contain alias definitions. -### DBE_PROPERTY event rate changed +### `DBE_PROPERTY` event rate changed -Updating property fields now only post DBE_PROPERTY events if the +Updating property fields now only posts `DBE_PROPERTY` events if the field actually changed. ### Changes to msi related to include paths @@ -74,14 +74,14 @@ From this release, record instances and aliases that have already been loaded by an IOC can be removed from the database again before the call to iocInit by loading a second instance of the named records but using `"#"` in place of the record type. Values for the fields are not required or advised, just use -an empty record body { }. This is useful when a template defines records that +an empty record body `{}`. This is useful when a template defines records that are not wanted in some IOCs, without having to split or duplicate the original template. For example this will remove the record named "unwanted": ``` -record("#", "unwanted") { } +record("#", "unwanted") {} ``` ### Only keep readline history for interactive sessions @@ -428,10 +428,10 @@ changed to `(p)->dtor`. The order over operations when processing a waveformRecord is adjusted so that updates to NORD is posted with the correct timestamp. -### Automatic COMMANDLINE_LIBRARY w/ newer compilers +### Automatic `COMMANDLINE_LIBRARY` with newer compilers When built with a compiler supporting `__has_include<>`, the presence -of the `` will be used to automatically determine +of a `readline/readline.h` header will be used to automatically determine a default value for `COMMANDLINE_LIBRARY`. Mingw builds with readline support now link `-ltermcap` instead of `-lcurses`. @@ -676,7 +676,7 @@ These target architectures have been removed: + darwin-ppc, darwin-ppcx86 + linux-386, linux-486, linux-586, linux-686, linux-athlon (cross-build) -+ linux-cris, linux-cris_v10, linux-cris_v32 (cross-build) ++ linux-cris, linux-cris\_v10, linux-cris\_v32 (cross-build) + RTEMS-at91rm9200ek, RTEMS-gen68360, RTEMS-mcp750, RTEMS-mvme167, RTEMS-psim (cross-build) @@ -694,9 +694,9 @@ running on RTEMS 5: - RTEMS-beagleboneblack - RTEMS-pc686 -- RTEMS-qoriq_e500 (MVME2500) -- RTEMS-xilinx_zynq_a9_qemu -- RTEMS-xilinx_zynq_zedboard +- RTEMS-qoriq\_e500 (MVME2500) +- RTEMS-xilinx\_zynq\_a9\_qemu +- RTEMS-xilinx\_zynq\_zedboard The EPICS support for RTEMS 4 has always relied on RTEMS-specific kernel APIs which cannot be used on an SMP system, so a new port was @@ -708,7 +708,7 @@ to run `make distclean` if switching a single source tree from one to the other (both header files and dependency files are different between the two and must be cleaned out). -The configuration variable RTEMS_VERSION in the EPICS config file +The configuration variable `RTEMS_VERSION` in the EPICS config file `configure/os/CONFIG_SITE.Common.RTEMS` must be set to the full 3- part version number for RTEMS 4 releases, e.g. `4.9.1`, `4.10.2` but for RTEMS 5.1 and later it must only contain the major version @@ -943,7 +943,7 @@ compile device supports as loadable modules. ### Priority inversion safe Posix mutexes On Posix systems, epicsMutex now support priority inheritance if available. -The IOC needs to run with SCHED_FIFO engaged to use these. +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. @@ -1076,14 +1076,14 @@ properly handle zero-length arrays. The `caget`, `caput` and `camonitor` client programs are known to work with empty arrays as long as they were built with this or a later version of EPICS. -#### Change to the db_access.h `dbr_size_n(TYPE, COUNT)` macro +#### Change to the db\_access.h `dbr_size_n(TYPE, COUNT)` macro When called with COUNT=0 this macro no longer returns the number of bytes required for a scalar (1 element) but for an empty array (0 elements). Make sure code that uses this doesn't call it with COUNT=0 when it really means COUNT=1. -Note that the db_access.h header file is included by cadef.h so the change +Note that the db\_access.h header file is included by cadef.h so the change can impact Channel Access client programs that use this macro. #### Channel Access support for zero-length arrays @@ -1258,7 +1258,7 @@ The following launchpad bugs have fixes included in this release: operators on aarch64 - [lp: 1853148](https://bugs.launchpad.net/bugs/1853148), mingw compiler problem with printf/scanf formats -- [lp: 1852653](https://bugs.launchpad.net/bugs/1852653), USE_TYPED_DSET +- [lp: 1852653](https://bugs.launchpad.net/bugs/1852653), `USE_TYPED_DSET` incompatible with C++ - [lp: 1862328](https://bugs.launchpad.net/bugs/1862328), Race condition on IOC start leaves rsrv unresponsive @@ -1268,7 +1268,7 @@ The following launchpad bugs have fixes included in this release: - [lp: 1868680](https://bugs.launchpad.net/bugs/1868680), Access Security file reload (asInit) fails -### \*_API macros in EPICS headers +### `*_API` macros in EPICS headers Internally, the Com and ca libraries now express dllimport/export (Windows) and symbol visibility (GCC) using library-specific macros (eg. `LIBCOM_API`) @@ -1502,7 +1502,7 @@ The API functions `epicsGetExecDir()` and `epicsGetExecName()` are also added to `osiFileName.h` to provide runtime access to the directory or filename of the executable with which the process was started. -### Decouple LINKER_USE_RPATH and STATIC_BUILD +### Decouple `LINKER_USE_RPATH` and `STATIC_BUILD` Previously, setting `STATIC_BUILD=NO` implied `LINKER_USE_RPATH=NO`. This is no longer the case. Setting `LINKER_USE_RPATH=YES` will @@ -2081,7 +2081,7 @@ number instead, like this: Channel Access does not (and probably never will) directly support 64-bit integer types, so the new field types are presented to the CA server as `DBF_DOUBLE` values. This means that field values larger than 2^52 -(0x10_0000_0000_0000 = 4503599627370496) cannot be transported over Channel +(0x10\_0000\_0000\_0000 = 4503599627370496) cannot be transported over Channel Access without their least significant bits being truncated. The EPICS V4 pvAccess network protocol _can_ transport 64-bit data types however, and a future release of the pvaSrv module will connect this ability to the fields of From 0d2ffcd97f58abed4716cbe5483f5d8c319fd196 Mon Sep 17 00:00:00 2001 From: Simon Rose <58027931+simon-ess@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:47:24 +0100 Subject: [PATCH 21/36] Typo fix on arch name (#593) --- configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug b/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug index 21db17445..25d27b996 100644 --- a/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug +++ b/configure/os/CONFIG.darwin-aarch64.darwin-aarch64-debug @@ -6,7 +6,7 @@ -include $(CONFIG)/os/CONFIG.Common.darwin-aarch64 -include $(CONFIG)/os/CONFIG.darwin-aarch64.darwin-aarch64 --include $(CONFIG)/os/CONFIG_SITE.Common.darwin-aarch46 +-include $(CONFIG)/os/CONFIG_SITE.Common.darwin-aarch64 -include $(CONFIG)/os/CONFIG_SITE.darwin-aarch64.darwin-aarch64 From 8ac2c871563fefc07e757c099ae35a82a00148db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Tue, 7 Jan 2025 19:47:50 -0300 Subject: [PATCH 22/36] Post monitors from compress record when resetting it This way clients receive updates with an empty array after writing into the RES field. --- documentation/RELEASE_NOTES.md | 5 +++++ modules/database/src/std/rec/compressRecord.c | 1 + 2 files changed, 6 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 48623d7f8..ce4088385 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,6 +22,11 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.8.1 +### Post monitors from compress record when it's reset + +Writing into a compress record's `RES` field now posts a monitor event instead +of only changing `VAL`. Monitor clients will therefore receive an empty array. + ### The AMSG error message propagates through MSS links A database link with the MSS attribute will now propagate not only SEVR and diff --git a/modules/database/src/std/rec/compressRecord.c b/modules/database/src/std/rec/compressRecord.c index 22e804915..844172bf8 100644 --- a/modules/database/src/std/rec/compressRecord.c +++ b/modules/database/src/std/rec/compressRecord.c @@ -384,6 +384,7 @@ static long special(DBADDR *paddr, int after) if (special_type == SPC_RESET) { reset(prec); + monitor(prec); return 0; } From 48eed22f3b84d7f3fb14a36cf8bdc4b2d60d3e6d Mon Sep 17 00:00:00 2001 From: DW Date: Fri, 20 Sep 2024 12:38:10 +0900 Subject: [PATCH 23/36] check IOCSH_STARTUP_SCRIPT before set --- modules/libcom/src/iocsh/iocsh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 1e1cf1cd0..ae013f8a0 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -1325,7 +1325,7 @@ iocshCmd (const char *cmd) int epicsStdCall iocshLoad(const char *pathname, const char *macros) { - if (pathname) + if (pathname && !getenv("IOCSH_STARTUP_SCRIPT")) epicsEnvSet("IOCSH_STARTUP_SCRIPT", pathname); return iocshBody(pathname, NULL, macros); } From 144f9756eac4e800f18d3d9a35f0d42a712614fd Mon Sep 17 00:00:00 2001 From: JJL772 Date: Thu, 13 Jun 2024 07:12:01 -0400 Subject: [PATCH 24/36] Add iocshSetError in a bunch of places --- modules/database/src/ioc/db/dbIocRegister.c | 87 ++++++++++--------- .../src/ioc/dbStatic/dbStaticIocRegister.c | 2 +- modules/database/src/ioc/misc/dlload.c | 6 +- modules/libcom/RTEMS/posix/rtems_init.c | 26 ++++-- modules/libcom/RTEMS/score/rtems_init.c | 23 +++-- modules/libcom/src/iocsh/libComRegister.c | 13 ++- 6 files changed, 98 insertions(+), 59 deletions(-) diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c index 83a2c9114..9b5085ea0 100644 --- a/modules/database/src/ioc/db/dbIocRegister.c +++ b/modules/database/src/ioc/db/dbIocRegister.c @@ -75,21 +75,21 @@ static const iocshFuncDef dbbFuncDef = {"dbb",1,dbbArgs, "Set Breakpoint on a record\n" "This command spawns one breakpoint continuation task per lockset," " in which further record execution is run\n"}; -static void dbbCallFunc(const iocshArgBuf *args) { dbb(args[0].sval);} +static void dbbCallFunc(const iocshArgBuf *args) { iocshSetError(dbb(args[0].sval));} /* dbd */ static const iocshArg dbdArg0 = { "record name",iocshArgStringRecord}; static const iocshArg * const dbdArgs[1] = {&dbdArg0}; static const iocshFuncDef dbdFuncDef = {"dbd",1,dbdArgs, "Remove breakpoint from a record.\n"}; -static void dbdCallFunc(const iocshArgBuf *args) { dbd(args[0].sval);} +static void dbdCallFunc(const iocshArgBuf *args) { iocshSetError(dbd(args[0].sval));} /* dbc */ static const iocshArg dbcArg0 = { "record name",iocshArgStringRecord}; static const iocshArg * const dbcArgs[1] = {&dbcArg0}; static const iocshFuncDef dbcFuncDef = {"dbc",1,dbcArgs, "Continue processing in a lockset until next breakpoint is found.\n"}; -static void dbcCallFunc(const iocshArgBuf *args) { dbc(args[0].sval);} +static void dbcCallFunc(const iocshArgBuf *args) { iocshSetError(dbc(args[0].sval));} /* dbs */ static const iocshArg dbsArg0 = { "record name",iocshArgStringRecord}; @@ -97,12 +97,12 @@ static const iocshArg * const dbsArgs[1] = {&dbsArg0}; static const iocshFuncDef dbsFuncDef = {"dbs",1,dbsArgs, "Step through record processing within a lockset.\n" "If called without an argument, automatically steps with the last breakpoint.\n"}; -static void dbsCallFunc(const iocshArgBuf *args) { dbs(args[0].sval);} +static void dbsCallFunc(const iocshArgBuf *args) { iocshSetError(dbs(args[0].sval));} /* dbstat */ static const iocshFuncDef dbstatFuncDef = {"dbstat",0,0, "Print list of suspended records, and breakpoints set in locksets.\n"}; -static void dbstatCallFunc(const iocshArgBuf *args) { dbstat();} +static void dbstatCallFunc(const iocshArgBuf *args) { iocshSetError(dbstat());} /* dbp */ static const iocshArg dbpArg0 = { "record name",iocshArgStringRecord}; @@ -119,7 +119,9 @@ static const iocshFuncDef dbpFuncDef = { " 3 - Fields of minor interest to a System developer.\n" " 4 - Internal record fields.\n"}; static void dbpCallFunc(const iocshArgBuf *args) -{ dbp(args[0].sval,args[1].ival);} +{ + iocshSetError(dbp(args[0].sval,args[1].ival)); +} /* dbap */ static const iocshArg dbapArg0 = { "record name",iocshArgStringRecord}; @@ -127,7 +129,7 @@ static const iocshArg * const dbapArgs[1] = {&dbapArg0}; static const iocshFuncDef dbapFuncDef = {"dbap",1,dbapArgs, "Auto Print.\n" "Toggle automatic printing after processing a record that has a breakpoint.\n"}; -static void dbapCallFunc(const iocshArgBuf *args) { dbap(args[0].sval);} +static void dbapCallFunc(const iocshArgBuf *args) { iocshSetError(dbap(args[0].sval));} /* dbsr */ static const iocshArg dbsrArg0 = { "interest level",iocshArgInt}; @@ -150,7 +152,7 @@ static const iocshFuncDef dbcarFuncDef = {"dbcar",2,dbcarArgs, " 2 - Shows info. for all links.\n"}; static void dbcarCallFunc(const iocshArgBuf *args) { - dbcar(args[0].sval,args[1].ival); + iocshSetError(dbcar(args[0].sval,args[1].ival)); } /* dbjlr */ @@ -162,7 +164,7 @@ static const iocshFuncDef dbjlrFuncDef = {"dbjlr",2,dbjlrArgs, "List all JSON links in a record. If no record is specified, print for all\n"}; static void dbjlrCallFunc(const iocshArgBuf *args) { - dbjlr(args[0].sval,args[1].ival); + iocshSetError(dbjlr(args[0].sval,args[1].ival)); } /* dbel */ @@ -176,7 +178,7 @@ static const iocshFuncDef dbelFuncDef = {"dbel",2,dbelArgs, "Example: dbel aitest 2\n"}; static void dbelCallFunc(const iocshArgBuf *args) { - dbel(args[0].sval, args[1].ival); + iocshSetError(dbel(args[0].sval, args[1].ival)); } /* dba */ @@ -187,7 +189,7 @@ static const iocshFuncDef dbaFuncDef = {"dba",1,dbaArgs, "Print information in the dbAddr structure for a specific field.\n" "If no field is specified, VAL is assumed.\n\n" "Example: dba(\"aitest.HIGH\")\n"}; -static void dbaCallFunc(const iocshArgBuf *args) { dba(args[0].sval);} +static void dbaCallFunc(const iocshArgBuf *args) { iocshSetError(dba(args[0].sval));} /* dbl */ static const iocshArg dblArg0 = { "record type",iocshArgString}; @@ -204,7 +206,7 @@ static const iocshFuncDef dblFuncDef = {"dbl",2,dblArgs, " dbl(\"ai\",\"HIGH LOW VAL PREC\")\n"}; static void dblCallFunc(const iocshArgBuf *args) { - dbl(args[0].sval,args[1].sval); + iocshSetError(dbl(args[0].sval,args[1].sval)); } /* dbnr */ @@ -213,7 +215,7 @@ static const iocshArg * const dbnrArgs[1] = {&dbnrArg0}; static const iocshFuncDef dbnrFuncDef = {"dbnr",1,dbnrArgs, "List number of records and aliases by type.\n" "If verbose, list all record types regardless of being instanced\n"}; -static void dbnrCallFunc(const iocshArgBuf *args) { dbnr(args[0].ival);} +static void dbnrCallFunc(const iocshArgBuf *args) { iocshSetError(dbnr(args[0].ival));} /* dbli */ static const iocshArg dbliArg0 = { "pattern",iocshArgString}; @@ -221,7 +223,7 @@ static const iocshArg * const dbliArgs[1] = {&dbliArg0}; static const iocshFuncDef dbliFuncDef = {"dbli",1,dbliArgs, "List info() tags with names matching pattern.\n\n" "Example: dbli(\"autosave*\")\n"}; -static void dbliCallFunc(const iocshArgBuf *args) { dbli(args[0].sval);} +static void dbliCallFunc(const iocshArgBuf *args) { iocshSetError(dbli(args[0].sval));} /* dbla */ static const iocshArg dblaArg0 = { "pattern",iocshArgStringRecord}; @@ -229,7 +231,7 @@ static const iocshArg * const dblaArgs[1] = {&dblaArg0}; static const iocshFuncDef dblaFuncDef = {"dbla",1,dblaArgs, "List record alias()s by alias name pattern.\n\n" "Example: dbla(\"alia*\")\n"}; -static void dblaCallFunc(const iocshArgBuf *args) { dbla(args[0].sval);} +static void dblaCallFunc(const iocshArgBuf *args) { iocshSetError(dbla(args[0].sval));} /* dbgrep */ static const iocshArg dbgrepArg0 = { "pattern",iocshArgStringRecord}; @@ -240,7 +242,7 @@ static const iocshFuncDef dbgrepFuncDef = {"dbgrep",1,dbgrepArgs, " - \"?\", which matches 0 or one characters.\n" " - \"*\", which matches 0 or more characters.\n\n" "Example: dbgrep(\"*gpibAi*\")\n"}; -static void dbgrepCallFunc(const iocshArgBuf *args) { dbgrep(args[0].sval);} +static void dbgrepCallFunc(const iocshArgBuf *args) { iocshSetError(dbgrep(args[0].sval));} /* dbgf */ static const iocshArg dbgfArg0 = { "record name",iocshArgStringRecord}; @@ -250,7 +252,7 @@ static const iocshFuncDef dbgfFuncDef = {"dbgf",1,dbgfArgs, "Print current value of record field.\n" "If no field name is specified, VAL is assumed.\n\n" "Example: dbgf(\"aitest.VAL\")\n"}; -static void dbgfCallFunc(const iocshArgBuf *args) { dbgf(args[0].sval);} +static void dbgfCallFunc(const iocshArgBuf *args) { iocshSetError(dbgf(args[0].sval));} /* dbpf */ static const iocshArg dbpfArg0 = { "record name",iocshArgStringRecord}; @@ -261,7 +263,7 @@ static const iocshFuncDef dbpfFuncDef = {"dbpf",2,dbpfArgs, "Change value of record field and read it back with dbgf.\n" "If no field is specified, VAL is assumed\n"}; static void dbpfCallFunc(const iocshArgBuf *args) -{ dbpf(args[0].sval,args[1].sval);} +{ iocshSetError(dbpf(args[0].sval,args[1].sval));} /* dbpr */ static const iocshArg dbprArg0 = { "record name",iocshArgStringRecord}; @@ -279,14 +281,14 @@ static const iocshFuncDef dbprFuncDef = { "Example: dbpr aitest 3\n" }; static void dbprCallFunc(const iocshArgBuf *args) -{ dbpr(args[0].sval,args[1].ival);} +{ iocshSetError(dbpr(args[0].sval,args[1].ival));} /* dbtr */ static const iocshArg dbtrArg0 = { "record name",iocshArgStringRecord}; static const iocshArg * const dbtrArgs[1] = {&dbtrArg0}; static const iocshFuncDef dbtrFuncDef = {"dbtr",1,dbtrArgs, "Process record and then some fields.\n"}; -static void dbtrCallFunc(const iocshArgBuf *args) { dbtr(args[0].sval);} +static void dbtrCallFunc(const iocshArgBuf *args) { iocshSetError(dbtr(args[0].sval));} /* dbtgf */ static const iocshArg dbtgfArg0 = { "record name",iocshArgStringRecord}; @@ -296,7 +298,7 @@ static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs, "Get and print the specified field with all possible DBR_* types\n" "Example: dbtgf aitest\n" "Example: dbtgf aitest.VAL\n"}; -static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);} +static void dbtgfCallFunc(const iocshArgBuf *args) { iocshSetError(dbtgf(args[0].sval));} /* dbtpf */ static const iocshArg dbtpfArg0 = { "record name",iocshArgStringRecord}; @@ -308,7 +310,7 @@ static const iocshFuncDef dbtpfFuncDef = {"dbtpf",2,dbtpfArgs, "for all possible DBR_* types\n\n" "Example: dbtpf aitest 5.0\n"}; static void dbtpfCallFunc(const iocshArgBuf *args) -{ dbtpf(args[0].sval,args[1].sval);} +{ iocshSetError(dbtpf(args[0].sval,args[1].sval));} /* dbior */ static const iocshArg dbiorArg0 = { "driver name",iocshArgString}; @@ -317,7 +319,7 @@ static const iocshArg * const dbiorArgs[] = {&dbiorArg0,&dbiorArg1}; static const iocshFuncDef dbiorFuncDef = {"dbior",2,dbiorArgs, "Driver Report.\n"}; static void dbiorCallFunc(const iocshArgBuf *args) -{ dbior(args[0].sval,args[1].ival);} +{ iocshSetError(dbior(args[0].sval,args[1].ival));} /* dbhcr */ static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0, @@ -327,7 +329,7 @@ static const iocshFuncDef dbhcrFuncDef = {"dbhcr",0,0, "Use the UNIX sort command:\n" "dbhcr > report\n" "sort report > report.sorted\n"}; -static void dbhcrCallFunc(const iocshArgBuf *args) { dbhcr();} +static void dbhcrCallFunc(const iocshArgBuf *args) { iocshSetError(dbhcr());} /* gft */ static const iocshArg gftArg0 = { "record name",iocshArgStringRecord}; @@ -336,7 +338,7 @@ static const iocshFuncDef gftFuncDef = {"gft",1,gftArgs, "Report dbChannel info and value.\n" "Example: gft aitest\n" "Example: gft aitest.VAL\n"}; -static void gftCallFunc(const iocshArgBuf *args) { gft(args[0].sval);} +static void gftCallFunc(const iocshArgBuf *args) { iocshSetError(gft(args[0].sval));} /* pft */ static const iocshArg pftArg0 = { "record name",iocshArgStringRecord}; @@ -346,7 +348,7 @@ static const iocshFuncDef pftFuncDef = {"pft",2,pftArgs, "dbChannel put value.\n" "Example: pft aitest 5.0\n"}; static void pftCallFunc(const iocshArgBuf *args) -{ pft(args[0].sval,args[1].sval);} +{ iocshSetError(pft(args[0].sval,args[1].sval));} /* dbtpn */ static const iocshArg dbtpnArg0 = { "record name",iocshArgStringRecord}; @@ -359,12 +361,12 @@ static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs, "Example: dbtpn aitest\n" "Example: dbtpn aitest 5.0\n"}; static void dbtpnCallFunc(const iocshArgBuf *args) -{ dbtpn(args[0].sval,args[1].sval);} +{ iocshSetError(dbtpn(args[0].sval,args[1].sval));} /* dbNotifyDump */ static const iocshFuncDef dbNotifyDumpFuncDef = {"dbNotifyDump",0,0, "Report status of any active async processing with completion notification.\n"}; -static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { dbNotifyDump();} +static void dbNotifyDumpCallFunc(const iocshArgBuf *args) { iocshSetError(dbNotifyDump());} /* dbPutAttribute */ static const iocshArg dbPutAttrArg0 = { "record type",iocshArgString}; @@ -375,7 +377,7 @@ static const iocshArg * const dbPutAttrArgs[] = static const iocshFuncDef dbPutAttrFuncDef = {"dbPutAttribute",3,dbPutAttrArgs, "Set/Create record attribute.\n"}; static void dbPutAttrCallFunc(const iocshArgBuf *args) -{ dbPutAttribute(args[0].sval,args[1].sval,args[2].sval);} +{ iocshSetError(dbPutAttribute(args[0].sval,args[1].sval,args[2].sval));} /* tpn */ static const iocshArg tpnArg0 = { "record name",iocshArgStringRecord}; @@ -385,7 +387,7 @@ static const iocshFuncDef tpnFuncDef = {"tpn",2,tpnArgs, "Test Process Notify.\n\n" "Example: tpn aitest 5.0\n"}; static void tpnCallFunc(const iocshArgBuf *args) -{ tpn(args[0].sval,args[1].sval);} +{ iocshSetError(tpn(args[0].sval,args[1].sval));} /* dblsr */ static const iocshArg dblsrArg0 = { "record name",iocshArgStringRecord}; @@ -399,7 +401,7 @@ static const iocshFuncDef dblsrFuncDef = {"dblsr",2,dblsrArgs, " 2 - Show each record and all database links in the lock set.\n\n" "Example: dblsr aitest 2\n"}; static void dblsrCallFunc(const iocshArgBuf *args) -{ dblsr(args[0].sval,args[1].ival);} +{ iocshSetError(dblsr(args[0].sval,args[1].ival));} /* dbLockShowLocked */ static const iocshArg dbLockShowLockedArg0 = { "interest level",iocshArgInt}; @@ -412,7 +414,7 @@ static const iocshFuncDef dbLockShowLockedFuncDef = { "Example: dbLockShowLocked 0\n" }; static void dbLockShowLockedCallFunc(const iocshArgBuf *args) -{ dbLockShowLocked(args[0].ival);} +{ iocshSetError(dbLockShowLocked(args[0].ival));} /* scanOnceSetQueueSize */ static const iocshArg scanOnceSetQueueSizeArg0 = { "size",iocshArgInt}; @@ -423,7 +425,7 @@ static const iocshFuncDef scanOnceSetQueueSizeFuncDef = {"scanOnceSetQueueSize", "Must be called before iocInit().\n"}; static void scanOnceSetQueueSizeCallFunc(const iocshArgBuf *args) { - scanOnceSetQueueSize(args[0].ival); + iocshSetError(scanOnceSetQueueSize(args[0].ival)); } /* scanOnceQueueShow */ @@ -444,7 +446,7 @@ static const iocshFuncDef scanpplFuncDef = {"scanppl",1,scanpplArgs, "Print info for records with periodic scan.\n" "If rate == 0.0, all periods are shown.\n"}; static void scanpplCallFunc(const iocshArgBuf *args) -{ scanppl(args[0].dval);} +{ iocshSetError(scanppl(args[0].dval));} /* scanpel */ static const iocshArg scanpelArg0 = { "event name",iocshArgString}; @@ -452,7 +454,7 @@ static const iocshArg * const scanpelArgs[1] = {&scanpelArg0}; static const iocshFuncDef scanpelFuncDef = {"scanpel",1,scanpelArgs, "Print info for records with SCAN = \"Event\".\n"}; static void scanpelCallFunc(const iocshArgBuf *args) -{ scanpel(args[0].sval);} +{ iocshSetError(scanpel(args[0].sval));} /* postEvent */ static const iocshArg postEventArg0 = { "event name",iocshArgString}; @@ -468,7 +470,7 @@ static void postEventCallFunc(const iocshArgBuf *args) /* scanpiol */ static const iocshFuncDef scanpiolFuncDef = {"scanpiol",0,0, "Print info for records with SCAN = \"I/O Intr\".\n"}; -static void scanpiolCallFunc(const iocshArgBuf *args) { scanpiol();} +static void scanpiolCallFunc(const iocshArgBuf *args) { iocshSetError(scanpiol());} /* callbackSetQueueSize */ static const iocshArg callbackSetQueueSizeArg0 = { "bufsize",iocshArgInt}; @@ -479,7 +481,7 @@ static const iocshFuncDef callbackSetQueueSizeFuncDef = {"callbackSetQueueSize", "Must be called before iocInit().\n"}; static void callbackSetQueueSizeCallFunc(const iocshArgBuf *args) { - callbackSetQueueSize(args[0].ival); + iocshSetError(callbackSetQueueSize(args[0].ival)); } /* callbackQueueShow */ @@ -504,7 +506,7 @@ static const iocshFuncDef callbackParallelThreadsFuncDef = {"callbackParallelThr "or one of LOW, MEDIUM, or HIGH.\n"}; static void callbackParallelThreadsCallFunc(const iocshArgBuf *args) { - callbackParallelThreads(args[0].ival, args[1].sval); + iocshSetError(callbackParallelThreads(args[0].ival, args[1].sval)); } /* dbStateCreate */ @@ -514,7 +516,8 @@ static const iocshFuncDef dbStateCreateFuncDef = {"dbStateCreate", 1, dbStateCre "Allocate new state name for \"state\" filter.\n"}; static void dbStateCreateCallFunc (const iocshArgBuf *args) { - dbStateCreate(args[0].sval); + if (!dbStateCreate(args[0].sval)) + iocshSetError(-1); } /* dbStateSet */ @@ -527,6 +530,8 @@ static void dbStateSetCallFunc (const iocshArgBuf *args) if (sid) dbStateSet(sid); + else + iocshSetError(-1); } /* dbStateClear */ @@ -539,6 +544,8 @@ static void dbStateClearCallFunc (const iocshArgBuf *args) if (sid) dbStateClear(sid); + else + iocshSetError(-1); } /* dbStateShow */ @@ -552,6 +559,8 @@ static void dbStateShowCallFunc (const iocshArgBuf *args) if (sid) dbStateShow(sid, args[1].ival); + else + iocshSetError(-1); } /* dbStateShowAll */ diff --git a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c index ff9aafc78..21a34e857 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c +++ b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c @@ -207,7 +207,7 @@ static const iocshFuncDef dbPvdTableSizeFuncDef = { }; static void dbPvdTableSizeCallFunc(const iocshArgBuf *args) { - dbPvdTableSize(args[0].ival); + iocshSetError(dbPvdTableSize(args[0].ival)); } /* dbReportDeviceConfig */ diff --git a/modules/database/src/ioc/misc/dlload.c b/modules/database/src/ioc/misc/dlload.c index 8b2a76371..8aea72cb5 100644 --- a/modules/database/src/ioc/misc/dlload.c +++ b/modules/database/src/ioc/misc/dlload.c @@ -10,11 +10,13 @@ #include "iocsh.h" #include "epicsExport.h" -IOCSH_STATIC_FUNC void dlload(const char* name) +IOCSH_STATIC_FUNC int dlload(const char* name) { if (!epicsLoadLibrary(name)) { printf("epicsLoadLibrary failed: %s\n", epicsLoadError()); + return -1; } + return 0; } static const iocshArg dlloadArg0 = { "path/library.so", iocshArgStringPath}; @@ -28,7 +30,7 @@ static const iocshFuncDef dlloadFuncDef = { }; static void dlloadCallFunc(const iocshArgBuf *args) { - dlload(args[0].sval); + iocshSetError(dlload(args[0].sval)); } static void dlloadRegistar(void) { diff --git a/modules/libcom/RTEMS/posix/rtems_init.c b/modules/libcom/RTEMS/posix/rtems_init.c index 79859724a..0af4fa78f 100644 --- a/modules/libcom/RTEMS/posix/rtems_init.c +++ b/modules/libcom/RTEMS/posix/rtems_init.c @@ -510,6 +510,7 @@ static void rtshellCallFunc(const iocshArgBuf *args) if (!cmd) { fprintf(stderr, "ERR: No such command\n"); + iocshSetError(-1); } else { fflush(stdout); @@ -517,6 +518,7 @@ static void rtshellCallFunc(const iocshArgBuf *args) ret = (*cmd->command)(args[1].aval.ac,args[1].aval.av); fflush(stdout); fflush(stderr); + iocshSetError(ret); if(ret) fprintf(stderr, "ERR: %d\n",ret); } @@ -611,18 +613,27 @@ static void nfsMountCallFunc(const iocshArgBuf *args) } *cp = '/'; } - nfsMount(args[0].sval, args[1].sval, args[2].sval); + iocshSetError(nfsMount(args[0].sval, args[1].sval, args[2].sval)); } #endif -void zoneset(const char *zone) +int zoneset(const char *zone) { - if(zone) - setenv("TZ", zone, 1); - else - unsetenv("TZ"); + int ret; + if(zone) { + if ((ret = setenv("TZ", zone, 1)) < 0) + return ret; + } + #if defined( __NEWLIB_MINOR__ ) /* Added in newlib 2.2.0 */ + else if ((ret = unsetenv("TZ")) < 0) + return ret; + #else + else + unsetenv("TZ"); + #endif tzset(); + return 0; } static const iocshArg zonesetArg0 = {"zone string", iocshArgString}; @@ -634,7 +645,7 @@ static const iocshFuncDef zonesetFuncDef = {"zoneset",1,zonesetArgs }; static void zonesetCallFunc(const iocshArgBuf *args) { - zoneset(args[0].sval); + iocshSetError(zoneset(args[0].sval)); } #ifndef RTEMS_LEGACY_STACK @@ -667,6 +678,7 @@ static void setlogmaskCallFunc(const iocshArgBuf *args) return; } printf("Error: unknown log level.\n"); + iocshSetError(-1); } } static const iocshArg setlogmaskArg0 = {"level name", iocshArgString}; diff --git a/modules/libcom/RTEMS/score/rtems_init.c b/modules/libcom/RTEMS/score/rtems_init.c index f8cd62d5d..d291ea1f9 100644 --- a/modules/libcom/RTEMS/score/rtems_init.c +++ b/modules/libcom/RTEMS/score/rtems_init.c @@ -483,18 +483,27 @@ static void nfsMountCallFunc(const iocshArgBuf *args) } *cp = '/'; } - nfsMount(args[0].sval, args[1].sval, args[2].sval); + iocshSetError(nfsMount(args[0].sval, args[1].sval, args[2].sval)); } #endif -void zoneset(const char *zone) +int zoneset(const char *zone) { - if(zone) - setenv("TZ", zone, 1); - else - unsetenv("TZ"); + int ret; + if(zone) { + if ((ret = setenv("TZ", zone, 1)) < 0) + return ret; + } + #if defined( __NEWLIB_MINOR__ ) /* Added in newlib 2.2.0 */ + else if ((ret = unsetenv("TZ")) < 0) + return ret; + #else + else + unsetenv("TZ"); + #endif tzset(); + return 0; } static const iocshArg zonesetArg0 = {"zone string", iocshArgString}; @@ -502,7 +511,7 @@ static const iocshArg * const zonesetArgs[1] = {&zonesetArg0}; static const iocshFuncDef zonesetFuncDef = {"zoneset",1,zonesetArgs}; static void zonesetCallFunc(const iocshArgBuf *args) { - zoneset(args[0].sval); + iocshSetError(zoneset(args[0].sval)); } diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index 5751ad070..9fbf6b850 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -139,10 +139,12 @@ static void epicsEnvSetCallFunc(const iocshArgBuf *args) if (name == NULL) { fprintf(stderr, "Missing environment variable name argument.\n"); + iocshSetError(-1); return; } if (value == NULL) { fprintf(stderr, "Missing environment variable value argument.\n"); + iocshSetError(-1); return; } epicsEnvSet (name, value); @@ -159,6 +161,7 @@ static void epicsEnvUnsetCallFunc(const iocshArgBuf *args) if (name == NULL) { fprintf(stderr, "Missing environment variable name argument.\n"); + iocshSetError(-1); return; } epicsEnvUnset (name); @@ -215,7 +218,7 @@ static const iocshFuncDef iocLogInitFuncDef = {"iocLogInit",0,0, " see 'setIocLogDisable' command\n"}; static void iocLogInitCallFunc(const iocshArgBuf *args) { - iocLogInit (); + iocshSetError(iocLogInit ()); } /* iocLogDisable */ @@ -354,6 +357,7 @@ static void threadCallFunc(const iocshArgBuf *args) tid = epicsThreadGetId (cp); if (!tid) { fprintf(stderr, "\t'%s' is not a known thread name\n", cp); + iocshSetError(-1); continue; } } @@ -429,6 +433,7 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args) tid = epicsThreadGetId(cp); if (!tid) { fprintf(stderr, "'%s' is not a valid thread name\n", cp); + iocshSetError(-1); continue; } } @@ -437,12 +442,14 @@ static void epicsThreadResumeCallFunc(const iocshArgBuf *args) epicsThreadGetName(tid, nameBuf, sizeof nameBuf); if (nameBuf[0] == '\0') { fprintf(stderr, "'%s' is not a valid thread id\n", cp); + iocshSetError(-1); continue; } } if (!epicsThreadIsSuspended(tid)) { fprintf(stderr, "Thread %s is not suspended\n", cp); + iocshSetError(-1); continue; } epicsThreadResume(tid); @@ -458,7 +465,7 @@ static const iocshFuncDef generalTimeReportFuncDef = {"generalTimeReport",1,gene " 1 - Additionally show current time obtained from each provider.\n"}; static void generalTimeReportCallFunc(const iocshArgBuf *args) { - generalTimeReport(args[0].ival); + iocshSetError(generalTimeReport(args[0].ival)); } /* installLastResortEventProvider */ @@ -467,7 +474,7 @@ static const iocshFuncDef installLastResortEventProviderFuncDef = {"installLastR "which returns the current time for every event number\n"}; static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) { - installLastResortEventProvider(); + iocshSetError(installLastResortEventProvider()); } static iocshVarDef comDefs[] = { From 1d19ba4cc2e8c9ab17288b684022a0682e398bde Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 7 Feb 2025 09:06:13 -0800 Subject: [PATCH 25/36] doc and log for *MustSucceed() Replace the "never returns NULL." statement which is manifestly not true. --- modules/libcom/src/misc/cantProceed.c | 4 ++-- modules/libcom/src/misc/cantProceed.h | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/modules/libcom/src/misc/cantProceed.c b/modules/libcom/src/misc/cantProceed.c index 80e26f8f6..47b928da3 100644 --- a/modules/libcom/src/misc/cantProceed.c +++ b/modules/libcom/src/misc/cantProceed.c @@ -24,7 +24,7 @@ LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *msg) void * mem = NULL; if (count > 0 && size > 0) { while ((mem = calloc(count, size)) == NULL) { - errlogPrintf("%s: callocMustSucceed(%lu, %lu) - calloc failed\n", + errlogPrintf("%s: callocMustSucceed(%lu, %lu) - " ERL_ERROR " calloc failed\n", msg, (unsigned long)count, (unsigned long)size); errlogPrintf("Thread %s (%p) suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); @@ -40,7 +40,7 @@ LIBCOM_API void * mallocMustSucceed(size_t size, const char *msg) void * mem = NULL; if (size > 0) { while ((mem = malloc(size)) == NULL) { - errlogPrintf("%s: mallocMustSucceed(%lu) - malloc failed\n", + errlogPrintf("%s: mallocMustSucceed(%lu) - " ERL_ERROR " malloc failed\n", msg, (unsigned long)size); errlogPrintf("Thread %s (%p) suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); diff --git a/modules/libcom/src/misc/cantProceed.h b/modules/libcom/src/misc/cantProceed.h index 0232a8611..f9559b14c 100644 --- a/modules/libcom/src/misc/cantProceed.h +++ b/modules/libcom/src/misc/cantProceed.h @@ -56,18 +56,24 @@ LIBCOM_API void cantProceed( * gracefully when memory runs out. */ /** @{ */ -/** \brief A calloc() that never returns NULL. +/** \brief A calloc() which suspends on error. * \param count Number of objects. * \param size Size of each object. - * \param errorMessage What this memory is needed for. - * \return Pointer to zeroed allocated memory. + * \param errorMessage Context added to logged error message + * \return Pointer to zeroed allocated memory. Should later be free() d + * + * Will always return NULL for a zero length allocation. + * Will never return NULL otherwise. */ LIBCOM_API void * callocMustSucceed(size_t count, size_t size, const char *errorMessage); -/** \brief A malloc() that never returns NULL. +/** \brief A malloc() which suspends on error. * \param size Size of block to allocate. - * \param errorMessage What this memory is needed for. - * \return Pointer to allocated memory. + * \param errorMessage Context added to logged error message + * \return Pointer to allocated memory. Should later be free() d + * + * Will always return NULL for a zero length allocation. + * Will never return NULL otherwise. */ LIBCOM_API void * mallocMustSucceed(size_t size, const char *errorMessage); /** @} */ From 1735a821dbd8e5eed2f19fa22285303cf3e7af2e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 11 Feb 2025 17:44:51 -0600 Subject: [PATCH 26/36] Update pvDatabase --- modules/pvDatabase | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pvDatabase b/modules/pvDatabase index f207e512d..c070a3485 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit f207e512d67addab79e33a00b712e3444228ba7c +Subproject commit c070a3485b01714e500f6623780e6845bfae1f4c From f4c474eb7730cf8bd199a1cdc59008504fc76d67 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 22 Jan 2025 12:20:37 -0600 Subject: [PATCH 27/36] Remove Python build dependency when LINKER_USE_RPATH=ORIGIN This change converts the makeRPath.py script to Perl. Also changes the PYTHON default to run `python3` --- configure/CONFIG_BASE | 3 +- configure/CONFIG_COMMON | 8 +-- src/tools/Makefile | 4 +- src/tools/makeRPath.pl | 135 ++++++++++++++++++++++++++++++++++++++++ src/tools/makeRPath.py | 86 ------------------------- 5 files changed, 142 insertions(+), 94 deletions(-) create mode 100644 src/tools/makeRPath.pl delete mode 100644 src/tools/makeRPath.py diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE index a737b37fc..7d2637f00 100644 --- a/configure/CONFIG_BASE +++ b/configure/CONFIG_BASE @@ -54,8 +54,7 @@ CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl) FILTERMAKEFLAGS = $(PERL) $(call FIND_TOOL,filterMakeflags.pl) FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG) - -MAKERPATH = $(PYTHON) $(TOOLS)/makeRPath.py +MAKERPATH = $(PERL) $(TOOLS)/makeRPath.pl #--------------------------------------------------------------- # tools for installing libraries and products diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index 9165ae294..42129726d 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -34,11 +34,11 @@ CROSS2 = $(CROSS_COMPILER_TARGET_ARCHS$(filter-out 1,$(words $(filter $(EPICS_HO BUILD_ARCHS = $(EPICS_HOST_ARCH) $(CROSS1) $(CROSS2) #------------------------------------------------------- -# Default for perl if it's on the PATH, -# otherwise override this in os/CONFIG_SITE..Common +# Defaults for Perl and Python assume they're on $PATH. +# Python (now python3) is only needed by developers, when building docs. +# Override these in os/CONFIG_SITE..Common or CONFIG_SITE.local PERL = perl -CSD - -PYTHON = python +PYTHON = python3 #------------------------------------------------------- # Check configure/RELEASE file for consistency diff --git a/src/tools/Makefile b/src/tools/Makefile index bb47f37a0..ad57b54a2 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -37,6 +37,7 @@ PERL_SCRIPTS += fullPathName.pl PERL_SCRIPTS += installEpics.pl PERL_SCRIPTS += makeAPIheader.pl PERL_SCRIPTS += makeMakefile.pl +PERL_SCRIPTS += makeRPath.pl PERL_SCRIPTS += makeTestfile.pl PERL_SCRIPTS += mkmf.pl PERL_SCRIPTS += munch.pl @@ -49,14 +50,13 @@ PERL_SCRIPTS += testFailures.pl PERL_SCRIPTS += useManifestTool.pl PERL_SCRIPTS += genVersionHeader.pl -PERL_SCRIPTS += makeRPath.py - HTMLS = style.css HTMLS += EPICS/Getopts.html HTMLS += EPICS/Path.html HTMLS += EPICS/Readfile.html HTMLS += fullPathName.html HTMLS += makeAPIheader.html +HTMLS += makeRPath.html HTMLS += munch.html HTMLS += podToHtml.html HTMLS += podToMD.html diff --git a/src/tools/makeRPath.pl b/src/tools/makeRPath.pl new file mode 100644 index 000000000..8120ff070 --- /dev/null +++ b/src/tools/makeRPath.pl @@ -0,0 +1,135 @@ +#!/usr/bin/env perl +#************************************************************************* +# SPDX-License-Identifier: EPICS +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +use strict; +use warnings; + +use Getopt::Long; +use Cwd qw(abs_path getcwd); +use File::Spec; +use File::Basename; +use Pod::Usage; + +# Example: +# target to be installed as: /build/bin/blah +# post-install will copy as: /install/bin/blah +# +# Need to link against: +# /install/lib/libA.so +# /build/lib/libB.so +# /other/lib/libC.so +# +# Want final result to be: +# -rpath $ORIGIN/../lib -rpath /other/lib \ +# -rpath-link /build/lib -rpath-link /install/lib + +warn "[" . join(' ', $0, @ARGV) . "]\n" + if $ENV{EPICS_DEBUG_RPATH} && $ENV{EPICS_DEBUG_RPATH} eq 'YES'; + +# Defaults for command-line arguments +my $final = getcwd(); +my $root = ''; +my $origin = '$ORIGIN'; +my $help = 0; + +# Parse command-line arguments +GetOptions( + 'final|F=s' => \$final, + 'root|R=s' => \$root, + 'origin|O=s' => \$origin, + 'help|h' => \$help, +) or pod2usage( + -exitval => 2, + -verbose => 1, + -noperldoc => 1, +); + +# Display help message if requested +pod2usage( + -exitval => 1, + -verbose => 2, + -noperldoc => 1, +) if $help; + +# Convert paths to absolute +$final = abs_path($final); +my @roots = map { abs_path($_) } grep { length($_) } split(/:/, $root); + +# Determine the root containing the final location +my $froot; +foreach my $root (@roots) { + my $frel = File::Spec->abs2rel($final, $root); + if ($frel !~ /^\.\./) { + $froot = $root; + last; + } +} + +if (!defined $froot) { + warn "makeRPath: Final location $final\n" . + "Not under any of: @roots\n"; + @roots = (); # Skip $ORIGIN handling below +} + +# Prepare output +my (@output, %output); +foreach my $path (@ARGV) { + $path = abs_path($path); + foreach my $root (@roots) { + my $rrel = File::Spec->abs2rel($path, $root); + if ($rrel !~ /^\.\./) { + # Add rpath-link for internal use by 'ld' + my $opt = "-Wl,-rpath-link,$path"; + push @output, $opt unless $output{$opt}++; + + # Calculate relative path + my $rel_path = File::Spec->abs2rel($rrel, $final); + my $opath = File::Spec->catfile($origin, $rel_path); + $opt = "-Wl,-rpath,$opath"; + push @output, $opt unless $output{$opt}++; + last; + } + } +} + +# Print the output +print join(' ', @output), "\n"; + +__END__ + +=head1 NAME + +makeRPath.pl - Compute and output -rpath entries for given paths + +=head1 SYNOPSIS + +makeRPath.pl [options] [path ...] + +=head1 OPTIONS + + -h, --help Display detailed help and exit + -F, --final Final install location for ELF file + -R, --root Root(s) of relocatable tree, separated by ':' + -O, --origin Origin path (default: '$ORIGIN') + +=head1 DESCRIPTION + +Computes and outputs -rpath entries for each of the given paths. +Paths under C<--root> will be computed as relative to C<--final>. + +=head1 EXAMPLE + +A library to be placed in C and linked against libraries in +C, C, and C would pass + + makeRPath.pl -F /build/lib -R /build /build/lib /build/module/lib /other/lib + +which generates + + -Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib + +=cut diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py deleted file mode 100644 index ec024e2a9..000000000 --- a/src/tools/makeRPath.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -#************************************************************************* -# SPDX-License-Identifier: EPICS -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* - -from __future__ import print_function - -import sys -import os -from collections import OrderedDict # used as OrderedSet - -from argparse import ArgumentParser - -if os.environ.get('EPICS_DEBUG_RPATH','')=='YES': - sys.stderr.write('%s'%sys.argv) - -P = ArgumentParser(description='''Compute and output -rpath entries for each of the given paths. - Paths under --root will be computed as relative to --final .''', -epilog=''' -eg. A library to be placed in /build/lib and linked against libraries in -'/build/lib', '/build/module/lib', and '/other/lib' would pass: - - "makeRPath.py -F /build/lib -R /build /build/lib /build/module/lib /other/lib" -which prints "-Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib" -''') -P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file') -P.add_argument('-R','--root',default='', help='Root(s) of relocatable tree. Separate with :') -P.add_argument('-O', '--origin', default='$ORIGIN') -P.add_argument('path', nargs='*') -args = P.parse_args() - -# eg. -# target to be installed as: /build/bin/blah -# -# post-install will copy as: /install/bin/blah -# -# Need to link against: -# /install/lib/libA.so -# /build/lib/libB.so -# /other/lib/libC.so -# -# Want final result to be: -# -rpath $ORIGIN/../lib -rpath /other/lib \ -# -rpath-link /build/lib -rpath-link /install/lib - -fdir = os.path.abspath(args.final) -roots = [os.path.abspath(root) for root in args.root.split(':') if len(root)] - -# find the root which contains the final location -froot = None -for root in roots: - frel = os.path.relpath(fdir, root) - if not frel.startswith('..'): - # final dir is under this root - froot = root - break - -if froot is None: - sys.stderr.write("makeRPath: Final location %s\nNot under any of: %s\n"%(fdir, roots)) - # skip $ORIGIN handling below... - roots = [] - -output = OrderedDict() -for path in args.path: - path = os.path.abspath(path) - - for root in roots: - rrel = os.path.relpath(path, root) - if not rrel.startswith('..'): - # path is under this root - - # some older binutils don't seem to handle $ORIGIN correctly - # when locating dependencies of libraries. So also provide - # the absolute path for internal use by 'ld' only. - output['-Wl,-rpath-link,'+path] = True - - # frel is final location relative to enclosing root - # rrel is target location relative to enclosing root - path = os.path.relpath(rrel, frel) - break - - output['-Wl,-rpath,'+os.path.join(args.origin, path)] = True - -print(' '.join(output)) From 2612b47c3fbad195f79efa6188b7ea483f276aeb Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 14 Feb 2025 17:13:21 -0600 Subject: [PATCH 28/36] Release Notes for PYTHON=python3 --- documentation/RELEASE_NOTES.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index ce4088385..236b562d9 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,6 +22,24 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.8.1 +### Build system `$(PYTHON)` default changed + +The default value of the build system's `$(PYTHON)` variable has changed from +`python` to `python3`, in line with many recent OS installations' removal of +the `python` binary after Python 2 support ended. +This change may affect EPICS support modules which run Python scripts at +build-time that haven't yet been converted to Python 3. +If needed, the value can be overridden in a `configure/CONFIG_SITE.local` file, +either in Base or in the specific module. + +This variable was added in EPICS 7.0.3.1 and only used by Base when configured +with `LINKER_USE_RPATH=ORIGIN`. +That configuration now runs a Perl translation of the original script, so +Python is not required to build Base. + +EPICS developers working on documentation may need to point `PYTHON` to a +Pythons venv that has the additional packages needed to run Sphinx. + ### Post monitors from compress record when it's reset Writing into a compress record's `RES` field now posts a monitor event instead From 890cbc2c0d60629a9ccc696fc5098ddede45d9f2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 13 Feb 2025 14:24:28 -0800 Subject: [PATCH 29/36] doc --- modules/database/src/ioc/db/dbLink.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h index b8a819b98..e53133541 100644 --- a/modules/database/src/ioc/db/dbLink.h +++ b/modules/database/src/ioc/db/dbLink.h @@ -391,6 +391,10 @@ typedef struct lset { #define dbGetSevr(link, sevr) \ dbGetAlarm(link, NULL, sevr) +/** @brief Lookup link field name from pointer. + * Returns only field name. aka. value of ``dbFldDes::name`` + * @since 3.16.2 + */ DBCORE_API const char * dbLinkFieldName(const struct link *plink); DBCORE_API void dbInitLink(struct link *plink, short dbfType); From 73843511815aea743c45ffcadfb9e3138e2951a2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 18 Feb 2025 07:24:35 -0800 Subject: [PATCH 30/36] clarify cantProceed() message --- modules/libcom/src/misc/cantProceed.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/misc/cantProceed.c b/modules/libcom/src/misc/cantProceed.c index 47b928da3..f66d61bc2 100644 --- a/modules/libcom/src/misc/cantProceed.c +++ b/modules/libcom/src/misc/cantProceed.c @@ -59,7 +59,7 @@ LIBCOM_API void cantProceed(const char *msg, ...) errlogVprintf(msg, pvar); va_end(pvar); - errlogPrintf("Thread %s (%p) can't proceed, suspending.\n", + errlogPrintf(ANSI_RED("CRITICAL ERROR") " Thread %s (%p) can't proceed, suspending.\n", epicsThreadGetNameSelf(), (void *)epicsThreadGetIdSelf()); epicsStackTrace(); From 7a6e11cae0f46cdb4da148c278aed3a6daeadb08 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 6 Feb 2025 15:32:08 -0800 Subject: [PATCH 31/36] make casStatsFetch() safe-ish when RSRV not initialized Maybe too early. Or maybe RSRV disabled via dbServer. --- modules/database/src/ioc/rsrv/camsgtask.c | 2 ++ modules/database/src/ioc/rsrv/caservertask.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/modules/database/src/ioc/rsrv/camsgtask.c b/modules/database/src/ioc/rsrv/camsgtask.c index 24df11d39..568adc7d4 100644 --- a/modules/database/src/ioc/rsrv/camsgtask.c +++ b/modules/database/src/ioc/rsrv/camsgtask.c @@ -163,6 +163,8 @@ void camsgtask ( void *pParm ) int casClientInitiatingCurrentThread ( char * pBuf, size_t bufSize ) { + if ( ! rsrvCurrentClient ) + return RSRV_ERROR; /* not yet initialized, or disabled via dbServer */ struct client * pClient = ( struct client * ) epicsThreadPrivateGet ( rsrvCurrentClient ); diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index f904d3268..a658c3796 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -1536,6 +1536,13 @@ struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr) void casStatsFetch ( unsigned *pChanCount, unsigned *pCircuitCount ) { + if(!clientQlock) { /* not yet initialized, or disabled via dbServer */ + if(pChanCount) + *pChanCount = 0; + if(pCircuitCount) + *pCircuitCount = 0; + return; + } LOCK_CLIENTQ; { int circuitCount = ellCount ( &clientQ ); From a3d8531008997b05e49421608f24ba9ef29eb0f4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 19 Feb 2025 14:10:16 -0600 Subject: [PATCH 32/36] Revert PR #589 * Revert "Release Notes for PYTHON=python3" commit 2612b47c3fbad195f79efa6188b7ea483f276aeb. * Revert "Remove Python build dependency when LINKER_USE_RPATH=ORIGIN" commit f4c474eb7730cf8bd199a1cdc59008504fc76d67. --- configure/CONFIG_BASE | 3 +- configure/CONFIG_COMMON | 8 +- documentation/RELEASE_NOTES.md | 18 ----- src/tools/Makefile | 4 +- src/tools/makeRPath.pl | 135 --------------------------------- src/tools/makeRPath.py | 86 +++++++++++++++++++++ 6 files changed, 94 insertions(+), 160 deletions(-) delete mode 100644 src/tools/makeRPath.pl create mode 100644 src/tools/makeRPath.py diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE index 7d2637f00..a737b37fc 100644 --- a/configure/CONFIG_BASE +++ b/configure/CONFIG_BASE @@ -54,7 +54,8 @@ CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl) FILTERMAKEFLAGS = $(PERL) $(call FIND_TOOL,filterMakeflags.pl) FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG) -MAKERPATH = $(PERL) $(TOOLS)/makeRPath.pl + +MAKERPATH = $(PYTHON) $(TOOLS)/makeRPath.py #--------------------------------------------------------------- # tools for installing libraries and products diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index 42129726d..9165ae294 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -34,11 +34,11 @@ CROSS2 = $(CROSS_COMPILER_TARGET_ARCHS$(filter-out 1,$(words $(filter $(EPICS_HO BUILD_ARCHS = $(EPICS_HOST_ARCH) $(CROSS1) $(CROSS2) #------------------------------------------------------- -# Defaults for Perl and Python assume they're on $PATH. -# Python (now python3) is only needed by developers, when building docs. -# Override these in os/CONFIG_SITE..Common or CONFIG_SITE.local +# Default for perl if it's on the PATH, +# otherwise override this in os/CONFIG_SITE..Common PERL = perl -CSD -PYTHON = python3 + +PYTHON = python #------------------------------------------------------- # Check configure/RELEASE file for consistency diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 236b562d9..ce4088385 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,24 +22,6 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.8.1 -### Build system `$(PYTHON)` default changed - -The default value of the build system's `$(PYTHON)` variable has changed from -`python` to `python3`, in line with many recent OS installations' removal of -the `python` binary after Python 2 support ended. -This change may affect EPICS support modules which run Python scripts at -build-time that haven't yet been converted to Python 3. -If needed, the value can be overridden in a `configure/CONFIG_SITE.local` file, -either in Base or in the specific module. - -This variable was added in EPICS 7.0.3.1 and only used by Base when configured -with `LINKER_USE_RPATH=ORIGIN`. -That configuration now runs a Perl translation of the original script, so -Python is not required to build Base. - -EPICS developers working on documentation may need to point `PYTHON` to a -Pythons venv that has the additional packages needed to run Sphinx. - ### Post monitors from compress record when it's reset Writing into a compress record's `RES` field now posts a monitor event instead diff --git a/src/tools/Makefile b/src/tools/Makefile index ad57b54a2..bb47f37a0 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -37,7 +37,6 @@ PERL_SCRIPTS += fullPathName.pl PERL_SCRIPTS += installEpics.pl PERL_SCRIPTS += makeAPIheader.pl PERL_SCRIPTS += makeMakefile.pl -PERL_SCRIPTS += makeRPath.pl PERL_SCRIPTS += makeTestfile.pl PERL_SCRIPTS += mkmf.pl PERL_SCRIPTS += munch.pl @@ -50,13 +49,14 @@ PERL_SCRIPTS += testFailures.pl PERL_SCRIPTS += useManifestTool.pl PERL_SCRIPTS += genVersionHeader.pl +PERL_SCRIPTS += makeRPath.py + HTMLS = style.css HTMLS += EPICS/Getopts.html HTMLS += EPICS/Path.html HTMLS += EPICS/Readfile.html HTMLS += fullPathName.html HTMLS += makeAPIheader.html -HTMLS += makeRPath.html HTMLS += munch.html HTMLS += podToHtml.html HTMLS += podToMD.html diff --git a/src/tools/makeRPath.pl b/src/tools/makeRPath.pl deleted file mode 100644 index 8120ff070..000000000 --- a/src/tools/makeRPath.pl +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env perl -#************************************************************************* -# SPDX-License-Identifier: EPICS -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* - -use strict; -use warnings; - -use Getopt::Long; -use Cwd qw(abs_path getcwd); -use File::Spec; -use File::Basename; -use Pod::Usage; - -# Example: -# target to be installed as: /build/bin/blah -# post-install will copy as: /install/bin/blah -# -# Need to link against: -# /install/lib/libA.so -# /build/lib/libB.so -# /other/lib/libC.so -# -# Want final result to be: -# -rpath $ORIGIN/../lib -rpath /other/lib \ -# -rpath-link /build/lib -rpath-link /install/lib - -warn "[" . join(' ', $0, @ARGV) . "]\n" - if $ENV{EPICS_DEBUG_RPATH} && $ENV{EPICS_DEBUG_RPATH} eq 'YES'; - -# Defaults for command-line arguments -my $final = getcwd(); -my $root = ''; -my $origin = '$ORIGIN'; -my $help = 0; - -# Parse command-line arguments -GetOptions( - 'final|F=s' => \$final, - 'root|R=s' => \$root, - 'origin|O=s' => \$origin, - 'help|h' => \$help, -) or pod2usage( - -exitval => 2, - -verbose => 1, - -noperldoc => 1, -); - -# Display help message if requested -pod2usage( - -exitval => 1, - -verbose => 2, - -noperldoc => 1, -) if $help; - -# Convert paths to absolute -$final = abs_path($final); -my @roots = map { abs_path($_) } grep { length($_) } split(/:/, $root); - -# Determine the root containing the final location -my $froot; -foreach my $root (@roots) { - my $frel = File::Spec->abs2rel($final, $root); - if ($frel !~ /^\.\./) { - $froot = $root; - last; - } -} - -if (!defined $froot) { - warn "makeRPath: Final location $final\n" . - "Not under any of: @roots\n"; - @roots = (); # Skip $ORIGIN handling below -} - -# Prepare output -my (@output, %output); -foreach my $path (@ARGV) { - $path = abs_path($path); - foreach my $root (@roots) { - my $rrel = File::Spec->abs2rel($path, $root); - if ($rrel !~ /^\.\./) { - # Add rpath-link for internal use by 'ld' - my $opt = "-Wl,-rpath-link,$path"; - push @output, $opt unless $output{$opt}++; - - # Calculate relative path - my $rel_path = File::Spec->abs2rel($rrel, $final); - my $opath = File::Spec->catfile($origin, $rel_path); - $opt = "-Wl,-rpath,$opath"; - push @output, $opt unless $output{$opt}++; - last; - } - } -} - -# Print the output -print join(' ', @output), "\n"; - -__END__ - -=head1 NAME - -makeRPath.pl - Compute and output -rpath entries for given paths - -=head1 SYNOPSIS - -makeRPath.pl [options] [path ...] - -=head1 OPTIONS - - -h, --help Display detailed help and exit - -F, --final Final install location for ELF file - -R, --root Root(s) of relocatable tree, separated by ':' - -O, --origin Origin path (default: '$ORIGIN') - -=head1 DESCRIPTION - -Computes and outputs -rpath entries for each of the given paths. -Paths under C<--root> will be computed as relative to C<--final>. - -=head1 EXAMPLE - -A library to be placed in C and linked against libraries in -C, C, and C would pass - - makeRPath.pl -F /build/lib -R /build /build/lib /build/module/lib /other/lib - -which generates - - -Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib - -=cut diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py new file mode 100644 index 000000000..ec024e2a9 --- /dev/null +++ b/src/tools/makeRPath.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +#************************************************************************* +# SPDX-License-Identifier: EPICS +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* + +from __future__ import print_function + +import sys +import os +from collections import OrderedDict # used as OrderedSet + +from argparse import ArgumentParser + +if os.environ.get('EPICS_DEBUG_RPATH','')=='YES': + sys.stderr.write('%s'%sys.argv) + +P = ArgumentParser(description='''Compute and output -rpath entries for each of the given paths. + Paths under --root will be computed as relative to --final .''', +epilog=''' +eg. A library to be placed in /build/lib and linked against libraries in +'/build/lib', '/build/module/lib', and '/other/lib' would pass: + + "makeRPath.py -F /build/lib -R /build /build/lib /build/module/lib /other/lib" +which prints "-Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib" +''') +P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file') +P.add_argument('-R','--root',default='', help='Root(s) of relocatable tree. Separate with :') +P.add_argument('-O', '--origin', default='$ORIGIN') +P.add_argument('path', nargs='*') +args = P.parse_args() + +# eg. +# target to be installed as: /build/bin/blah +# +# post-install will copy as: /install/bin/blah +# +# Need to link against: +# /install/lib/libA.so +# /build/lib/libB.so +# /other/lib/libC.so +# +# Want final result to be: +# -rpath $ORIGIN/../lib -rpath /other/lib \ +# -rpath-link /build/lib -rpath-link /install/lib + +fdir = os.path.abspath(args.final) +roots = [os.path.abspath(root) for root in args.root.split(':') if len(root)] + +# find the root which contains the final location +froot = None +for root in roots: + frel = os.path.relpath(fdir, root) + if not frel.startswith('..'): + # final dir is under this root + froot = root + break + +if froot is None: + sys.stderr.write("makeRPath: Final location %s\nNot under any of: %s\n"%(fdir, roots)) + # skip $ORIGIN handling below... + roots = [] + +output = OrderedDict() +for path in args.path: + path = os.path.abspath(path) + + for root in roots: + rrel = os.path.relpath(path, root) + if not rrel.startswith('..'): + # path is under this root + + # some older binutils don't seem to handle $ORIGIN correctly + # when locating dependencies of libraries. So also provide + # the absolute path for internal use by 'ld' only. + output['-Wl,-rpath-link,'+path] = True + + # frel is final location relative to enclosing root + # rrel is target location relative to enclosing root + path = os.path.relpath(rrel, frel) + break + + output['-Wl,-rpath,'+os.path.join(args.origin, path)] = True + +print(' '.join(output)) From 0733beae50157c9a90f8a223cc0eb47fce877506 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 20 Feb 2025 10:27:41 -0600 Subject: [PATCH 33/36] Fix for PR #597 breakage of VS-2012/2010 builds --- modules/database/src/ioc/rsrv/camsgtask.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/rsrv/camsgtask.c b/modules/database/src/ioc/rsrv/camsgtask.c index 568adc7d4..b69a39458 100644 --- a/modules/database/src/ioc/rsrv/camsgtask.c +++ b/modules/database/src/ioc/rsrv/camsgtask.c @@ -163,11 +163,11 @@ void camsgtask ( void *pParm ) int casClientInitiatingCurrentThread ( char * pBuf, size_t bufSize ) { + struct client * pClient; if ( ! rsrvCurrentClient ) return RSRV_ERROR; /* not yet initialized, or disabled via dbServer */ - struct client * pClient = ( struct client * ) - epicsThreadPrivateGet ( rsrvCurrentClient ); + pClient = ( struct client * ) epicsThreadPrivateGet ( rsrvCurrentClient ); if ( ! pClient ) return RSRV_ERROR; From 07572ab02593fa225660fdee670850c9989f5851 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 21 Feb 2025 15:47:00 -0600 Subject: [PATCH 34/36] Update submodules to released versions --- 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 f1268adb8..96061ca1c 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit f1268adb8ecbacbd74bb66c172d02d9d427bedfd +Subproject commit 96061ca1cc6d0e101b0033635396a8e6b6add68c diff --git a/modules/pvData b/modules/pvData index 144f0228c..0ef8a3617 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 144f0228cc412d2dc1eaad7e09e310697d18532f +Subproject commit 0ef8a361721bc4972743a9c9a0112f441ba36b0f diff --git a/modules/pvDatabase b/modules/pvDatabase index c070a3485..8cf550ff5 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit c070a3485b01714e500f6623780e6845bfae1f4c +Subproject commit 8cf550ff57ab8b573a95af2e9602643b8af98110 diff --git a/modules/pva2pva b/modules/pva2pva index 949b3f63c..3a08da445 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 949b3f63c2387bb92c1c22ca2f80f8d320805117 +Subproject commit 3a08da445b46e2e7029406d24425cdd3dfd7da24 diff --git a/modules/pvaClient b/modules/pvaClient index 8ed07fef9..a34876e36 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit 8ed07fef96e41d35d47ab61276e29eb1a81e7fec +Subproject commit a34876e36a56c9de9b172d6a83a9439bb330783d From 86154953f57b1796e7cb81bbc807eae120b9e840 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 21 Feb 2025 17:31:33 -0600 Subject: [PATCH 35/36] Final commit for 7.0.9 --- configure/CONFIG_BASE_VERSION | 6 +- configure/CONFIG_CA_VERSION | 2 +- configure/CONFIG_DATABASE_VERSION | 6 +- configure/CONFIG_LIBCOM_VERSION | 6 +- documentation/RELEASE_NOTES.md | 195 ++++++++++++++++++++++++++++-- 5 files changed, 193 insertions(+), 22 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index e48336bf8..86319c032 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 = 8 +EPICS_MODIFICATION = 9 # 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 d565e7ce1..905f0d590 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -6,7 +6,7 @@ EPICS_CA_MAINTENANCE_VERSION = 5 # 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 b770ea72a..546c63110 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 = 23 -EPICS_DATABASE_MAINTENANCE_VERSION = 2 +EPICS_DATABASE_MINOR_VERSION = 24 +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 bb5c55904..d1546a965 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 = 23 -EPICS_LIBCOM_MAINTENANCE_VERSION = 2 +EPICS_LIBCOM_MINOR_VERSION = 24 +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 diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index ce4088385..e201d79e6 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -8,19 +8,27 @@ under the 3.15 release to which they were originally committed.** Thus it is important to read more than just the first section to understand everything that has changed in each 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: +The external PVA submodules each have their own individual release notes files. +However the entries describing changes included in those submodules since EPICS +7.0.5 have now been copied into the appropriate place of this file. -- [normativeTypes](https://github.com/epics-base/normativeTypesCPP/blob/master/documentation/RELEASE_NOTES.md) -- [pvAccess](http://epics-base.github.io/pvAccessCPP/pvarelease_notes.html) -- [pvData](http://epics-base.github.io/pvDataCPP/release_notes.html) -- [pvDatabase](https://github.com/epics-base/pvDatabaseCPP/blob/master/documentation/RELEASE_NOTES.md) -- [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html) -- [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md) +## EPICS Release 7.0.9 -**This version of EPICS has not been released yet.** +### Core documentation published at ReadTheDocs -## Changes made on the 7.0 branch since 7.0.8.1 +The `documentation` directory's `Makefile` can now run various publication scripts including Sphinx and Doxygen to generate formatted documentation that is now being published +[at docs.epics-controls.org](https://docs.epics-controls.org/projects/base/en/latest/index.html) +and integrated into the main [EPICS Documentation website](https://docs.epics-controls.org/en/latest/index.html). +The best place to find out more about these mechanisms is the +[Contribution Guide](https://docs.epics-controls.org/en/latest/CONTRIBUTING.html) +although it doesn't currently cover the new processes added to epics-base. + +Much of the documentation generated from .dbd.pod files at build time is now +also being converted into MarkDown (.md) files and installed into the top-level +`doc` directory. Some users might find it quicker to look up information about a +record type by opening these files in a text editor intead of opening a browser +and loading the HTML versions or finding and opening the files from the EPICS +Documentation site. ### Post monitors from compress record when it's reset @@ -72,7 +80,6 @@ file from the command line, `msi` will not use the `-I`-specified paths to search for the file, but will only work relative to the current working directory, consistent with most commandline utilities. - ### Allow users to delete previously created records from the database From this release, record instances and aliases that have already been loaded @@ -106,7 +113,7 @@ already be conditionally casting to/from the appropriate type. ### Fix issues with `_FORTIFY_SOURCE=3` This release fixes the false positives failures whhen building with `_FORTIFY_SOURCE` level 3. -The override introduced with `7.0.8.1` is removed. +The override introduced in 7.0.8.1 has been removed. ### Other @@ -118,6 +125,17 @@ The override introduced with `7.0.8.1` is removed. - Add `ABORT_ON_ASSERT` flag to `CONFIG_SITE_ENV` - rationalize osdMutex +### Submodule updates + +The pvDatabase module was updated to version 4.7.2: + +* Resolved issue with changed field set in the case where the top level (master) +field ("_") is not requested by the client, but the master field callback causes +all fields to be marked as updated, rather than only those fields that have +actually been modified. + +----- + ## EPICS Release 7.0.8.1 ### Limit to `_FORTIFY_SOURCE=2` @@ -355,6 +373,50 @@ The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC expression engine and is available to all software using that (calc and calcout record types, access security library and some extensions). +### Submodule updates + +The pvData module was updated to version 8.0.6: + +- Compatible changes + - Actually enable JSON-5 output in PVStructure::Formatter::JSON when available. + - Fix unaligned access issues for some ARM/Linux targets. + +The pvAccess module was updated to version 7.1.7: + +- Changes + - Registering the PVA server with the IOC now sets the `PVAS_SERVER_PORT` + variable in the environment. + +The pva2pva module was updated to version 1.4.1: + +- Bug Fixes + - `dbLoadGroup` was fixed +- Additions + - Support for "meta" member at top of array of structs + +The pvDatabase module was updated to version 4.7.1: + +* Added data distributor plugin which can be used for distributing data between + a group of clients. The plugin is triggered by the request string of the + form: + + `_[distributor=group:;set:;trigger:;updates:;mode:]` + + The plugin parameters are optional and are described bellow: + + - group: this parameter indicates a group that client application belongs to (default value: "default"); groups of clients are completely independent of each other + + - set: this parameter designates a client set that application belongs to within its group (default value: "default") + + - trigger: this is the PV structure field that distinguishes different channel updates (default value: "timeStamp"); for example, for area detector images one could use the "uniqueId" field of the NTND structure + + - updates: this parameter configures how many sequential updates a client (or a set of clients) will receive before the data distributor starts updating the next one (default value: "1") + + - mode: this parameter configures how channel updates are to be distributed between clients in a set: + - one: update goes to one client per set + - all: update goes to all clients in a set + - default is "one" if client set id is not specified, and "all" if set id is specified + ----- ## EPICS Release 7.0.7 @@ -605,6 +667,44 @@ or if unsupported (`$TERM` not set, or Windows < 10). The `dbnd` server side filter now passes through alarm and property change events, even when not exceeding the deadband. +### Submodule updates + +The pvData module was updated to version 8.0.5: + +- Compatible changes + - Internal changes to use the YAJL API for generating JSON and JSON-5 output. + +The pvAccess module was updated to version 7.1.6: + +- Changes to caProvider + - Bug fix related to enum values. + - More internal changes to improve performance when connecting tens of + thousands of CA channels. +- Several minor internal improvements. + +The pva2pva module was updated to version 1.4.0: + +- Bug Fixes + - Apply ACF when writing to atomic group +- Additions + - Add new "structure" to @ref qsrv_group_map_types +- Changes + - Add Access Security hooks for single and group writes. + - Enable "Async Soft Channel" for output links + - When built against Base 7.0.6.1, set timeStamp.userTag from UTAG field. + - Add DTYP="QSRV Set UTag" for longin, which sets UTAG=VAL. + +The pvDatabase module was updated to version 4.7.0: + +* Added support for the whole structure (master field) server side plugins. + The whole structure is identified as the `_` string, and a pvRequest string + that applies a plugin to it takes the form: + + `field(_[XYZ=A:3;B:uniqueId])` + + where `XYZ` is the name of a specific filter plugin that takes parameters + `A` and `B` with values `3` and `uniqueId` respectively. + ----- ## EPICS Release 7.0.6.1 @@ -671,6 +771,15 @@ This was done to simplify the code and may have improved performance slightly fo Many of the built-in record types have had improvements to their documentation with additional fields added to the tables, rewrites of descriptions and links to other documents added or fixed. +### Submodule updates + +The pvAccess module was updated to version 7.1.4: + +- Changes to caProvider + - Resolve issues with pv structures that don't have a value field + - Add NULL checks for handling unusual structures + - Speed up channel creation when using large numbers of channels + ----- ## EPICS Release 7.0.6 @@ -911,6 +1020,39 @@ Test programs written directly in Perl as a `.plt` script should implement a similar timeout for themselves. The "netget" test in Base does this in a way that works on Windows as well as Unix-like hosts. +### Submodule updates + +The pvAccess module was updated to version 7.1.4: + +- Changes + - Adjust argument parsing with pvput (Jesus Vasquez). + +The pva2pva module was updated to version 1.3.1: + +- Bug Fixes + - Correct handling for server side filters. +- Changes + - Syncing softMain.cpp with epics-base + +The pvDatabase module was updated to version 4.6.0: + +* Access Security is now supported. +* special has been revised and extended. +* addRecord, removeRecord, processRecord, and traceRecord are replaced by pvdbcr versions. +* support is DEPRECATED + +The pvaClient module was updated to version 4.8.0: + +* `PvaClientNTMultiData::getChannelChangeFlags` is a new method. It fixes + issue #66. +* Fix for issue #68. Both `PvaClientArray` and `PvaClientField` are not longer + present. Neither was previously implemented. +* Several public methods are now protected. They were never meant to be called + by clients. +* Issue #70 has been fixed. +* Changes was made to increase the performance of `pvaMultiChannel`. +* doxygen changes were made. + ----- ## EPICS Release 7.0.5 @@ -1198,6 +1340,35 @@ 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. + +### Submodule updates + +The pvData module was updated to version 8.0.4: + +- Incompatible changes + - Remove `ByteBuffer::align()` +- Compatible changes + - Deprecate `SerializableControl::alignBuffer()` and + `DeserializableControl::alignData()` + - `shared_vector_convert<>()` fix convert of empty, untyped, array + +The pvAccess module was updated to version 7.1.3: + +- Bug fixes + - Increase default TCP timeout to 40 seconds. + Applies a 4/3 multiplier on `$EPICS_PVA_CONN_TMO` for compatibility. + - CA Provider implementation restructured to simplify, reduce duplication + and fix issues #163 and #165. +- Changes + - Enable building of pvtools to all except vxWorks, RTEMS and iOS. + +The pva2pva module was updated to version 1.3.0: + +- Changes + - Add `dbLoadGroup()` iocsh function to read group JSON definitions + from a file. Mappings in files must refer to full record names + instead of fields. eg. 'recname.VAL' instead of 'VAL'. + ----- ## EPICS Release 7.0.4.1 From 7bd3e7aa2e2483bc4a2878742504fac2651487b0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 21 Feb 2025 17:45:00 -0600 Subject: [PATCH 36/36] Update version numbers and submodules after release --- configure/CONFIG_BASE_VERSION | 7 ++----- configure/CONFIG_CA_VERSION | 4 ++-- configure/CONFIG_DATABASE_VERSION | 4 ++-- configure/CONFIG_LIBCOM_VERSION | 4 ++-- documentation/RELEASE_NOTES.md | 8 ++++++++ modules/normativeTypes | 2 +- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 11 files changed, 22 insertions(+), 17 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 86319c032..eeb577824 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -52,11 +52,11 @@ EPICS_MODIFICATION = 9 # 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 @@ -71,6 +71,3 @@ endif EPICS_SHORT_VERSION=$(EPICS_VERSION).$(EPICS_REVISION).$(EPICS_MODIFICATION)$(EPICS_PATCH_VSTRING) EPICS_VERSION_NUMBER=$(EPICS_SHORT_VERSION)$(EPICS_DEV_SNAPSHOT)$(EPICS_SITE_VSTRING) EPICS_VERSION_STRING="EPICS Version $(EPICS_VERSION_NUMBER)" - -# Provide this in case anyone is still using the old name -COMMIT_DATE="-no-date-" diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index 905f0d590..770e1965f 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -2,11 +2,11 @@ EPICS_CA_MAJOR_VERSION = 4 EPICS_CA_MINOR_VERSION = 14 -EPICS_CA_MAINTENANCE_VERSION = 5 +EPICS_CA_MAINTENANCE_VERSION = 6 # 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 546c63110..5c5eae1ee 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -2,11 +2,11 @@ EPICS_DATABASE_MAJOR_VERSION = 3 EPICS_DATABASE_MINOR_VERSION = 24 -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 d1546a965..7f1487489 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -2,11 +2,11 @@ EPICS_LIBCOM_MAJOR_VERSION = 3 EPICS_LIBCOM_MINOR_VERSION = 24 -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 e201d79e6..732c98654 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -12,6 +12,14 @@ The external PVA submodules each have their own individual release notes files. However the entries describing changes included in those submodules since EPICS 7.0.5 have now been copied into the appropriate place of this file. +__This version of EPICS has not been released yet.__ + +## Changes made on the 7.0 branch since 7.0.9 + +__Add new items below here__ + +----- + ## EPICS Release 7.0.9 ### Core documentation published at ReadTheDocs 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 96061ca1c..dafb6aad3 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 96061ca1cc6d0e101b0033635396a8e6b6add68c +Subproject commit dafb6aad31a99f8d825a1f77aa919c82bb28e0cf diff --git a/modules/pvData b/modules/pvData index 0ef8a3617..1c5f75bcd 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 0ef8a361721bc4972743a9c9a0112f441ba36b0f +Subproject commit 1c5f75bcd6c387f5913076027e54cf7312b25643 diff --git a/modules/pvDatabase b/modules/pvDatabase index 8cf550ff5..073d2acaf 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit 8cf550ff57ab8b573a95af2e9602643b8af98110 +Subproject commit 073d2acafc7109178d319109ad435131a80fed0e diff --git a/modules/pva2pva b/modules/pva2pva index 3a08da445..8fa231352 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 3a08da445b46e2e7029406d24425cdd3dfd7da24 +Subproject commit 8fa231352dac32c08734eb04cf4b12e76895a261 diff --git a/modules/pvaClient b/modules/pvaClient index a34876e36..09cf31752 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit a34876e36a56c9de9b172d6a83a9439bb330783d +Subproject commit 09cf317521bfa172e3e00a5631bf0c70b88157ba