From 9f660f2238a6efe85af8a49510edeaee69b6641a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 4 Sep 2023 09:50:08 +0200 Subject: [PATCH 01/66] add initHookAtPrepare --- modules/database/src/ioc/db/dbUnitTest.c | 2 ++ modules/libcom/src/iocsh/initHooks.c | 3 +++ modules/libcom/src/iocsh/initHooks.h | 12 ++++++++++++ 3 files changed, 17 insertions(+) diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c index 2c7efd8a9..bf4ec205b 100644 --- a/modules/database/src/ioc/db/dbUnitTest.c +++ b/modules/database/src/ioc/db/dbUnitTest.c @@ -50,6 +50,7 @@ void testdbPrepare(void) { if(!testEvtLock) testEvtLock = epicsMutexMustCreate(); + initHookAnnounce(initHookAfterPrepareDatabase); } void testdbReadDatabase(const char* file, @@ -94,6 +95,7 @@ void testIocShutdownOk(void) void testdbCleanup(void) { + initHookAnnounce(initHookBeforeCleanupDatabase); dbFreeBase(pdbbase); db_cleanup_events(); initHookFree(); diff --git a/modules/libcom/src/iocsh/initHooks.c b/modules/libcom/src/iocsh/initHooks.c index 750a76d42..90b1de2c5 100644 --- a/modules/libcom/src/iocsh/initHooks.c +++ b/modules/libcom/src/iocsh/initHooks.c @@ -139,6 +139,9 @@ const char *initHookName(int state) "initHookBeforeFree", "initHookAfterShutdown", + "initHookAfterPrepareDatabase", + "initHookBeforeCleanupDatabase", + "initHookAfterInterruptAccept", "initHookAtEnd" }; diff --git a/modules/libcom/src/iocsh/initHooks.h b/modules/libcom/src/iocsh/initHooks.h index de4a72a32..a5ad93d3f 100644 --- a/modules/libcom/src/iocsh/initHooks.h +++ b/modules/libcom/src/iocsh/initHooks.h @@ -71,6 +71,7 @@ extern "C" { * if the IOC is later paused and restarted. */ typedef enum { + // iocInit() begins initHookAtIocBuild = 0, /**< Start of iocBuild() / iocInit() */ initHookAtBeginning, /**< Database sanity checks passed */ @@ -133,6 +134,17 @@ typedef enum { initHookAfterShutdown, // iocShutdown() ends + /** \brief Called during testdbPrepare() + * Use this hook to repeat actions each time an empty test database is initialized. + * \since UNRELEASED Added, triggered only by unittest code. + */ + initHookAfterPrepareDatabase, + /** \brief Called during testdbCleanup() + * Use this hook to perform cleanup each time before a test database is free()'d. + * \since UNRELEASED Added, triggered only by unittest code. + */ + initHookBeforeCleanupDatabase, + /* Deprecated states: */ /** Only announced once. Deprecated in favor of initHookAfterDatabaseRunning */ initHookAfterInterruptAccept, From 3b22e5f7109dac8a9e9d20bc9715d54bcf543464 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 12 Sep 2023 11:45:33 +0200 Subject: [PATCH 02/66] doc dbLock.h --- modules/database/src/ioc/db/dbLock.h | 48 +++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbLock.h b/modules/database/src/ioc/db/dbLock.h index 3d617f995..8fe068ce9 100644 --- a/modules/database/src/ioc/db/dbLock.h +++ b/modules/database/src/ioc/db/dbLock.h @@ -24,18 +24,64 @@ extern "C" { struct dbCommon; struct dbBase; +/** @brief Lock multiple records. + * + * A dbLocker allows a caller to simultaneously lock multiple records. + * The list of records is provided to dbLockerAlloc(). + * And the resulting dbLocker can be locked/unlocked repeatedly. + * + * Each thread can only lock one dbLocker at a time. + * While locked, dbScanLock() may be called only on those records + * included in the dbLocker. + * + * @since 3.16.0.1 + */ +struct dbLocker; typedef struct dbLocker dbLocker; +/** @brief Lock a record for modification. + * + * While locked, caller may access record using eg. dbGet() or dbPut(), + * but not dbGetField() or dbPutField(). + * The caller must later call dbScanUnlock(). + * dbScanLock() may be called again as the record lock behaves as a recursive mutex. + */ DBCORE_API void dbScanLock(struct dbCommon *precord); +/** @brief Unlock a record. + * + * Reverse the action of dbScanLock() + */ DBCORE_API void dbScanUnlock(struct dbCommon *precord); +/** @brief Prepare to lock a set of records. + * @param precs Array of nrecs dbCommon pointers. + * @param nrecs Length of precs array + * @param flags Set to 0 + * @return NULL on error + * @since 3.16.0.1 + */ DBCORE_API dbLocker *dbLockerAlloc(struct dbCommon * const *precs, size_t nrecs, unsigned int flags); -DBCORE_API void dbLockerFree(dbLocker *); +/** @brief Free dbLocker allocated by dbLockerAlloc() + * @param plocker Must not be NULL + * @since 3.16.0.1 + */ +DBCORE_API void dbLockerFree(dbLocker *plocker); +/** @brief Lock all records of dbLocker + * + * While locked, caller may access any associated record passed to dbLockerAlloc() . + * dbScanLockMany() may not be called again (multi-lock is not recursive). + * dbScanLock()/dbScanUnlock() may be called on individual record. + * The caller must later call dbScanUnlockMany(). + * @since 3.16.0.1 + */ DBCORE_API void dbScanLockMany(dbLocker*); +/** @brief Unlock all records of dbLocker + * @since 3.16.0.1 + */ DBCORE_API void dbScanUnlockMany(dbLocker*); DBCORE_API unsigned long dbLockGetLockId( From 39b5c01c5df06fb7cc0b241fe8ee7140c454a5c7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Sep 2023 14:00:53 +0200 Subject: [PATCH 03/66] minor --- modules/database/src/ioc/db/dbLockPvt.h | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/database/src/ioc/db/dbLockPvt.h b/modules/database/src/ioc/db/dbLockPvt.h index 520241c3e..99ab590df 100644 --- a/modules/database/src/ioc/db/dbLockPvt.h +++ b/modules/database/src/ioc/db/dbLockPvt.h @@ -10,6 +10,7 @@ #define DBLOCKPVT_H #include "dbLock.h" +#include "epicsMutex.h" #include "epicsSpin.h" /* Define to enable additional error checking */ From 5aca4c684cc87158ded4c4d4c3303b4c018e43fa Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Sep 2023 17:03:17 +0200 Subject: [PATCH 04/66] dbEvent minor --- modules/database/src/ioc/db/dbEvent.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index d5c930dfc..653ea411c 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -1017,6 +1017,7 @@ static int event_read ( struct event_que *ev_que ) notifiedRemaining = eventsRemaining; } LOCKEVQUE (ev_que); + /* concurrent db_cancel_event() may have free()'d pevent */ /* * check to see if this event has been canceled each @@ -1029,13 +1030,10 @@ static int event_read ( struct event_que *ev_que ) ev_que->evUser->pSuicideEvent = NULL; } else { + pevent->callBackInProgress = FALSE; if ( pevent->user_sub==NULL && pevent->npend==0u ) { - pevent->callBackInProgress = FALSE; epicsEventSignal ( ev_que->evUser->pflush_sem ); } - else { - pevent->callBackInProgress = FALSE; - } } } db_delete_field_log(pfl); From 3d25756065fb0bb311321fcf226a1fad0a3e537c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 14 Sep 2023 09:20:43 +0200 Subject: [PATCH 05/66] privatize evSubscrip --- modules/database/src/ioc/db/dbChannel.h | 10 ++++++++-- modules/database/src/ioc/db/dbEvent.c | 1 + modules/database/test/ioc/db/dbPutGetTest.c | 2 ++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h index 23ffd7d09..70e422405 100644 --- a/modules/database/src/ioc/db/dbChannel.h +++ b/modules/database/src/ioc/db/dbChannel.h @@ -41,7 +41,12 @@ extern "C" { /** * event subscription */ -typedef struct evSubscrip { +struct evSubscrip; + +typedef struct evSubscrip evSubscrip; + +#ifdef EPICS_PRIVATE_API +struct evSubscrip { ELLNODE node; struct dbChannel * chan; EVENTFUNC * user_sub; @@ -54,7 +59,8 @@ typedef struct evSubscrip { char useValque; char callBackInProgress; char enabled; -} evSubscrip; +}; +#endif typedef struct chFilter chFilter; diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 653ea411c..3016630fb 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -18,6 +18,7 @@ * Ralph Lange */ +#define EPICS_PRIVATE_API #include #include #include diff --git a/modules/database/test/ioc/db/dbPutGetTest.c b/modules/database/test/ioc/db/dbPutGetTest.c index 8f539407d..3a5155661 100644 --- a/modules/database/test/ioc/db/dbPutGetTest.c +++ b/modules/database/test/ioc/db/dbPutGetTest.c @@ -4,6 +4,8 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +#define EPICS_PRIVATE_API + #include #include From fab8fd7102143a661a81cf7163dd889601eb015c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 14 Sep 2023 10:11:25 +0200 Subject: [PATCH 06/66] dbEvent: handle multiple db_event_cancel() Allow for multiple db_event_cancel() (concurrent or self-cancel) prior to event_task wakeup. In db_event_cancel(), immediate free() only if idle (not queued or in progress). Otherwise, defer free() to event task. Avoids need to immediately expunge canceled event from queue. Allow event task to process canceled events as normal (except no user_sub) until npend==0. --- modules/database/src/ioc/db/dbChannel.h | 13 +- modules/database/src/ioc/db/dbEvent.c | 179 ++++++++---------------- 2 files changed, 73 insertions(+), 119 deletions(-) diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h index 70e422405..d4cb9e9bc 100644 --- a/modules/database/src/ioc/db/dbChannel.h +++ b/modules/database/src/ioc/db/dbChannel.h @@ -49,15 +49,24 @@ typedef struct evSubscrip evSubscrip; struct evSubscrip { ELLNODE node; struct dbChannel * chan; + /* user_sub==NULL used to indicate db_cancel_event() */ EVENTFUNC * user_sub; void * user_arg; + /* associated queue, may be shared with other evSubscrip */ struct event_que * ev_que; + /* NULL if !npend. if npend!=0, pointer to last event added to event_que::valque */ db_field_log ** pLastLog; - unsigned long npend; /**< n times this event is on the queue */ - unsigned long nreplace; /**< n times replacing event on the queue */ + /* n times this event is on the queue */ + unsigned long npend; + /* n times replacing event on the queue */ + unsigned long nreplace; + /* DBE mask */ unsigned char select; + /* if set, subscription will yield dbfl_type_val */ char useValque; + /* event_task is handling this subscription */ char callBackInProgress; + /* this node added to dbCommon::mlis */ char enabled; }; #endif diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 3016630fb..38ec9e701 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -76,7 +76,6 @@ struct event_que { unsigned short getix; unsigned short quota; /* the number of assigned entries*/ unsigned short nDuplicates; /* N events duplicated on this q */ - unsigned short nCanceled; /* the number of canceled entries */ unsigned possibleStall; }; @@ -92,7 +91,7 @@ struct event_user { void *extralabor_arg;/* parameter to above */ epicsThreadId taskid; /* event handler task id */ - struct evSubscrip *pSuicideEvent; /* event that is deleting itself */ + epicsUInt32 pflush_seq; /* worker cycle count for synchronization */ unsigned queovr; /* event que overflow count */ unsigned char pendexit; /* exit pend task */ unsigned char extra_labor; /* if set call extra labor func */ @@ -123,10 +122,9 @@ static void *dbevFieldLogFreeList; static char *EVENT_PEND_NAME = "eventTask"; -static struct evSubscrip canceledEvent; - static epicsMutexId stopSync; +/* unused space in queue (EVENTQUESIZE when empty) */ static unsigned short ringSpace ( const struct event_que *pevq ) { if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) { @@ -140,17 +138,11 @@ static unsigned short ringSpace ( const struct event_que *pevq ) return 0; } -/* - * db_event_list () - */ int db_event_list ( const char *pname, unsigned level ) { return dbel ( pname, level ); } -/* - * dbel () - */ int dbel ( const char *pname, unsigned level ) { DBADDR addr; @@ -218,7 +210,6 @@ int dbel ( const char *pname, unsigned level ) if ( level > 2 ) { unsigned nDuplicates; - unsigned nCanceled; if ( pevent->nreplace ) { printf (", discarded by replacement=%ld", pevent->nreplace); } @@ -227,14 +218,10 @@ int dbel ( const char *pname, unsigned level ) } LOCKEVQUE(pevent->ev_que); nDuplicates = pevent->ev_que->nDuplicates; - nCanceled = pevent->ev_que->nCanceled; UNLOCKEVQUE(pevent->ev_que); if ( nDuplicates ) { printf (", duplicate count =%u\n", nDuplicates ); } - if ( nCanceled ) { - printf (", canceled count =%u\n", nCanceled ); - } } if ( level > 3 ) { @@ -331,7 +318,6 @@ dbEventCtx db_init_events (void) evUser->flowCtrlMode = FALSE; evUser->extraLaborBusy = FALSE; - evUser->pSuicideEvent = NULL; return (dbEventCtx) evUser; fail: if(evUser->lock) @@ -462,8 +448,7 @@ dbEventSubscription db_add_event ( while ( TRUE ) { int success = 0; LOCKEVQUE ( ev_que ); - success = ( ev_que->quota + ev_que->nCanceled < - EVENTQUESIZE - EVENTENTRIES ); + success = ( ev_que->quota < EVENTQUESIZE - EVENTENTRIES ); if ( success ) { ev_que->quota += EVENTENTRIES; } @@ -580,62 +565,52 @@ static void event_remove ( struct event_que *ev_que, void db_cancel_event (dbEventSubscription event) { struct evSubscrip * const pevent = (struct evSubscrip *) event; - unsigned short getix; + struct event_que *que = pevent->ev_que; + char sync = 0; db_event_disable ( event ); - /* - * flag the event as canceled by NULLing out the callback handler - * - * make certain that the event isn't being accessed while - * its call back changes - */ - LOCKEVQUE (pevent->ev_que); + LOCKEVQUE (que); - pevent->user_sub = NULL; + pevent->user_sub = NULL; /* callback pointer doubles as canceled flag */ - /* - * purge this event from the queue - * - * Its better to take this approach rather than waiting - * for the event thread to finish removing this event - * from the queue because the event thread will not - * process if we are in flow control mode. Since blocking - * here will block CA's TCP input queue then a dead lock - * would be possible. - */ - for ( getix = pevent->ev_que->getix; - pevent->ev_que->evque[getix] != EVENTQEMPTY; ) { - if ( pevent->ev_que->evque[getix] == pevent ) { - assert ( pevent->ev_que->nCanceled < USHRT_MAX ); - pevent->ev_que->nCanceled++; - event_remove ( pevent->ev_que, getix, &canceledEvent ); - } - getix = RNGINC ( getix ); - if ( getix == pevent->ev_que->getix ) { - break; - } - } - assert ( pevent->npend == 0u ); + if(pevent->callBackInProgress) { + /* this event callback is pending or in-progress in event_task. */ + if(pevent->ev_que->evUser->taskid != epicsThreadGetIdSelf()) + sync = 1; /* concurrent to event_task, so wait */ - if ( pevent->ev_que->evUser->taskid == epicsThreadGetIdSelf() ) { - pevent->ev_que->evUser->pSuicideEvent = pevent; - } - else { - while ( pevent->callBackInProgress ) { - UNLOCKEVQUE (pevent->ev_que); - epicsEventMustWait ( pevent->ev_que->evUser->pflush_sem ); - LOCKEVQUE (pevent->ev_que); - } + } else if(pevent->npend) { + /* some (now defunct) events in the queue, defer free() to event_task */ + + } else { + /* no other references, cleanup now */ + + pevent->ev_que->quota -= EVENTENTRIES; + freeListFree ( dbevEventSubscriptionFreeList, pevent ); } - pevent->ev_que->quota -= EVENTENTRIES; + UNLOCKEVQUE (que); - UNLOCKEVQUE (pevent->ev_que); - - freeListFree ( dbevEventSubscriptionFreeList, pevent ); - - return; + if(sync) { + /* wait for worker to cycle */ + struct event_user *evUser = que->evUser; + epicsUInt32 curSeq; + epicsMutexMustLock ( evUser->lock ); + /* grab current cycle counter, then wait for it to change */ + curSeq = evUser->pflush_seq; + do { + epicsMutexUnlock( evUser->lock ); + epicsEventMustWait(evUser->pflush_sem); + /* The complexity needed to track the # of waiters does not seem + * worth it for the relatively rare situation of concurrent cancel. + * So uncondtionally re-trigger. This will result in one spurious + * wakeup for each cancellation. + */ + epicsEventTrigger(evUser->pflush_sem); + epicsMutexMustLock ( evUser->lock ); + } while(curSeq == evUser->pflush_seq); + epicsMutexUnlock( evUser->lock ); + } } /* @@ -935,10 +910,7 @@ void db_post_single_event (dbEventSubscription event) */ static int event_read ( struct event_que *ev_que ) { - db_field_log *pfl; int notifiedRemaining = 0; - void ( *user_sub ) ( void *user_arg, struct dbChannel *chan, - int eventsRemaining, db_field_log *pfl ); /* * evUser ring buffer must be locked for the multiple @@ -959,19 +931,7 @@ static int event_read ( struct event_que *ev_que ) while ( ev_que->evque[ev_que->getix] != EVENTQEMPTY ) { struct evSubscrip *pevent = ev_que->evque[ev_que->getix]; int eventsRemaining; - - pfl = ev_que->valque[ev_que->getix]; - if ( pevent == &canceledEvent ) { - ev_que->evque[ev_que->getix] = EVENTQEMPTY; - if (ev_que->valque[ev_que->getix]) { - db_delete_field_log(ev_que->valque[ev_que->getix]); - ev_que->valque[ev_que->getix] = NULL; - } - ev_que->getix = RNGINC ( ev_que->getix ); - assert ( ev_que->nCanceled > 0 ); - ev_que->nCanceled--; - continue; - } + db_field_log *pfl = ev_que->valque[ev_que->getix]; /* * Simple type values queued up for reliable interprocess @@ -981,13 +941,7 @@ static int event_read ( struct event_que *ev_que ) event_remove ( ev_que, ev_que->getix, EVENTQEMPTY ); ev_que->getix = RNGINC ( ev_que->getix ); - eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY && !ev_que->nCanceled; - - /* - * create a local copy of the call back parameters while - * we still have the lock - */ - user_sub = pevent->user_sub; + eventsRemaining = ev_que->evque[ev_que->getix] != EVENTQEMPTY; /* * Next event pointer can be used by event tasks to determine @@ -999,14 +953,12 @@ static int event_read ( struct event_que *ev_que ) * record lock, and it is calling db_post_events() waiting * for the event queue lock (which this thread now has). */ - if ( user_sub ) { - /* - * This provides a way to test to see if an event is in use - * despite the fact that the event queue does not point to - * it. - */ + if ( pevent->user_sub ) { + EVENTFUNC* user_sub = pevent->user_sub; pevent->callBackInProgress = TRUE; + UNLOCKEVQUE (ev_que); + /* Run post-event-queue filter chain */ if (ellCount(&pevent->chan->post_chain)) { pfl = dbChannelRunPostChain(pevent->chan, pfl); @@ -1017,25 +969,15 @@ static int event_read ( struct event_que *ev_que ) eventsRemaining, pfl ); notifiedRemaining = eventsRemaining; } - LOCKEVQUE (ev_que); - /* concurrent db_cancel_event() may have free()'d pevent */ - /* - * check to see if this event has been canceled each - * time that the callBackInProgress flag is set to false - * while we have the event queue lock, and post the flush - * complete sem if there are no longer any events on the - * queue - */ - if ( ev_que->evUser->pSuicideEvent == pevent ) { - ev_que->evUser->pSuicideEvent = NULL; - } - else { - pevent->callBackInProgress = FALSE; - if ( pevent->user_sub==NULL && pevent->npend==0u ) { - epicsEventSignal ( ev_que->evUser->pflush_sem ); - } - } + LOCKEVQUE (ev_que); + + pevent->callBackInProgress = FALSE; + } + /* callback may have called db_cancel_event(), so must check user_sub again */ + if(!pevent->user_sub && !pevent->npend) { + pevent->ev_que->quota -= EVENTENTRIES; + freeListFree ( dbevEventSubscriptionFreeList, pevent ); } db_delete_field_log(pfl); } @@ -1050,9 +992,6 @@ static int event_read ( struct event_que *ev_que ) return DB_EVENT_OK; } -/* - * EVENT_TASK() - */ static void event_task (void *pParm) { struct event_user * const evUser = (struct event_user *) pParm; @@ -1069,6 +1008,7 @@ static void event_task (void *pParm) do { void (*pExtraLaborSub) (void *); void *pExtraLaborArg; + char wake; epicsEventMustWait(evUser->ppendsem); /* @@ -1093,15 +1033,20 @@ static void event_task (void *pParm) } evUser->extraLaborBusy = FALSE; - for ( ev_que = &evUser->firstque; ev_que; - ev_que = ev_que->nextque ) { + for ( ev_que = &evUser->firstque; ev_que; ev_que = ev_que->nextque ) { + /* unlock during iteration is safe as event_que will not be free'd */ epicsMutexUnlock ( evUser->lock ); event_read (ev_que); epicsMutexMustLock ( evUser->lock ); } pendexit = evUser->pendexit; + + evUser->pflush_seq++; + epicsMutexUnlock ( evUser->lock ); + epicsEventSignal(evUser->pflush_sem); + } while( ! pendexit ); epicsMutexDestroy(evUser->firstque.writelock); From 7c4a21eab44183a84f25ea234ce2fde8ad08c4ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Mon, 31 Jul 2023 11:36:11 -0300 Subject: [PATCH 07/66] libCom: detect support for backtrace() with __has_include. This is necessary in order to build epics-base with musl libc, for example, and any other C libraries which don't include this functionality. In order to not regress builds with older compilers, we still support the uclibc check. Furthermore, it has been checked that uclibc-ng (the maintained version of uclibc) doesn't install the header when the functionality is disabled [1] [2]. To avoid repetition, we don't define HAS_EXECINFO to 0 when it is not available. [1] https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Makefile.in?id=cdb07d2cd52af39feb425e6d36c02b30916b9f0a#n224 [2] https://cgit.uclibc-ng.org/cgi/cgit/uclibc-ng.git/tree/Makefile.in?id=cdb07d2cd52af39feb425e6d36c02b30916b9f0a#n277 --- modules/libcom/src/osi/os/posix/osdExecinfoBackTrace.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/posix/osdExecinfoBackTrace.cpp b/modules/libcom/src/osi/os/posix/osdExecinfoBackTrace.cpp index 8d50e6a8e..9be48755a 100644 --- a/modules/libcom/src/osi/os/posix/osdExecinfoBackTrace.cpp +++ b/modules/libcom/src/osi/os/posix/osdExecinfoBackTrace.cpp @@ -12,10 +12,13 @@ #include // execinfo.h may not be present if uclibc is configured to omit backtrace() -#if !defined(__UCLIBC_MAJOR__) || defined(__UCLIBC_HAS_EXECINFO__) +// some C libraries, such as musl, don't have execinfo.h at all +#if defined(__has_include) +# if __has_include() +# define HAS_EXECINFO 1 +# endif +#elif !defined(__UCLIBC_MAJOR__) || defined(__UCLIBC_HAS_EXECINFO__) # define HAS_EXECINFO 1 -#else -# define HAS_EXECINFO 0 #endif #if HAS_EXECINFO From 45b3bce51534178a0baaf3912a17827caa1b000d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 23 May 2023 10:30:31 -0700 Subject: [PATCH 08/66] epicsThreadShow() zombies Flag when the thread has returned, but the tracking struct is still around. eg. in need of joining. --- modules/libcom/src/osi/os/Linux/osdThread.h | 1 + modules/libcom/src/osi/os/Linux/osdThreadExtra.c | 6 ++++-- modules/libcom/src/osi/os/RTEMS-score/osdThread.c | 9 ++++++++- modules/libcom/src/osi/os/WIN32/osdThread.c | 6 ++++++ modules/libcom/src/osi/os/posix/osdThread.c | 3 +++ modules/libcom/src/osi/os/posix/osdThread.h | 1 + modules/libcom/src/osi/os/posix/osdThreadExtra.c | 6 ++++-- 7 files changed, 27 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/osi/os/Linux/osdThread.h b/modules/libcom/src/osi/os/Linux/osdThread.h index 7f0a8bbc9..4bf7f29a6 100644 --- a/modules/libcom/src/osi/os/Linux/osdThread.h +++ b/modules/libcom/src/osi/os/Linux/osdThread.h @@ -36,6 +36,7 @@ typedef struct epicsThreadOSD { int isEpicsThread; int isRealTimeScheduled; int isOnThreadList; + int isRunning; unsigned int osiPriority; int joinable; char name[1]; /* actually larger */ diff --git a/modules/libcom/src/osi/os/Linux/osdThreadExtra.c b/modules/libcom/src/osi/os/Linux/osdThreadExtra.c index 813846bc2..e10c6fcc5 100644 --- a/modules/libcom/src/osi/os/Linux/osdThreadExtra.c +++ b/modules/libcom/src/osi/os/Linux/osdThreadExtra.c @@ -23,6 +23,7 @@ #include #include +#include "epicsAtomic.h" #include "epicsStdio.h" #include "ellLib.h" #include "epicsEvent.h" @@ -45,11 +46,12 @@ void epicsThreadShowInfo(epicsThreadId pthreadInfo, unsigned int level) if (!status) priority = param.sched_priority; } - fprintf(epicsGetStdout(),"%16.16s %14p %8lu %3d%8d %8.8s\n", + fprintf(epicsGetStdout(),"%16.16s %14p %8lu %3d%8d %8.8s%s\n", pthreadInfo->name,(void *) pthreadInfo,(unsigned long)pthreadInfo->lwpId, pthreadInfo->osiPriority,priority, - pthreadInfo->isSuspended ? "SUSPEND" : "OK"); + pthreadInfo->isSuspended ? "SUSPEND" : "OK", + epicsAtomicGetIntT(&pthreadInfo->isRunning) ? "" : " ZOMBIE"); } } diff --git a/modules/libcom/src/osi/os/RTEMS-score/osdThread.c b/modules/libcom/src/osi/os/RTEMS-score/osdThread.c index 110951445..7d37bbe48 100644 --- a/modules/libcom/src/osi/os/RTEMS-score/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS-score/osdThread.c @@ -53,6 +53,7 @@ struct taskVar { rtems_id join_barrier; /* only valid if joinable */ int refcnt; int joinable; + int isRunning; EPICSTHREADFUNC funptr; void *parm; unsigned int threadVariableCapacity; @@ -197,6 +198,7 @@ threadWrapper (rtems_task_argument arg) osdThreadHooksRun((epicsThreadId)v->id); (*v->funptr)(v->parm); epicsExitCallAtThreadExits (); + epicsAtomicSetIntT(&v->isRunning, 0); taskVarLock (); if (v->back) v->back->forw = v->forw; @@ -239,6 +241,7 @@ setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr, v->refcnt = joinable ? 2 : 1; v->threadVariableCapacity = 0; v->threadVariables = NULL; + v->isRunning = 1; if (joinable) { char c[3]; strncpy(c, v->name, 3); @@ -797,7 +800,11 @@ epicsThreadShowInfo (struct taskVar *v, unsigned int level) fprintf(epicsGetStdout(),"+--------+-----------+--------+--------+---------------------+\n"); } else { fprintf(epicsGetStdout(),"%9.8x", (int)v->id); - showInternalTaskInfo (v->id); + if(epicsAtomicGetIntT(&v->isRunning)) { + showInternalTaskInfo (v->id); + } else { + fprintf(epicsGetStdout(),"%-30s", " *** ZOMBIE task! ***"); + } fprintf(epicsGetStdout()," %s\n", v->name); } } diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 1cfeb3767..5e9eeb435 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -102,6 +102,7 @@ typedef struct epicsThreadOSD { unsigned epicsPriority; char isSuspended; int joinable; + int isRunning; HANDLE timer; /* waitable timer */ } win32ThreadParam; @@ -519,6 +520,8 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) epicsExitCallAtThreadExits (); + epicsAtomicSetIntT(&pParm->isRunning, 0); + /* On Windows we could omit this and rely on the callback given to FlsAlloc() to free. * However < vista doesn't implement FLS at all, and WINE (circa 5.0.3) doesn't * implement fully (dtor never runs). So for EPICS threads, we explicitly @@ -540,6 +543,7 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName ) pParmWIN32->pName = (char *) ( pParmWIN32 + 1 ); strcpy ( pParmWIN32->pName, pName ); pParmWIN32->isSuspended = 0; + pParmWIN32->isRunning = 1; epicsAtomicIncrIntT(&pParmWIN32->refcnt); #ifdef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION pParmWIN32->timer = CreateWaitableTimerEx(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS); @@ -1044,6 +1048,8 @@ static void epicsThreadShowInfo ( epicsThreadId id, unsigned level ) fprintf (epicsGetStdout(), " %-8p %-8p ", (void *) pParm->handle, (void *) pParm->parm ); } + if(!epicsAtomicGetIntT(&pParm->isRunning)) + fprintf (epicsGetStdout(), " ZOMBIE"); } else { fprintf (epicsGetStdout(), diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 5fa85d4a5..6142e73c5 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -173,6 +173,7 @@ static epicsThreadOSD * create_threadInfo(const char *name) pthreadInfo = calloc(1,sizeof(*pthreadInfo) + strlen(name)); if(!pthreadInfo) return NULL; + pthreadInfo->isRunning = 1; pthreadInfo->suspendEvent = epicsEventCreate(epicsEventEmpty); if(!pthreadInfo->suspendEvent){ free(pthreadInfo); @@ -441,6 +442,8 @@ static void * start_routine(void *arg) (*pthreadInfo->createFunc)(pthreadInfo->createArg); epicsExitCallAtThreadExits (); + + epicsAtomicSetIntT(&pthreadInfo->isRunning, 0); return(0); } diff --git a/modules/libcom/src/osi/os/posix/osdThread.h b/modules/libcom/src/osi/os/posix/osdThread.h index 58065a497..ea49030a3 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.h +++ b/modules/libcom/src/osi/os/posix/osdThread.h @@ -34,6 +34,7 @@ typedef struct epicsThreadOSD { int isEpicsThread; int isRealTimeScheduled; int isOnThreadList; + int isRunning; unsigned int osiPriority; int joinable; char name[1]; /* actually larger */ diff --git a/modules/libcom/src/osi/os/posix/osdThreadExtra.c b/modules/libcom/src/osi/os/posix/osdThreadExtra.c index 0fb3023f2..4344110f0 100644 --- a/modules/libcom/src/osi/os/posix/osdThreadExtra.c +++ b/modules/libcom/src/osi/os/posix/osdThreadExtra.c @@ -12,6 +12,7 @@ /* This is part of the posix implementation of epicsThread */ +#include "epicsAtomic.h" #include "epicsStdio.h" #include "ellLib.h" #include "epicsEvent.h" @@ -35,11 +36,12 @@ void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level) status = pthread_getschedparam(pthreadInfo->tid,&policy,¶m); if(!status) priority = param.sched_priority; } - fprintf(epicsGetStdout(),"%16.16s %14p %12lu %3d%8d %8.8s\n", + fprintf(epicsGetStdout(),"%16.16s %14p %12lu %3d%8d %8.8s%s\n", pthreadInfo->name,(void *) pthreadInfo,(unsigned long)pthreadInfo->tid, pthreadInfo->osiPriority,priority, - pthreadInfo->isSuspended?"SUSPEND":"OK"); + pthreadInfo->isSuspended?"SUSPEND":"OK", + epicsAtomicGetIntT(&pthreadInfo->isRunning) ? "" : " ZOMBIE"); } } From 8c08c5724725ca8012093672fa6fa16984c05875 Mon Sep 17 00:00:00 2001 From: Emilio Perez Date: Wed, 8 Mar 2023 14:48:02 +0000 Subject: [PATCH 09/66] Allow adding error symbols after early initialization This was acomplished by making errSymbolAdd add the error symbol directly into the global hash table and removing errnumlist which is not needed anymore. Unit tests were added for checking the following cases: - Adding a valid symbol and checking that it exists (fixed by this change) - Getting an existing error symbol - Getting a non existing error symbol - Adding an invalid error symbol (fixed by this change) - Adding an error symbol with a code that already exists (fixed by this change) Therefore, issue #268 was fixed error: statically allocate error symbol hash table This will allow calling errSymbolAdd before errSymBld, therefore, a function adding error symbols can now be run before iocInit or errlogInit error: add a constant for the minimum module number Make adding an identical error symbol not fail A test case was also added which test that adding an error symbol with same error code and message as one added before will not fail Add locking to error symbol table This protects the cases of: - simultaneously adding and requesting of an error symbol - simultaneously adding many error symbols Update release notes regarding adding error symbols --- documentation/RELEASE_NOTES.md | 4 + modules/libcom/src/error/Makefile | 1 + modules/libcom/src/error/errMdef.h | 2 + modules/libcom/src/error/errSymLib.c | 141 ++++++++++++++------------ modules/libcom/src/error/errSymTbl.h | 3 + modules/libcom/test/epicsErrlogTest.c | 58 ++++++++++- 6 files changed, 143 insertions(+), 66 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index e0ec809b8..75922f874 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -102,6 +102,10 @@ and string formats, some of which support full nanosecond precision. More information is included in the filters documentation, which can be found in the `html/filters.html` document that is generated during the build +### Allow adding new error symbols at any time + +`errSymbolAdd` can now be called after early initialization. + ### Add conditional output (OOPT) to the longout record The longout record can now be configured using its new OOPT and OOCH fields diff --git a/modules/libcom/src/error/Makefile b/modules/libcom/src/error/Makefile index 570974b95..f98ed4b24 100644 --- a/modules/libcom/src/error/Makefile +++ b/modules/libcom/src/error/Makefile @@ -26,6 +26,7 @@ ERR_S_FILES += $(LIBCOM)/as/asLib.h ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h ERR_S_FILES += $(LIBCOM)/error/errMdef.h +ERR_S_FILES += $(LIBCOM)/error/errSymTbl.h ERR_S_FILES += $(TOP)/modules/database/src/ioc/db/dbAccessDefs.h ERR_S_FILES += $(TOP)/modules/database/src/ioc/dbStatic/dbStaticLib.h diff --git a/modules/libcom/src/error/errMdef.h b/modules/libcom/src/error/errMdef.h index 1a9c47e33..9c07353c4 100644 --- a/modules/libcom/src/error/errMdef.h +++ b/modules/libcom/src/error/errMdef.h @@ -19,6 +19,7 @@ #define RTN_SUCCESS(STATUS) ((STATUS)==0) /* Module numbers start above 500 for compatibility with vxWorks errnoLib */ +#define MIN_MODULE_NUM 501 /* FIXME: M_xxx values could be declared as integer variables and set * at runtime from registration routines; the S_xxx definitions would @@ -32,6 +33,7 @@ #define M_stdlib (504 << 16) /* EPICS Standard library */ #define M_pool (505 << 16) /* Thread pool */ #define M_time (506 << 16) /* epicsTime */ +#define M_err (507 << 16) /* Error */ /* ioc */ #define M_dbAccess (511 << 16) /* Database Access Routines */ diff --git a/modules/libcom/src/error/errSymLib.c b/modules/libcom/src/error/errSymLib.c index f3162cf66..a47208062 100644 --- a/modules/libcom/src/error/errSymLib.c +++ b/modules/libcom/src/error/errSymLib.c @@ -23,6 +23,8 @@ #include "cantProceed.h" #include "epicsAssert.h" #include "epicsStdio.h" +#include "epicsMutex.h" +#include "epicsThread.h" #include "errMdef.h" #include "errSymTbl.h" #include "ellLib.h" @@ -33,69 +35,49 @@ static epicsUInt16 errhash(long errNum); typedef struct errnumnode { - ELLNODE node; long errNum; struct errnumnode *hashnode; const char *message; long pad; } ERRNUMNODE; -static ELLLIST errnumlist = ELLLIST_INIT; -static ERRNUMNODE **hashtable; -static int initialized = 0; +typedef struct { + ERRNUMNODE *table[NHASH * sizeof(ERRNUMNODE *)]; + epicsMutexId tableMutexId; +} errHashTable_t; + +static errHashTable_t errHashTable; + extern ERRSYMTAB_ID errSymTbl; /**************************************************************** * ERRSYMBLD * - * Create the normal ell LIST of sorted error messages nodes - * Followed by linked hash lists - that link together those - * ell nodes that have a common hash number. + * Populate EPICS error symbols * ***************************************************************/ int errSymBld(void) { - ERRSYMBOL *errArray = errSymTbl->symbols; - ERRNUMNODE *perrNumNode = NULL; - ERRNUMNODE *pNextNode = NULL; - ERRNUMNODE **phashnode = NULL; - int i; - int modnum; - - if (initialized) - return(0); - - hashtable = (ERRNUMNODE**)callocMustSucceed - (NHASH, sizeof(ERRNUMNODE*),"errSymBld"); + ERRSYMBOL *errArray = errSymTbl->symbols; + int i; for (i = 0; i < errSymTbl->nsymbols; i++, errArray++) { - modnum = errArray->errNum >> 16; - if (modnum < 501) { - fprintf(stderr, "errSymBld: ERROR - Module number in errSymTbl < 501 was Module=%lx Name=%s\n", - errArray->errNum, errArray->name); - continue; - } - if ((errSymbolAdd(errArray->errNum, errArray->name)) < 0) { + if (errSymbolAdd(errArray->errNum, errArray->name)) { fprintf(stderr, "errSymBld: ERROR - errSymbolAdd() failed \n"); - continue; } } - perrNumNode = (ERRNUMNODE *) ellFirst(&errnumlist); - while (perrNumNode) { - /* hash each perrNumNode->errNum */ - epicsUInt16 hashInd = errhash(perrNumNode->errNum); - phashnode = (ERRNUMNODE**)&hashtable[hashInd]; - pNextNode = (ERRNUMNODE*) *phashnode; - /* search for last node (NULL) of hashnode linked list */ - while (pNextNode) { - phashnode = &pNextNode->hashnode; - pNextNode = *phashnode; - } - *phashnode = perrNumNode; - perrNumNode = (ERRNUMNODE *) ellNext((ELLNODE *) perrNumNode); - } - initialized = 1; - return(0); + return 0; +} + +static void _initErrorHashTable(void *_unused) +{ + errHashTable.tableMutexId = epicsMutexMustCreate(); +} + +static void initErrorHashTable() +{ + static epicsThreadOnceId initErrSymOnceFlag = EPICS_THREAD_ONCE_INIT; + epicsThreadOnce(&initErrSymOnceFlag, _initErrorHashTable, NULL); } /**************************************************************** @@ -109,21 +91,48 @@ static epicsUInt16 errhash(long errNum) modnum = (unsigned short) (errNum >> 16); errnum = (unsigned short) (errNum & 0xffff); - return (((modnum - 500) * 20) + errnum) % NHASH; + return ((modnum - (MIN_MODULE_NUM - 1)) * 20 + errnum) % NHASH; } /**************************************************************** * ERRSYMBOLADD - * adds symbols to the master errnumlist as compiled from errSymTbl.c + * adds symbols to the global error symbol hash table ***************************************************************/ int errSymbolAdd(long errNum, const char *name) { - ERRNUMNODE *pNew = (ERRNUMNODE*) callocMustSucceed(1, - sizeof(ERRNUMNODE), "errSymbolAdd"); + ERRNUMNODE *pNextNode = NULL; + ERRNUMNODE **phashnode = NULL; + ERRNUMNODE *pNew = NULL; + int modnum = (epicsUInt16) (errNum >> 16); + if (modnum < MIN_MODULE_NUM) + return S_err_invCode; + + initErrorHashTable(); + + epicsUInt16 hashInd = errhash(errNum); + + epicsMutexLock(errHashTable.tableMutexId); + phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd]; + pNextNode = (ERRNUMNODE*) *phashnode; + + /* search for last node (NULL) of hashnode linked list */ + while (pNextNode) { + if (pNextNode->errNum == errNum) { + int notIdentical = strcmp(name, pNextNode->message); + epicsMutexUnlock(errHashTable.tableMutexId); + return notIdentical ? S_err_codeExists : 0; + } + phashnode = &pNextNode->hashnode; + pNextNode = *phashnode; + } + + pNew = (ERRNUMNODE*) callocMustSucceed( + 1, sizeof(ERRNUMNODE), "errSymbolAdd"); pNew->errNum = errNum; pNew->message = name; - ellAdd(&errnumlist, (ELLNODE*)pNew); + *phashnode = pNew; + epicsMutexUnlock(errHashTable.tableMutexId); return 0; } @@ -155,31 +164,31 @@ const char* errSymLookupInternal(long status) if (!status) return "Ok"; - if (!initialized) - errSymBld(); + initErrorHashTable(); modNum = (unsigned) status; modNum >>= 16; modNum &= 0xffff; - if (modNum <= 500) { - const char * pStr = strerror ((int) status); - if (pStr) { - return pStr; - } + if (modNum < MIN_MODULE_NUM) { + return strerror ((int) status); } else { unsigned hashInd = errhash(status); - phashnode = (ERRNUMNODE**)&hashtable[hashInd]; + const char *result = NULL; + epicsMutexLock(errHashTable.tableMutexId); + phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd]; pNextNode = *phashnode; while (pNextNode) { if (pNextNode->errNum==status){ - return pNextNode->message; + result = pNextNode->message; + break; } phashnode = &pNextNode->hashnode; pNextNode = *phashnode; } + epicsMutexUnlock(errHashTable.tableMutexId); + return result; } - return NULL; } const char* errSymMsg(long status) @@ -210,12 +219,12 @@ void errSymDump(void) int i; int msgcount = 0; - if (!initialized) errSymBld(); + initErrorHashTable(); msgcount = 0; printf("errSymDump: number of hash slots = %d\n", NHASH); for (i = 0; i < NHASH; i++) { - ERRNUMNODE **phashnode = &hashtable[i]; + ERRNUMNODE **phashnode = &errHashTable.table[i]; ERRNUMNODE *pNextNode = *phashnode; int count = 0; @@ -246,14 +255,15 @@ void errSymTestPrint(long errNum) epicsUInt16 modnum; epicsUInt16 errnum; - if (!initialized) errSymBld(); + initErrorHashTable(); message[0] = '\0'; modnum = (epicsUInt16) (errNum >> 16); errnum = (epicsUInt16) (errNum & 0xffff); - if (modnum < 501) { + if (modnum < MIN_MODULE_NUM) { fprintf(stderr, "Usage: errSymTestPrint(long errNum) \n"); - fprintf(stderr, "errSymTestPrint: module number < 501 \n"); + fprintf(stderr, + "errSymTestPrint: module number < %d\n", MIN_MODULE_NUM); return; } errSymLookup(errNum, message, sizeof(message)); @@ -271,10 +281,11 @@ void errSymTest(epicsUInt16 modnum, epicsUInt16 begErrNum, long errNum; epicsUInt16 errnum; - if (!initialized) errSymBld(); - if (modnum < 501) + if (modnum < MIN_MODULE_NUM) return; + initErrorHashTable(); + /* print range of error messages */ for (errnum = begErrNum; errnum <= endErrNum; errnum++) { errNum = modnum << 16; diff --git a/modules/libcom/src/error/errSymTbl.h b/modules/libcom/src/error/errSymTbl.h index 89d74316c..1b39ff6f3 100644 --- a/modules/libcom/src/error/errSymTbl.h +++ b/modules/libcom/src/error/errSymTbl.h @@ -16,6 +16,9 @@ #include "libComAPI.h" #include "epicsTypes.h" +#define S_err_invCode (M_err | 1) /* Invalid error symbol code */ +#define S_err_codeExists (M_err | 2) /* Error code already exists */ + /* ERRSYMBOL - entry in symbol table */ typedef struct { long errNum; /* errMessage symbol number */ diff --git a/modules/libcom/test/epicsErrlogTest.c b/modules/libcom/test/epicsErrlogTest.c index 16a04a73c..3638da34d 100644 --- a/modules/libcom/test/epicsErrlogTest.c +++ b/modules/libcom/test/epicsErrlogTest.c @@ -29,6 +29,7 @@ #include "osiSock.h" #include "fdmgr.h" #include "epicsString.h" +#include "errSymTbl.h" /* private between errlog.c and this test */ LIBCOM_API @@ -197,13 +198,61 @@ void testANSIStrip(void) #undef testEscape } +static void testErrorMessageMatches(long status, const char *expected) +{ + const char *msg = errSymMsg(status); + testOk(strcmp(msg, expected) == 0, + "Error code %ld returns \"%s\", expected message \"%s\"", status, + msg, expected + ); +} + +static void testGettingExistingErrorSymbol() +{ + testErrorMessageMatches(S_err_invCode, "Invalid error symbol code"); +} + +static void testGettingNonExistingErrorSymbol() +{ + long invented_code = (0x7999 << 16) | 0x9998; + testErrorMessageMatches(invented_code, ""); +} + +static void testAddingErrorSymbol() +{ + long invented_code = (0x7999 << 16) | 0x9999; + errSymbolAdd(invented_code, "Invented Error Message"); + testErrorMessageMatches(invented_code, "Invented Error Message"); +} + +static void testAddingInvalidErrorSymbol() +{ + long invented_code = (500 << 16) | 0x1; + testOk(errSymbolAdd(invented_code, "No matter"), + "Adding error symbol with module code < 501 should fail"); +} + +static void testAddingExistingErrorSymbol() +{ + testOk(errSymbolAdd(S_err_invCode, "Duplicate"), + "Adding an error symbol with an existing error code should fail"); +} + +static void testAddingExistingErrorSymbolWithSameMessage() +{ + long invented_code = (0x7999 << 16) | 0x9997; + errSymbolAdd(invented_code, "Invented Error Message"); + testOk(!errSymbolAdd(invented_code, "Invented Error Message"), + "Adding identical error symbol shouldn't fail"); +} + MAIN(epicsErrlogTest) { size_t mlen, i, N; char msg[256]; clientPvt pvt, pvt2; - testPlan(48); + testPlan(54); testANSIStrip(); @@ -414,6 +463,13 @@ MAIN(epicsErrlogTest) testLogPrefix(); osiSockRelease(); + testGettingExistingErrorSymbol(); + testGettingNonExistingErrorSymbol(); + testAddingErrorSymbol(); + testAddingInvalidErrorSymbol(); + testAddingExistingErrorSymbol(); + testAddingExistingErrorSymbolWithSameMessage(); + return testDone(); } /* From 88ea1507f46daabb0520d773193b271ac6c9b56d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 28 Aug 2023 14:00:27 +0200 Subject: [PATCH 10/66] Fix compile w/ vs2012 --- modules/libcom/src/error/errSymLib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/error/errSymLib.c b/modules/libcom/src/error/errSymLib.c index a47208062..37e8102cd 100644 --- a/modules/libcom/src/error/errSymLib.c +++ b/modules/libcom/src/error/errSymLib.c @@ -23,6 +23,7 @@ #include "cantProceed.h" #include "epicsAssert.h" #include "epicsStdio.h" +#include "epicsTypes.h" #include "epicsMutex.h" #include "epicsThread.h" #include "errMdef.h" @@ -104,14 +105,13 @@ int errSymbolAdd(long errNum, const char *name) ERRNUMNODE **phashnode = NULL; ERRNUMNODE *pNew = NULL; int modnum = (epicsUInt16) (errNum >> 16); + epicsUInt16 hashInd = errhash(errNum); if (modnum < MIN_MODULE_NUM) return S_err_invCode; initErrorHashTable(); - epicsUInt16 hashInd = errhash(errNum); - epicsMutexLock(errHashTable.tableMutexId); phashnode = (ERRNUMNODE**)&errHashTable.table[hashInd]; pNextNode = (ERRNUMNODE*) *phashnode; From 60fa2d31da2deaaa89636b4a1f5b852efe0b2699 Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Tue, 18 Jul 2023 16:24:37 -0700 Subject: [PATCH 11/66] libCom: Fix buggy pointer dereference in postfix() --- modules/libcom/src/calc/postfix.c | 8 ++++++++ modules/libcom/test/epicsCalcTest.cpp | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/calc/postfix.c b/modules/libcom/src/calc/postfix.c index 7457abaab..d9dce515d 100644 --- a/modules/libcom/src/calc/postfix.c +++ b/modules/libcom/src/calc/postfix.c @@ -335,6 +335,10 @@ LIBCOM_API long break; case SEPERATOR: + if (pstacktop == stack) { + *perror = CALC_ERR_BAD_SEPERATOR; + goto bad; + } /* Move operators to the output until open paren */ while (pstacktop->name[0] != '(') { if (pstacktop <= stack+1) { @@ -353,6 +357,10 @@ LIBCOM_API long break; case CLOSE_PAREN: + if (pstacktop == stack) { + *perror = CALC_ERR_PAREN_NOT_OPEN; + goto bad; + } /* Move operators to the output until matching paren */ while (pstacktop->name[0] != '(') { if (pstacktop <= stack+1) { diff --git a/modules/libcom/test/epicsCalcTest.cpp b/modules/libcom/test/epicsCalcTest.cpp index 870547e4d..4f0bfbecb 100644 --- a/modules/libcom/test/epicsCalcTest.cpp +++ b/modules/libcom/test/epicsCalcTest.cpp @@ -298,7 +298,7 @@ MAIN(epicsCalcTest) const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0, g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0; - testPlan(635); + testPlan(637); /* LITERAL_OPERAND elements */ testExpr(0); @@ -953,6 +953,8 @@ MAIN(epicsCalcTest) testBadExpr("1?", CALC_ERR_CONDITIONAL); testBadExpr("1?1", CALC_ERR_CONDITIONAL); testBadExpr(":1", CALC_ERR_SYNTAX); + testBadExpr("0,", CALC_ERR_BAD_SEPERATOR); + testBadExpr("0)", CALC_ERR_PAREN_NOT_OPEN); // Bit manipulations wrt bit 31 (bug lp:1514520) // using integer literals From 766c9906b55dec0b723774907ec2f2ffd70a7352 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 22 Oct 2023 13:35:45 -0700 Subject: [PATCH 12/66] update ci-scripts --- .ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci b/.ci index 1e0e326f7..899b18336 160000 --- a/.ci +++ b/.ci @@ -1 +1 @@ -Subproject commit 1e0e326f74ffac4154ce80b5d41c410c754cf5d8 +Subproject commit 899b18336b4ce3bd9328fd30c33621224c78a4d7 From badd8f518d3753b70acc6d30a28ad873fd4b0d15 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 22 Oct 2023 17:42:19 -0700 Subject: [PATCH 13/66] update modules/pvData --- modules/pvData | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pvData b/modules/pvData index 2547514ab..13e4e577b 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 2547514abb90875bf47dda728ecaa9e30a5ab354 +Subproject commit 13e4e577bbc197ee7fe27e858e6ecd88d5265b45 From 6dec68554c30daab64823ef57e7757002cf4f644 Mon Sep 17 00:00:00 2001 From: AlexWells Date: Wed, 8 Mar 2023 15:56:01 +0000 Subject: [PATCH 14/66] iocsh: Add underline separator between help outputs Also tweaks the overall format of the message a bit. Add tests for new help output format --- modules/libcom/src/error/errlog.h | 16 +-- modules/libcom/src/iocsh/iocsh.cpp | 15 ++- modules/libcom/test/Makefile | 1 + modules/libcom/test/iocshTest.cpp | 109 ++++++++++++++++++++- modules/libcom/test/iocshTestHelpFunction1 | 4 + modules/libcom/test/iocshTestHelpFunctions | 14 +++ 6 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 modules/libcom/test/iocshTestHelpFunction1 create mode 100644 modules/libcom/test/iocshTestHelpFunctions diff --git a/modules/libcom/src/error/errlog.h b/modules/libcom/src/error/errlog.h index 32e2da7a5..4aaf054ac 100644 --- a/modules/libcom/src/error/errlog.h +++ b/modules/libcom/src/error/errlog.h @@ -285,14 +285,16 @@ LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength); #define ANSI_ESC_MAGENTA "\033[35;1m" #define ANSI_ESC_CYAN "\033[36;1m" #define ANSI_ESC_BOLD "\033[1m" +#define ANSI_ESC_UNDERLINE "\033[4m" #define ANSI_ESC_RESET "\033[0m" -#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET -#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET -#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET -#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET -#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET -#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET -#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET +#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET +#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET +#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET +#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET +#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET +#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET +#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET +#define ANSI_UNDERLINE(STR) ANSI_ESC_UNDERLINE STR ANSI_ESC_RESET #define ERL_ERROR ANSI_RED("ERROR") #define ERL_WARNING ANSI_MAGENTA("WARNING") /** @} */ diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 7c9551845..461780513 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -888,15 +888,19 @@ static void helpCallFunc(const iocshArgBuf *args) "Type 'help ' to see the arguments of . eg. 'help db*'\n"); } else { + bool firstFunction = true; for (int iarg = 1 ; iarg < argc ; iarg++) { for (pcmd = iocshCommandHead ; pcmd != NULL ; pcmd = pcmd->next) { piocshFuncDef = pcmd->def.pFuncDef; if (epicsStrGlobMatch(piocshFuncDef->name, argv[iarg]) != 0) { - if(piocshFuncDef->usage) { - fputs("\nUsage: ", epicsGetStdout()); + + if (! firstFunction) { + fprintf(epicsGetStdout(), + ANSI_UNDERLINE(" \n")); } + fprintf(epicsGetStdout(), - ANSI_BOLD("%s"), + ANSI_BOLD("\n%s"), piocshFuncDef->name); for (int a = 0 ; a < piocshFuncDef->nargs ; a++) { @@ -909,11 +913,14 @@ static void helpCallFunc(const iocshArgBuf *args) fprintf(epicsGetStdout(), " '%s'", cp); } } - fprintf(epicsGetStdout(),"\n");; + fprintf(epicsGetStdout(),"\n"); if(piocshFuncDef->usage) { fprintf(epicsGetStdout(), "\n%s", piocshFuncDef->usage); } + + firstFunction = false; } + } } } diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index 809ae7338..a3893661f 100644 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -269,6 +269,7 @@ TESTPROD_HOST += iocshTest iocshTest_SRCS += iocshTest.cpp TESTS += iocshTest TESTFILES += $(wildcard ../iocshTest*.cmd) +TESTFILES += ../iocshTestHelpFunction1 ../iocshTestHelpFunctions TESTPROD_HOST += epicsLoadTest epicsLoadTest_SRCS += epicsLoadTest.cpp diff --git a/modules/libcom/test/iocshTest.cpp b/modules/libcom/test/iocshTest.cpp index 7ca5c3867..4b98112da 100644 --- a/modules/libcom/test/iocshTest.cpp +++ b/modules/libcom/test/iocshTest.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -83,14 +85,117 @@ void assertCallFunc(const iocshArgBuf *args) iocshSetError(args[0].ival); } +const iocshFuncDef testHelpFunction1Def = {"testHelpFunction1",0,0, + "Usage message of testHelpFunction1\n"}; +const iocshFuncDef testHelpFunction2Def = {"testHelpFunction2",0,0, + "Usage message of testHelpFunction2\n"}; +const iocshFuncDef testHelpFunction3Def = {"testHelpFunction3",0,0, + "Usage message of testHelpFunction3\n"}; +void doNothing(const iocshArgBuf *args) +{ + return; +} + +std::string readFile(std::string filename) +{ + std::ifstream t(filename.c_str()); + std::stringstream buffer; + + if (!t.is_open()) { + throw std::invalid_argument("Could not open filename " + filename); + } + + buffer << t.rdbuf(); + return buffer.str(); +} + +bool compareFiles(const std::string& p1, const std::string& p2) +{ + std::ifstream f1(p1.c_str(), std::ifstream::binary|std::ifstream::ate); + std::ifstream f2(p2.c_str(), std::ifstream::binary|std::ifstream::ate); + + if (f1.fail() || f2.fail()) { + testDiag("One or more files failed to open"); + testDiag("f1.fail(): %d f2.fail(): %d", f1.fail(), f2.fail()); + return false; // File problem + } + + if (f1.tellg() != f2.tellg()) { + testDiag("File sizes did not match"); + return false; // Size mismatch + } + + // Seek back to beginning and use std::equal to compare contents + f1.seekg(0, std::ifstream::beg); + f2.seekg(0, std::ifstream::beg); + + bool are_equal = std::equal( + std::istreambuf_iterator(f1.rdbuf()), + std::istreambuf_iterator(), + std::istreambuf_iterator(f2.rdbuf()) + ); + + if (! are_equal) { + testDiag("File contents did not match"); + + std::string line; + f1.seekg(0, std::ifstream::beg); + f2.seekg(0, std::ifstream::beg); + + testDiag("File1 contents: "); + while(std::getline(f1, line)) { + testDiag("%s", line.c_str()); + } + + testDiag("File2 contents: "); + while(std::getline(f2, line)) { + testDiag("%s", line.c_str()); + } + } + + return are_equal; +} + + +void testHelp(void) +{ + testDiag("iocshTest testHelp start"); + + // Filename to save help output to + const std::string filename = "testHelpOutput"; + + // Verify help lists expected commands + iocshCmd(("help > " + filename).c_str()); + std::string contents = readFile(filename); + testOk1(contents.find("help") != std::string::npos); + testOk1(contents.find("testHelpFunction1") != std::string::npos); + testOk1(contents.find("testHelpFunction2") != std::string::npos); + testOk1(contents.find("testHelpFunction3") != std::string::npos); + + // Confirm formatting of a single command + iocshCmd(("help testHelpFunction1 > " + filename).c_str()); + testOk1(compareFiles(filename, "iocshTestHelpFunction1") == true); + + // Confirm formatting of multiple commands + iocshCmd(("help testHelp* > " + filename).c_str()); + testOk1(compareFiles(filename, "iocshTestHelpFunctions") == true); + + remove(filename.c_str()); +} + } // namespace + + MAIN(iocshTest) { - testPlan(19); + testPlan(25); libComRegister(); iocshRegister(&positionFuncDef, &positionCallFunc); iocshRegister(&assertFuncDef, &assertCallFunc); + iocshRegister(&testHelpFunction1Def, &doNothing); + iocshRegister(&testHelpFunction2Def, &doNothing); + iocshRegister(&testHelpFunction3Def, &doNothing); findTestData(); testFile("iocshTestSuccess.cmd"); @@ -129,6 +234,8 @@ MAIN(iocshTest) testPosition("after_error_1", false); reached.clear(); + testHelp(); + // cleanup after macLib to avoid valgrind false positives dbmfFreeChunks(); return testDone(); diff --git a/modules/libcom/test/iocshTestHelpFunction1 b/modules/libcom/test/iocshTestHelpFunction1 new file mode 100644 index 000000000..515d62f49 --- /dev/null +++ b/modules/libcom/test/iocshTestHelpFunction1 @@ -0,0 +1,4 @@ + +testHelpFunction1 + +Usage message of testHelpFunction1 diff --git a/modules/libcom/test/iocshTestHelpFunctions b/modules/libcom/test/iocshTestHelpFunctions new file mode 100644 index 000000000..0a6d11159 --- /dev/null +++ b/modules/libcom/test/iocshTestHelpFunctions @@ -0,0 +1,14 @@ + +testHelpFunction1 + +Usage message of testHelpFunction1 + + +testHelpFunction2 + +Usage message of testHelpFunction2 + + +testHelpFunction3 + +Usage message of testHelpFunction3 From df908f299b67add4339d8f6ffee8adab65b0d099 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 22 Oct 2023 10:48:56 -0700 Subject: [PATCH 15/66] remove unused local --- modules/database/src/ioc/db/dbEvent.c | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 38ec9e701..44059dbfa 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -1008,7 +1008,6 @@ static void event_task (void *pParm) do { void (*pExtraLaborSub) (void *); void *pExtraLaborArg; - char wake; epicsEventMustWait(evUser->ppendsem); /* From 49ea46ee5e85a518fa3afd189bee06f43e1a3f24 Mon Sep 17 00:00:00 2001 From: Jack Harper Date: Tue, 25 Apr 2023 11:15:21 +0100 Subject: [PATCH 16/66] iocsh: add comment to cvtArg explaining default iocsharg behaviour --- modules/libcom/src/iocsh/iocsh.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 461780513..617c50917 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -755,6 +755,13 @@ void epicsStdCall iocshFree(void) iocshTableUnlock (); } +/* + * Parse argument input based on the arg type specified. + * It is worth noting that depending on type this argument may + * be defaulted if a value is not specified. For example, a + * double/int with no value will default to 0 which may allow + * you to add optional arguments to the end of your argument list. + */ static int cvtArg (const char *filename, int lineno, char *arg, iocshArgBuf *argBuf, const iocshArg *piocshArg) From 92cae86ff2ad7e747967808b65ec4834bf7b7d94 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 3 Sep 2022 11:36:57 -0700 Subject: [PATCH 17/66] dbRecordsOnceOnly allow append only with "*" with > record(ai, "myrec") {} dbRecordsOnceOnly!=0 currently disallows appending fields with either form: > record("*", "myrec") {} # error > record(ai, "myrec") {} # error Change the meaning such that dbRecordsOnceOnly!=0 allways allows appending when explicitly intended (rtype "*"). > record("*", "myrec") {} # allowed > record(ai, "myrec") {} # error Also clearly label this parse error. --- .../database/src/ioc/dbStatic/dbLexRoutines.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 85af1f110..4819d4a41 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1110,14 +1110,10 @@ static void dbRecordHead(char *recordType, char *name, int visible) allocTemp(pdbentry); if (recordType[0] == '*' && recordType[1] == 0) { - if (dbRecordsOnceOnly) - epicsPrintf("Record-type \"*\" not valid with dbRecordsOnceOnly\n"); - else { - status = dbFindRecord(pdbentry, name); - if (status == 0) - return; /* done */ - epicsPrintf("Record \"%s\" not found\n", name); - } + status = dbFindRecord(pdbentry, name); + if (status == 0) + return; /* done */ + epicsPrintf(ERL_ERROR ": Record \"%s\" not found\n", name); yyerror(NULL); duplicate = TRUE; return; @@ -1136,15 +1132,16 @@ static void dbRecordHead(char *recordType, char *name, int visible) status = dbCreateRecord(pdbentry,name); if (status == S_dbLib_recExists) { if (strcmp(recordType, dbGetRecordTypeName(pdbentry)) != 0) { - epicsPrintf("Record \"%s\" of type \"%s\" redefined with new type " + epicsPrintf(ERL_ERROR ": Record \"%s\" of type \"%s\" redefined with new type " "\"%s\"\n", name, dbGetRecordTypeName(pdbentry), recordType); yyerror(NULL); duplicate = TRUE; return; } else if (dbRecordsOnceOnly) { - epicsPrintf("Record \"%s\" already defined (dbRecordsOnceOnly is " - "set)\n", name); + epicsPrintf(ERL_ERROR ": Record \"%s\" already defined and dbRecordsOnceOnly set.\n" + "Used record type \"*\" to append.\n", + name); yyerror(NULL); duplicate = TRUE; } From 395015aac4d24fdc81e757b4db7e162a8b52a9fc Mon Sep 17 00:00:00 2001 From: JJL772 Date: Fri, 7 Jul 2023 13:16:21 -0700 Subject: [PATCH 18/66] Com: Make STATIC_ASSERT macro typedefs unique --- modules/libcom/src/osi/epicsAssert.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/epicsAssert.h b/modules/libcom/src/osi/epicsAssert.h index 7b524f7af..ed00bde1a 100644 --- a/modules/libcom/src/osi/epicsAssert.h +++ b/modules/libcom/src/osi/epicsAssert.h @@ -78,14 +78,22 @@ LIBCOM_API void epicsAssert (const char *pFile, const unsigned line, #if __cplusplus>=201103L #define STATIC_ASSERT(expr) static_assert(expr, #expr) #else -#define STATIC_JOIN(x, y) STATIC_JOIN2(x, y) -#define STATIC_JOIN2(x, y) x ## y + +#define STATIC_JOIN(x, y, z, w) STATIC_JOIN4(x, y, z, w) +#define STATIC_JOIN4(x, y, z, w) x ## y ## z ## w + +/* Compilers that do not support __COUNTER__ (e.g. GCC 4.1) will not be able to use unique static assert typedefs */ +#ifdef __COUNTER__ +# define STATIC_ASSERT_MSG(l) STATIC_JOIN(static_assert_, __COUNTER__, _failed_at_line_, l) +#else +# define STATIC_ASSERT_MSG(l) STATIC_JOIN(static_assert_, 0, _failed_at_line_, l) +#endif /**\brief Declare a condition that should be true at compile-time. * \param expr A C/C++ const-expression that should evaluate to True. */ #define STATIC_ASSERT(expr) \ - typedef int STATIC_JOIN(static_assert_failed_at_line_, __LINE__) \ + typedef int STATIC_ASSERT_MSG(__LINE__) \ [ (expr) ? 1 : -1 ] EPICS_UNUSED #endif From 2ca70d3aa280610c768ae78668d2f62fc4ef5212 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 5 Oct 2023 14:12:25 -0700 Subject: [PATCH 19/66] iocsh: keep history file --- .gitignore | 1 + modules/libcom/src/iocsh/iocsh.cpp | 37 ++++++++++++++++++++++++++++++ src/template/base/top/.gitignore | 3 +++ src/template/ext/top/.gitignore | 3 +++ 4 files changed, 44 insertions(+) diff --git a/.gitignore b/.gitignore index b7a25673a..46b32dc1a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ O.*/ *.log .*.swp .DS_Store +.iocsh_history diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 617c50917..b40752a73 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,7 @@ #if EPICS_COMMANDLINE_LIBRARY == EPICS_COMMANDLINE_LIBRARY_READLINE # include +# include # define USE_READLINE /* libedit also provides readline.h, but isn't fully compatible with * GNU readline. It also doesn't specifically identify itself. @@ -633,6 +635,15 @@ struct ReadlineContext { rl_completer_quote_characters = (char*)"\""; rl_attempted_completion_function = &iocsh_attempt_completion; rl_bind_key('\t', rl_complete); + compute_hist_file(); + if(!hist_file.empty()) { + if(int err = read_history(hist_file.c_str())) { + if(err!=ENOENT) + fprintf(stderr, "Error %s (%d) loading '%s'\n", + strerror(err), err, hist_file.c_str()); + } + stifle_history(1024); // some limit... + } } #endif return context; @@ -641,6 +652,12 @@ struct ReadlineContext { ~ReadlineContext() { if(context) { #ifdef USE_READLINE + if(!hist_file.empty()) { + if(int err = write_history(hist_file.c_str())) { + fprintf(stderr, "Error %s (%d) writing '%s'\n", + strerror(err), err, hist_file.c_str()); + } + } rl_readline_name = prev_rl_readline_name; rl_basic_word_break_characters = prev_rl_basic_word_break_characters; rl_completer_word_break_characters = prev_rl_completer_word_break_characters; @@ -653,6 +670,26 @@ struct ReadlineContext { epicsReadlineEnd(context); } } + +#ifdef USE_READLINE + std::string hist_file; + + void compute_hist_file() { + std::string scratch; + if(const char *env = getenv("EPICS_IOCSH_HISTFILE")) { + scratch = env; + } else { + scratch = ".iocsh_history"; + } + const char *home = getenv("HOME"); + if(home && scratch.size()>=2 && scratch[0]=='~' && scratch[1]=='/') { + std::ostringstream strm; + strm< Date: Fri, 10 Mar 2023 13:41:31 +0100 Subject: [PATCH 20/66] gha: turn most warnings into errors in github build --- .github/workflows/ci-scripts-build.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 5a66f1d7b..e8dd9c85b 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -51,6 +51,25 @@ jobs: matrix: # Job names also name artifacts, character limitations apply include: + - os: ubuntu-22.04 + cmp: gcc-12 + name: "Ub-22 gcc-12 c++20 Werror" + # Turn all warnings into errors, + # except for those we could not fix (yet). + # Remove respective -Wno-error=... flag once it is fixed. + extra: "CMD_CXXFLAGS=-std=c++20 + CMD_CPPFLAGS='-fdiagnostics-color + -Werror + -Wno-error=deprecated-declarations + -Wno-error=stringop-truncation + -Wno-error=restrict + -Wno-error=sizeof-pointer-memaccess + -Wno-error=nonnull + -Wno-error=dangling-pointer + -Wno-error=format-overflow + -Wno-error=format-security + -Wno-error=stringop-overread'" + - os: ubuntu-20.04 cmp: gcc configuration: default From b41787b6bf8093caaf00e934b6a132963824fbe7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 9 Oct 2023 18:53:31 -0700 Subject: [PATCH 21/66] doc --- documentation/RELEASE_NOTES.md | 43 +++++++++++++++++++++--- modules/database/src/ioc/db/dbLink.h | 2 ++ modules/libcom/src/osi/epicsStackTrace.h | 2 ++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 75922f874..8c9f2a13e 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,6 +22,28 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.7 +### Allow explicit append with `dbRecordsOnceOnly!=0` + +Previously setting `dbRecordsOnceOnly!=0` prevented any further changes to a record via a .db file. eg. + +``` +record(ai, "myrec") {} +``` + +`dbRecordsOnceOnly!=0` previously disallowed appending fields with either form: + +``` +record("*", "myrec") {} # error +record(ai, "myrec") {} # error +``` + +Beginning with this release, `dbRecordsOnceOnly!=0` allows appending when explicitly intended (when record type is `"*"`). + +``` +record("*", "myrec") {} # allowed +record(ai, "myrec") {} # error +``` + ### Add `$EPICS_CLI_TIMEOUT` Add support for CA tools timeout from environment variable `$EPICS_CLI_TIMEOUT` @@ -63,7 +85,7 @@ Previously, if a subRecord has an invalid `INP*` link, it was silently failing (and not running the proc function). Now the the status code returned by the subroutine is returned from `dbProcess()`. -### COMMANDLINE_LIBRARY fallback to GNU_DIR +### COMMANDLINE\_LIBRARY fallback to GNU\_DIR Fall back to the previous behavior when searching for `readline.h` with older compilers. @@ -118,7 +140,9 @@ This functionality was suggested in be added to other output record types if the community finds it useful, please send feedback about the feature to tech-talk. -### Tab completion for IOC shell +### IOC Shell + +#### Tab completion When built with optional GNU libreadline support, the interactive IOC shell will perform tab completion for command names as well as for some arguments @@ -130,14 +154,25 @@ using the new `iocshArgStringRecord` and `iocshArgStringPath` argument types. Both function identically to `iocshArgString` but indicate how to suggest completion strings. -Builds on macOS (darwin-x86 or darwin-aarch64 targets) normally use Apple's +Builds on macOS (`darwin-x86` or `darwin-aarch64` targets) normally use Apple's libedit library in readline compatibility mode, which doesn't support the tab completion API that GNU readline provides. You can use Homebrew or some other third-party package manager to install the GNU readline package, then edit the -configure/os/CONFIG_SITE.darwinCommon.darwinCommon file to have EPICS use the +`configure/os/CONFIG_SITE.darwinCommon.darwinCommon` file to have EPICS use the real thing to get tab completion in the IOC shell. The default settings in that file currently look for and use a Homebrew-installed readline if present. +#### Persist history + +Attempt to read and write command to a file (`./.iocsh_history` by default). +Name may be overwritten with by setting `$EPICS_IOCSH_HISTFILE` to an +alternate path, or disabled by setting to an empty string. + +#### Changes to help output + +Rework the `help` command output to improve formatting and readability, +and include a visual marker (a line of underlines) between different help commands. + ### Add FMOD as CALC Expression The floating point modulo function `FMOD(NUM,DEN)` has been added to the CALC diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h index 9b4e9a9f0..4e7862479 100644 --- a/modules/database/src/ioc/db/dbLink.h +++ b/modules/database/src/ioc/db/dbLink.h @@ -359,6 +359,8 @@ typedef struct lset { * @param plink the link * @param rtn routine to execute * @returns status value + * + * @since 3.16.1 */ long (*doLocked)(struct link *plink, dbLinkUserCallback rtn, void *priv); diff --git a/modules/libcom/src/osi/epicsStackTrace.h b/modules/libcom/src/osi/epicsStackTrace.h index 931477994..f336d419f 100644 --- a/modules/libcom/src/osi/epicsStackTrace.h +++ b/modules/libcom/src/osi/epicsStackTrace.h @@ -25,6 +25,8 @@ extern "C" { /** \brief Dump a stack trace * * Dump a stack trace to the errlog. + * + * \since 3.15.0.2 Added */ LIBCOM_API void epicsStackTrace(void); From 9f868a107461b652280721dffdc8b592b9269270 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 23 Oct 2023 19:25:01 -0700 Subject: [PATCH 22/66] avoid hang during concurrent db_cancel_event() cf. fab8fd7102143a661a81cf7163dd889601eb015c --- modules/database/src/ioc/db/dbEvent.c | 51 ++++++++++++++++++--------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 44059dbfa..e7d0427fc 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -82,9 +82,10 @@ struct event_que { struct event_user { struct event_que firstque; /* the first event que */ + ELLLIST waiters; /* event_waiter::node */ + epicsMutexId lock; epicsEventId ppendsem; /* Wait while empty */ - epicsEventId pflush_sem; /* wait for flush */ epicsEventId pexitsem; /* wait for event task to join */ EXTRALABORFUNC *extralabor_sub;/* off load to event task */ @@ -101,6 +102,11 @@ struct event_user { epicsThreadId init_func_arg; }; +typedef struct { + ELLNODE node; /* event_user::waiters */ + epicsEventId wake; +} event_waiter; + /* * Reliable intertask communication requires copying the current value of the * channel for later queuing so 3 stepper motor steps of 10 each do not turn @@ -306,9 +312,6 @@ dbEventCtx db_init_events (void) evUser->ppendsem = epicsEventCreate(epicsEventEmpty); if (!evUser->ppendsem) goto fail; - evUser->pflush_sem = epicsEventCreate(epicsEventEmpty); - if (!evUser->pflush_sem) - goto fail; evUser->lock = epicsMutexCreate(); if (!evUser->lock) goto fail; @@ -326,8 +329,6 @@ fail: epicsMutexDestroy (evUser->firstque.writelock); if(evUser->ppendsem) epicsEventDestroy (evUser->ppendsem); - if(evUser->pflush_sem) - epicsEventDestroy (evUser->pflush_sem); if(evUser->pexitsem) epicsEventDestroy (evUser->pexitsem); freeListFree(dbevEventUserFreeList,evUser); @@ -391,7 +392,6 @@ void db_close_events (dbEventCtx ctx) epicsEventDestroy(evUser->pexitsem); epicsEventDestroy(evUser->ppendsem); - epicsEventDestroy(evUser->pflush_sem); epicsMutexDestroy(evUser->lock); epicsMutexUnlock (stopSync); @@ -592,23 +592,33 @@ void db_cancel_event (dbEventSubscription event) UNLOCKEVQUE (que); if(sync) { - /* wait for worker to cycle */ + /* cycle through worker */ struct event_user *evUser = que->evUser; epicsUInt32 curSeq; + event_waiter wait; + wait.wake = epicsEventCreate(epicsEventEmpty); /* may fail */ + epicsMutexMustLock ( evUser->lock ); + ellAdd(&evUser->waiters, &wait.node); /* grab current cycle counter, then wait for it to change */ curSeq = evUser->pflush_seq; do { epicsMutexUnlock( evUser->lock ); - epicsEventMustWait(evUser->pflush_sem); - /* The complexity needed to track the # of waiters does not seem - * worth it for the relatively rare situation of concurrent cancel. - * So uncondtionally re-trigger. This will result in one spurious - * wakeup for each cancellation. - */ - epicsEventTrigger(evUser->pflush_sem); + /* ensure worker will cycle at least once */ + epicsEventMustTrigger(evUser->ppendsem); + + if(wait.wake) { + epicsEventMustWait(wait.wake); + } else { + epicsThreadSleep(0.01); /* ick. but better than cantProceed() */ + } + epicsMutexMustLock ( evUser->lock ); } while(curSeq == evUser->pflush_seq); + ellDelete(&evUser->waiters, &wait.node); + /* destroy under lock to ensure epicsEventMustTrigger() has returned */ + if(wait.wake) + epicsEventDestroy(wait.wake); epicsMutexUnlock( evUser->lock ); } } @@ -1041,11 +1051,18 @@ static void event_task (void *pParm) pendexit = evUser->pendexit; evUser->pflush_seq++; + if(ellCount(&evUser->waiters)) { + /* hold lock throughout to avoid race between event trigger and destroy */ + ELLNODE *cur; + for(cur = ellFirst(&evUser->waiters); cur; cur = ellNext(cur)) { + event_waiter *w = CONTAINER(cur, event_waiter, node); + if(w->wake) + epicsEventMustTrigger(w->wake); + } + } epicsMutexUnlock ( evUser->lock ); - epicsEventSignal(evUser->pflush_sem); - } while( ! pendexit ); epicsMutexDestroy(evUser->firstque.writelock); From eb3f8a004ca47543b1fbb7c7e81850afdd2030a6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Oct 2023 08:25:27 -0700 Subject: [PATCH 23/66] const-ify dbCopyEntry() and dbCopyEntryContents() --- modules/database/src/ioc/dbStatic/dbStaticLib.c | 4 ++-- modules/database/src/ioc/dbStatic/dbStaticLib.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index 81556e0b7..f8fa7608a 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -637,7 +637,7 @@ void dbFinishEntry(DBENTRY *pdbentry) } } -DBENTRY * dbCopyEntry(DBENTRY *pdbentry) +DBENTRY * dbCopyEntry(const DBENTRY *pdbentry) { DBENTRY *pnew; @@ -647,7 +647,7 @@ DBENTRY * dbCopyEntry(DBENTRY *pdbentry) return(pnew); } -void dbCopyEntryContents(DBENTRY *pfrom,DBENTRY *pto) +void dbCopyEntryContents(const DBENTRY *pfrom,DBENTRY *pto) { *pto = *pfrom; pto->message = NULL; diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.h b/modules/database/src/ioc/dbStatic/dbStaticLib.h index 568517edd..6f772f27d 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.h +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.h @@ -51,9 +51,9 @@ DBCORE_API void dbInitEntry(DBBASE *pdbbase, DBENTRY *pdbentry); DBCORE_API void dbFinishEntry(DBENTRY *pdbentry); -DBCORE_API DBENTRY * dbCopyEntry(DBENTRY *pdbentry); -DBCORE_API void dbCopyEntryContents(DBENTRY *pfrom, - DBENTRY *pto); +DBCORE_API DBENTRY * dbCopyEntry(const DBENTRY *pdbentry); +DBCORE_API void dbCopyEntryContents(const DBENTRY *pfrom, + DBENTRY *pto); DBCORE_API extern int dbBptNotMonotonic; From 95bd5453d93fd23d6700f044be1a38632b407045 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Oct 2023 08:57:12 -0700 Subject: [PATCH 24/66] dbRecordField() add "did you mean..." hint for unknown field --- .../database/src/ioc/dbStatic/dbLexRoutines.c | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 4819d4a41..16124d64e 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1167,8 +1167,28 @@ static void dbRecordField(char *name,char *value) pdbentry = ptempListNode->item; status = dbFindField(pdbentry,name); if (status) { - epicsPrintf("Record \"%s\" does not have a field \"%s\"\n", - dbGetRecordName(pdbentry), name); + epicsPrintf("%s Record \"%s\" does not have a field \"%s\"\n", + dbGetRecordTypeName(pdbentry), dbGetRecordName(pdbentry), name); + if(dbGetRecordName(pdbentry)) { + DBENTRY temp; + double bestSim = -1.0; + const dbFldDes *bestFld = NULL; + dbCopyEntryContents(pdbentry, &temp); + for(status = dbFirstField(&temp, 0); !status; status = dbNextField(&temp, 0)) { + double sim = epicsStrSimilarity(name, temp.pflddes->name); + if(!bestFld || sim > bestSim) { + bestSim = sim; + bestFld = temp.pflddes; + } + } + dbFinishEntry(&temp); + if(bestSim>0.0) { + epicsPrintf(" Did you mean \"%s\"?", bestFld->name); + if(bestFld->prompt) + epicsPrintf(" (%s)", bestFld->prompt); + epicsPrintf("\n"); + } + } yyerror(NULL); return; } From 3fa19323457ba747ef47ed206c818fc21856738c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 7 Nov 2023 15:14:09 -0800 Subject: [PATCH 25/66] update ci-scripts --- .ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci b/.ci index 899b18336..130e88b70 160000 --- a/.ci +++ b/.ci @@ -1 +1 @@ -Subproject commit 899b18336b4ce3bd9328fd30c33621224c78a4d7 +Subproject commit 130e88b7095812da93e423c602651e30f39da11a From f4be9daf4d3ab03ebc6c9d9c546c87a0efb83608 Mon Sep 17 00:00:00 2001 From: Jeremy Lorelli Date: Fri, 3 Nov 2023 11:40:25 -0700 Subject: [PATCH 26/66] Null check callback function in callbackRequest Previously, calling callbackRequest(pcallback), where pcallback->callback is NULL, would result in a crash on one of the callback threads. --- modules/database/src/ioc/db/callback.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/database/src/ioc/db/callback.c b/modules/database/src/ioc/db/callback.c index 556da37b9..0e40138e8 100644 --- a/modules/database/src/ioc/db/callback.c +++ b/modules/database/src/ioc/db/callback.c @@ -344,6 +344,10 @@ int callbackRequest(epicsCallback *pcallback) epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback was NULL\n"); return S_db_notInit; } + if (!pcallback->callback) { + epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback->callback was NULL\n"); + return S_db_notInit; + } priority = pcallback->priority; if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) { epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Bad priority\n"); From 63740f2edd3c39211b466f21d8ae0680dc3e1cc6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Oct 2023 11:26:25 -0700 Subject: [PATCH 27/66] colorize more errlog messages --- modules/database/src/ioc/dbStatic/dbLexRoutines.c | 2 +- modules/database/src/ioc/dbStatic/dbStaticLib.c | 4 ++-- modules/database/src/ioc/dbStatic/dbStaticRun.c | 2 +- modules/database/src/ioc/dbStatic/dbYacc.y | 4 ++-- modules/database/src/ioc/misc/iocInit.c | 2 +- modules/libcom/src/as/asLib.y | 2 +- modules/libcom/src/pool/threadPool.c | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 16124d64e..0b90f4b08 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1086,7 +1086,7 @@ int dbRecordNameValidate(const char *name) name, c); } else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') { - epicsPrintf("Error: Bad character '%c' in Record/Alias name \"%s\"\n", + epicsPrintf(ERL_ERROR ": Bad character '%c' in Record/Alias name \"%s\"\n", c, name); yyerrorAbort(NULL); return 1; diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index f8fa7608a..2e3811dca 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -2204,11 +2204,11 @@ long dbInitRecordLinks(dbRecordType *rtyp, struct dbCommon *prec) */ } else if(dbCanSetLink(plink, &link_info, devsup)!=0) { - errlogPrintf("Error: %s.%s: can't initialize link type %d with \"%s\" (type %d)\n", + errlogPrintf(ERL_ERROR ": %s.%s: can't initialize link type %d with \"%s\" (type %d)\n", prec->name, pflddes->name, plink->type, plink->text, link_info.ltype); } else if(dbSetLink(plink, &link_info, devsup)) { - errlogPrintf("Error: %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n", + errlogPrintf(ERL_ERROR ": %s.%s: failed to initialize link type %d with \"%s\" (type %d)\n", prec->name, pflddes->name, plink->type, plink->text, link_info.ltype); } free(plink->text); diff --git a/modules/database/src/ioc/dbStatic/dbStaticRun.c b/modules/database/src/ioc/dbStatic/dbStaticRun.c index 198ff5c1a..ee9480c54 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticRun.c +++ b/modules/database/src/ioc/dbStatic/dbStaticRun.c @@ -143,7 +143,7 @@ long dbAllocRecord(DBENTRY *pdbentry,const char *precordName) status = dbPutStringNum(pdbentry,pflddes->initial); if(status) - epicsPrintf("Error initializing %s.%s initial %s\n", + epicsPrintf(ERL_ERROR " initializing %s.%s initial %s\n", pdbRecordType->name,pflddes->name,pflddes->initial); } break; diff --git a/modules/database/src/ioc/dbStatic/dbYacc.y b/modules/database/src/ioc/dbStatic/dbYacc.y index 75fb86cf0..369fd914f 100644 --- a/modules/database/src/ioc/dbStatic/dbYacc.y +++ b/modules/database/src/ioc/dbStatic/dbYacc.y @@ -370,9 +370,9 @@ json_value: jsonNULL { $$ = dbmfStrdup("null"); } static int yyerror(char *str) { if (str) - epicsPrintf("Error: %s\n", str); + epicsPrintf(ERL_ERROR ": %s\n", str); else - epicsPrintf("Error"); + epicsPrintf(ERL_ERROR ""); if (!yyFailed) { /* Only print this stuff once */ epicsPrintf(" at or before '%s'", yytext); dbIncludePrint(); diff --git a/modules/database/src/ioc/misc/iocInit.c b/modules/database/src/ioc/misc/iocInit.c index 3be83adbe..1b1d4fc0b 100644 --- a/modules/database/src/ioc/misc/iocInit.c +++ b/modules/database/src/ioc/misc/iocInit.c @@ -173,7 +173,7 @@ static int iocBuild_2(void) scanInit(); if (asInit()) { - errlogPrintf("iocBuild: asInit Failed.\n"); + errlogPrintf(ERL_ERROR " iocBuild: asInit Failed.\n"); return -1; } dbProcessNotifyInit(); diff --git a/modules/libcom/src/as/asLib.y b/modules/libcom/src/as/asLib.y index ca22ee55f..1e7397123 100644 --- a/modules/libcom/src/as/asLib.y +++ b/modules/libcom/src/as/asLib.y @@ -209,7 +209,7 @@ static int yyerror(char *str) if (strlen(str)) errlogPrintf("%s at line %d\n", str, line_num); else - errlogPrintf("Error at line %d\n", line_num); + errlogPrintf(ERL_ERROR " at line %d\n", line_num); yyFailed = TRUE; return 0; } diff --git a/modules/libcom/src/pool/threadPool.c b/modules/libcom/src/pool/threadPool.c index d4f009107..a353aa31a 100644 --- a/modules/libcom/src/pool/threadPool.c +++ b/modules/libcom/src/pool/threadPool.c @@ -42,7 +42,7 @@ epicsThreadPool* epicsThreadPoolCreate(epicsThreadPoolConfig *opts) /* caller likely didn't initialize the options structure */ if (opts && opts->maxThreads == 0) { - errlogMessage("Error: epicsThreadPoolCreate() options provided, but not initialized"); + errlogMessage(ERL_ERROR ": epicsThreadPoolCreate() options provided, but not initialized"); return NULL; } @@ -78,7 +78,7 @@ epicsThreadPool* epicsThreadPoolCreate(epicsThreadPoolConfig *opts) if (pool->threadsRunning == 0 && pool->conf.initialThreads != 0) { epicsMutexUnlock(pool->guard); - errlogPrintf("Error: Unable to create any threads for thread pool\n"); + errlogPrintf(ERL_ERROR ": Unable to create any threads for thread pool\n"); goto cleanup; } From a352865df9b0da81ef6dab6be48eb21ab98f0846 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Oct 2023 11:25:44 -0700 Subject: [PATCH 28/66] print ANSI escapes to stderr unconditionally print ANSI some escapes (to colorize errors) to the stderr stream. --- modules/ca/src/client/udpiiu.cpp | 6 +++--- modules/ca/src/tools/caput.c | 5 +++-- modules/database/src/ioc/bpt/makeBpt.c | 5 +++-- modules/database/src/ioc/dbStatic/dbLexRoutines.c | 2 +- modules/database/src/ioc/dbStatic/dbStaticIocRegister.c | 3 ++- modules/database/src/ioc/dbStatic/dbStaticLib.c | 2 +- modules/database/src/ioc/dbtemplate/dbLoadTemplate.y | 3 ++- modules/database/src/ioc/dbtemplate/msi.cpp | 2 +- .../src/ioc/misc/registerAllRecordDeviceDrivers.cpp | 3 ++- modules/libcom/src/iocsh/iocsh.cpp | 4 ++-- 10 files changed, 20 insertions(+), 15 deletions(-) diff --git a/modules/ca/src/client/udpiiu.cpp b/modules/ca/src/client/udpiiu.cpp index c6ffb6def..d36e2c5b4 100644 --- a/modules/ca/src/client/udpiiu.cpp +++ b/modules/ca/src/client/udpiiu.cpp @@ -549,7 +549,7 @@ void epicsStdCall caRepeaterRegistrationMessage ( char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - fprintf ( stderr, "error sending registration message to CA repeater daemon was \"%s\"\n", + fprintf ( stderr, ERL_ERROR " sending registration message to CA repeater daemon was \"%s\"\n", sockErrBuf ); } } @@ -813,13 +813,13 @@ bool udpiiu::exceptionRespAction ( if ( msg.m_postsize > sizeof ( caHdr ) ){ errlogPrintf ( - "error condition \"%s\" detected by %s with context \"%s\" at %s\n", + ERL_ERROR " condition \"%s\" detected by %s with context \"%s\" at %s\n", ca_message ( msg.m_available ), name, reinterpret_cast ( &reqMsg + 1 ), date ); } else{ errlogPrintf ( - "error condition \"%s\" detected by %s at %s\n", + ERL_ERROR " condition \"%s\" detected by %s at %s\n", ca_message ( msg.m_available ), name, date ); } diff --git a/modules/ca/src/tools/caput.c b/modules/ca/src/tools/caput.c index 3f368469c..1e9158426 100644 --- a/modules/ca/src/tools/caput.c +++ b/modules/ca/src/tools/caput.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -549,7 +550,7 @@ int main (int argc, char *argv[]) result = ca_array_put (dbrType, count, pvs[0].chid, pbuf); } if (result != ECA_NORMAL) { - fprintf(stderr, "Error from put operation: %s\n", ca_message(result)); + fprintf(stderr, ERL_ERROR " from put operation: %s\n", ca_message(result)); free(sbuf); free(dbuf); free(ebuf); return 1; } @@ -570,7 +571,7 @@ int main (int argc, char *argv[]) } if (result != ECA_NORMAL) { - fprintf(stderr, "Error occured writing data: %s\n", ca_message(result)); + fprintf(stderr, ERL_ERROR " occured writing data: %s\n", ca_message(result)); free(sbuf); free(dbuf); free(ebuf); return 1; } diff --git a/modules/database/src/ioc/bpt/makeBpt.c b/modules/database/src/ioc/bpt/makeBpt.c index 23bcb3143..51821ebd9 100644 --- a/modules/database/src/ioc/bpt/makeBpt.c +++ b/modules/database/src/ioc/bpt/makeBpt.c @@ -21,6 +21,7 @@ #include #include "dbDefs.h" +#include "errlog.h" #include "ellLib.h" #include "cvtTable.h" @@ -125,12 +126,12 @@ int main(int argc, char **argv) } inFile = fopen(argv[1],"r"); if(!inFile) { - fprintf(stderr,"Error opening %s\n",argv[1]); + fprintf(stderr,ERL_ERROR " opening %s\n",argv[1]); exit(-1); } outFile = fopen(outFilename,"w"); if(!outFile) { - fprintf(stderr,"Error opening %s\n",outFilename); + fprintf(stderr,ERL_ERROR " opening %s\n",outFilename); exit(-1); } while(fgets(inbuf,MAX_LINE_SIZE,inFile)) { diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 0b90f4b08..7acaaa292 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1068,7 +1068,7 @@ int dbRecordNameValidate(const char *name) const char *pos = name; if (!*name) { - yyerrorAbort("Error: Record/Alias name can't be empty"); + yyerrorAbort(ERL_ERROR ": Record/Alias name can't be empty"); return 1; } diff --git a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c index 91f1ed144..ff9aafc78 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c +++ b/modules/database/src/ioc/dbStatic/dbStaticIocRegister.c @@ -10,6 +10,7 @@ #include "iocsh.h" #include "errSymTbl.h" +#include "errlog.h" #include "dbStaticIocRegister.h" #include "dbStaticLib.h" @@ -254,7 +255,7 @@ static void dbCreateAliasCallFunc(const iocshArgBuf *args) } dbFinishEntry(&ent); if(status) { - fprintf(stderr, "Error: %ld %s\n", status, errSymMsg(status)); + fprintf(stderr, ERL_ERROR ": %ld %s\n", status, errSymMsg(status)); iocshSetError(1); } } diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index 2e3811dca..19e154956 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -89,7 +89,7 @@ static FILE *openOutstream(const char *filename) errno = 0; stream = fopen(filename,"w"); if(!stream) { - fprintf(stderr,"error opening %s %s\n",filename,strerror(errno)); + fprintf(stderr,ERL_ERROR " opening %s %s\n",filename,strerror(errno)); return 0; } return stream; diff --git a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y index b14f5b606..a382459c1 100644 --- a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y +++ b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.y @@ -16,6 +16,7 @@ #include "osiUnistd.h" #include "macLib.h" #include "dbmf.h" +#include "errlog.h" #include "epicsExport.h" #include "dbAccess.h" @@ -337,7 +338,7 @@ int dbLoadTemplate(const char *sub_file, const char *cmd_collect) if (dbTemplateMaxVars < 1) { - fprintf(stderr,"Error: dbTemplateMaxVars = %d, must be +ve\n", + fprintf(stderr,ERL_ERROR ": dbTemplateMaxVars = %d, must be +ve\n", dbTemplateMaxVars); return -1; } diff --git a/modules/database/src/ioc/dbtemplate/msi.cpp b/modules/database/src/ioc/dbtemplate/msi.cpp index d504e3ea4..c4c0caa64 100644 --- a/modules/database/src/ioc/dbtemplate/msi.cpp +++ b/modules/database/src/ioc/dbtemplate/msi.cpp @@ -264,7 +264,7 @@ static void addMacroReplacements(MAC_HANDLE * const macPvt, if (status) { status = macInstallMacros(macPvt, pairs); if (!status) { - fprintf(stderr, "Error from macInstallMacros\n"); + fprintf(stderr, ERL_ERROR " from macInstallMacros\n"); usageExit(1); } free(pairs); diff --git a/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp b/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp index a744578d3..f6a21dc77 100644 --- a/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp +++ b/modules/database/src/ioc/misc/registerAllRecordDeviceDrivers.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -248,7 +249,7 @@ registerAllRecordDeviceDrivers(DBBASE *pdbbase) } catch(std::exception& e) { dbFinishEntry(&entry); - fprintf(stderr, "Error: %s\n", e.what()); + fprintf(stderr, ERL_ERROR ": %s\n", e.what()); return 2; } } diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index b40752a73..daa6dc368 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -639,7 +639,7 @@ struct ReadlineContext { if(!hist_file.empty()) { if(int err = read_history(hist_file.c_str())) { if(err!=ENOENT) - fprintf(stderr, "Error %s (%d) loading '%s'\n", + fprintf(stderr, ERL_ERROR " %s (%d) loading '%s'\n", strerror(err), err, hist_file.c_str()); } stifle_history(1024); // some limit... @@ -654,7 +654,7 @@ struct ReadlineContext { #ifdef USE_READLINE if(!hist_file.empty()) { if(int err = write_history(hist_file.c_str())) { - fprintf(stderr, "Error %s (%d) writing '%s'\n", + fprintf(stderr, ERL_ERROR " %s (%d) writing '%s'\n", strerror(err), err, hist_file.c_str()); } } From ffc2d0f23a39eb9819cd135c776531a9e1e6500b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 27 Oct 2023 10:01:31 -0700 Subject: [PATCH 29/66] incorrect error check on GetStdHandle() Likely inconsequential as GetConsoleMode() should return 0 when given an invalid handle. --- modules/libcom/src/error/errlog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/error/errlog.c b/modules/libcom/src/error/errlog.c index 6ae267323..480375ea4 100644 --- a/modules/libcom/src/error/errlog.c +++ b/modules/libcom/src/error/errlog.c @@ -246,7 +246,7 @@ int isATTY(FILE* fp) else if(fp==stderr) hand = GetStdHandle(STD_ERROR_HANDLE); #ifdef ENABLE_VIRTUAL_TERMINAL_PROCESSING - if(hand && GetConsoleMode(hand, &mode)) { + if(hand!=INVALID_HANDLE_VALUE && GetConsoleMode(hand, &mode)) { (void)SetConsoleMode(hand, mode|ENABLE_VIRTUAL_TERMINAL_PROCESSING); mode = 0u; if(GetConsoleMode(hand, &mode) && (mode&ENABLE_VIRTUAL_TERMINAL_PROCESSING)) From f2fe9d12032569a8b1d3f09ddf7e07f2ce8c04dd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 2 Nov 2023 15:23:05 -0700 Subject: [PATCH 30/66] bi "Raw Soft Channel" use MASK If set, apply MASK to value read into RVAL. --- modules/database/src/std/dev/devBiSoftRaw.c | 3 +++ modules/database/src/std/rec/biRecord.dbd.pod | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/modules/database/src/std/dev/devBiSoftRaw.c b/modules/database/src/std/dev/devBiSoftRaw.c index 0b57974b9..0f1ab2fdd 100644 --- a/modules/database/src/std/dev/devBiSoftRaw.c +++ b/modules/database/src/std/dev/devBiSoftRaw.c @@ -51,6 +51,9 @@ static long readLocked(struct link *pinp, void *dummy) if (status) return status; + if (prec->mask) + prec->rval &= prec->mask; + if (dbLinkIsConstant(&prec->tsel) && prec->tse == epicsTimeEventDeviceTime) dbGetTimeStamp(pinp, &prec->time); diff --git a/modules/database/src/std/rec/biRecord.dbd.pod b/modules/database/src/std/rec/biRecord.dbd.pod index 40ecd0293..157c33fe6 100644 --- a/modules/database/src/std/rec/biRecord.dbd.pod +++ b/modules/database/src/std/rec/biRecord.dbd.pod @@ -60,8 +60,10 @@ this chapter for information on soft device support. If the record gets its values from hardware or uses the C device support, the device support routines place the value in the RVAL -field which is then converted using the process described in the next -section. +field. +(Since UNRELEASED) If the MASK field is non-zero, then this MASK is applied to RVAL. +The value of RVAL is then converted using the process described in the +next section. =fields INP, DTYP, ZNAM, ONAM, RVAL, VAL From 0bc6ff3d4c0c309cd76e91c6bacad33c7ec59e28 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 7 Nov 2023 15:42:12 -0800 Subject: [PATCH 31/66] release notes --- documentation/RELEASE_NOTES.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 8c9f2a13e..2fe399ff3 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,6 +22,34 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.7 +### bi "Raw Soft Channel" use MASK + +If MASK is non-zero, The raw device support will now apply MASK to the +value read into RVAL. +eg. allows extraction of a bit from an input integer. + +``` +record(longin, "integer") { + field(VAL, "0xff") +} +record(bi, "bit1") { + field(DESC, "extract bit 1") + field(DTYP, "Raw Soft Channel") + field(INP , "integer") + field(MASK, "0x2") + field(ZNAM, "Clear") + field(ONAM, "Set") +} +``` + +### ANSI escapes in stderr + +ANSI escape charactor sequences may now be printed to the stderr stream. +These escapes will appear in logs captured from that stream. +Tools which parse and/or render these logs may need to be adjusted to +either strip out the escapes, or to translate them into markup. +(see [ansi2html](https://pypi.org/project/ansi2html/) for example) + ### Allow explicit append with `dbRecordsOnceOnly!=0` Previously setting `dbRecordsOnceOnly!=0` prevented any further changes to a record via a .db file. eg. From 7a65c001ce178f2547fa05a0e0a98b02f32b434d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 15 Nov 2023 07:31:53 -0800 Subject: [PATCH 32/66] update submodules --- modules/pvAccess | 2 +- modules/pvData | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/pvAccess b/modules/pvAccess index 81d79ecc4..cf483d664 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 81d79ecc49147452d8d87ec4eceb0975830a93c7 +Subproject commit cf483d664df92440443526acc276bc823c34ff31 diff --git a/modules/pvData b/modules/pvData index 13e4e577b..dd74289ea 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 13e4e577bbc197ee7fe27e858e6ecd88d5265b45 +Subproject commit dd74289eaf646670d1f62e2c6bbadbd400d1f17a From 7a7028de56714b944c4e5251bb962ceee4d5e67d Mon Sep 17 00:00:00 2001 From: Uchenna Ezeobi Date: Fri, 17 Nov 2023 13:00:28 -0600 Subject: [PATCH 33/66] Config: Fixed Hard coded LDFLAGS in MVME2500 --- configure/os/CONFIG.Common.RTEMS-qoriq_e500 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/os/CONFIG.Common.RTEMS-qoriq_e500 b/configure/os/CONFIG.Common.RTEMS-qoriq_e500 index 7f5c42e8e..94c7e825e 100644 --- a/configure/os/CONFIG.Common.RTEMS-qoriq_e500 +++ b/configure/os/CONFIG.Common.RTEMS-qoriq_e500 @@ -22,7 +22,7 @@ ARCH_DEP_CFLAGS += -DRTEMS_HAS_ALTIVEC #OP_SYS_LDLIBS += -lbspExt #does not use posix stuff ... want to ignore OP_SYS_LDLIBS += -Wl,--gc-sections #ARCH_DEP_LDFLAGS = -mcpu=8540 -meabi -msdata=sysv -mstrict-align -mspe -mabi=spe -mfloat-gprs=double -ARCH_DEP_LDFLAGS = -L$(RTEMS_BASE)/powerpc-rtems5/qoriq_e500/lib +ARCH_DEP_LDFLAGS = -L$(RTEMS_BASE)/$(GNU_TARGET)$(RTEMS_VERSION)/$(RTEMS_BSP)/lib MUNCH_SUFFIX = .img MUNCHNAME = $(PRODNAME:%$(EXE)=%$(MUNCH_SUFFIX)) From 511bf1ffcae641a9994c0f37c8bb66ed81caf44e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 25 Nov 2023 12:14:00 -0800 Subject: [PATCH 34/66] const-ify dbLink arrays external code really should never be modifying pamaplinkType[] --- modules/database/src/ioc/db/dbLock.c | 2 +- modules/database/src/ioc/dbStatic/dbStaticLib.c | 6 +++--- modules/database/src/ioc/dbStatic/link.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/database/src/ioc/db/dbLock.c b/modules/database/src/ioc/db/dbLock.c index 8ddb5dfc8..9a6b9efea 100644 --- a/modules/database/src/ioc/db/dbLock.c +++ b/modules/database/src/ioc/db/dbLock.c @@ -869,7 +869,7 @@ nosplit: } } -static char *msstring[4]={"NMS","MS","MSI","MSS"}; +static const char *msstring[4]={"NMS","MS","MSI","MSS"}; long dblsr(char *recordname,int level) { diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index 19e154956..eb008fb87 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -57,10 +57,10 @@ static char *pNullString = ""; */ STATIC_ASSERT(messagesize >= 21); -static char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"}; -static char *msstring[4]={" NMS"," MS"," MSI"," MSS"}; +static const char *ppstring[5]={" NPP"," PP"," CA"," CP"," CPP"}; +static const char *msstring[4]={" NMS"," MS"," MSI"," MSS"}; -maplinkType pamaplinkType[LINK_NTYPES] = { +const maplinkType pamaplinkType[LINK_NTYPES] = { {"CONSTANT",CONSTANT}, {"PV_LINK",PV_LINK}, {"VME_IO",VME_IO}, diff --git a/modules/database/src/ioc/dbStatic/link.h b/modules/database/src/ioc/dbStatic/link.h index 74607a1b1..a7edebf57 100644 --- a/modules/database/src/ioc/dbStatic/link.h +++ b/modules/database/src/ioc/dbStatic/link.h @@ -43,11 +43,11 @@ extern "C" { #define VXI_IO 15 #define LINK_NTYPES 16 typedef struct maplinkType { - char *strvalue; + const char *strvalue; int value; } maplinkType; -DBCORE_API extern maplinkType pamaplinkType[]; +DBCORE_API extern const maplinkType pamaplinkType[LINK_NTYPES]; #define VXIDYNAMIC 0 #define VXISTATIC 1 From 69d05fe5b02088549f0b72630e2ef61dafa0ec15 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 26 Nov 2023 15:20:58 -0800 Subject: [PATCH 35/66] Add ERROR to error messages --- modules/database/src/ioc/db/dbAccess.c | 15 +++++---------- modules/database/src/ioc/dbtemplate/msi.cpp | 4 ++-- modules/libcom/src/as/asLibRoutines.c | 4 ++-- modules/libcom/src/iocsh/iocsh.cpp | 6 +++--- 4 files changed, 12 insertions(+), 17 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index 7f6a6b6f7..4128cbe4e 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -798,18 +798,13 @@ int dbLoadRecords(const char* file, const char* subs) return -1; } status = dbReadDatabase(&pdbbase, file, 0, subs); - switch(status) - { - case 0: + if(status==0) { if(dbLoadRecordsHook) dbLoadRecordsHook(file, subs); - break; - case -2: - errlogPrintf("dbLoadRecords: failed to load '%s'\n" - " Records cannot be loaded after iocInit!\n", file); - break; - default: - errlogPrintf("dbLoadRecords: failed to load '%s'\n", file); + } else { + fprintf(stderr, ERL_ERROR " failed to load '%s'\n", file); + if(status==-2) + fprintf(stderr, " Records cannot be loaded after iocInit!\n"); } return status; } diff --git a/modules/database/src/ioc/dbtemplate/msi.cpp b/modules/database/src/ioc/dbtemplate/msi.cpp index c4c0caa64..88c5d160d 100644 --- a/modules/database/src/ioc/dbtemplate/msi.cpp +++ b/modules/database/src/ioc/dbtemplate/msi.cpp @@ -522,7 +522,7 @@ static void inputOpenFile(inputData *pinputData, const char * const filename) } if (!fp) { - fprintf(stderr, "msi: Can't open file '%s'\n", filename); + fprintf(stderr, ERL_ERROR " msi: Can't open file '%s'\n", filename); inputErrPrint(pinputData); abortExit(1); } @@ -672,7 +672,7 @@ static void substituteOpen(subInfo **ppvt, const std::string& substitutionName) fp = fopen(substitutionName.c_str(), "r"); if (!fp) { - fprintf(stderr, "msi: Can't open file '%s'\n", substitutionName.c_str()); + fprintf(stderr, ERL_ERROR " msi: Can't open file '%s'\n", substitutionName.c_str()); abortExit(1); } diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index 8ffb85fd7..59dd80bda 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -176,12 +176,12 @@ long epicsStdCall asInitFile(const char *filename,const char *substitutions) fp = fopen(filename,"r"); if(!fp) { - errlogPrintf("asInitFile: Can't open file '%s'\n", filename); + fprintf(stderr, ERL_ERROR " asInitFile: Can't open file '%s'\n", filename); return(S_asLib_badConfig); } status = asInitFP(fp,substitutions); if(fclose(fp)==EOF) { - errMessage(0,"asInitFile: fclose failed!"); + fprintf(stderr, ERL_ERROR " asInitFile: fclose failed!"); if(!status) status = S_asLib_badConfig; } return(status); diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index daa6dc368..39effd9b9 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -204,7 +204,7 @@ showError (const char *filename, int lineno, const char *msg, ...) va_start (ap, msg); if (filename) - fprintf(epicsGetStderr(), "%s line %d: ", filename, lineno); + fprintf(epicsGetStderr(), ERL_ERROR " %s line %d: ", filename, lineno); vfprintf (epicsGetStderr(), msg, ap); fputc ('\n', epicsGetStderr()); va_end (ap); @@ -1434,12 +1434,12 @@ static void varCallFunc(const iocshArgBuf *args) found = 1; } if (!found && name != NULL) - fprintf(epicsGetStderr(), "No var matching %s found.\n", name); + fprintf(epicsGetStderr(), ANSI_RED("No var matching") " %s found.\n", name); } else { v = (iocshVariable *)registryFind(iocshVarID, args[0].sval); if (v == NULL) { - fprintf(epicsGetStderr(), "Var %s not found.\n", name); + fprintf(epicsGetStderr(), "Var %s " ANSI_RED("not found.") "\n", name); } else { varHandler(v->pVarDef, value); From 0cf8c934f9232bdbcc369e47849f1b4b7f940b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Fri, 17 Nov 2023 13:54:29 -0300 Subject: [PATCH 36/66] Set ASL0 for mbboDirect Bx fields. Since the record's VAL field is ASL0, it doesn't make sense to gate writes into the Bx fields with ASL1. --- .../src/std/rec/mbboDirectRecord.dbd.pod | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/modules/database/src/std/rec/mbboDirectRecord.dbd.pod b/modules/database/src/std/rec/mbboDirectRecord.dbd.pod index 7916b1685..b038a2e5f 100644 --- a/modules/database/src/std/rec/mbboDirectRecord.dbd.pod +++ b/modules/database/src/std/rec/mbboDirectRecord.dbd.pod @@ -322,6 +322,7 @@ to alarms that are common to all record types. field(B0,DBF_UCHAR) { prompt("Bit 0") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -329,6 +330,7 @@ to alarms that are common to all record types. field(B1,DBF_UCHAR) { prompt("Bit 1") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -336,6 +338,7 @@ to alarms that are common to all record types. field(B2,DBF_UCHAR) { prompt("Bit 2") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -343,6 +346,7 @@ to alarms that are common to all record types. field(B3,DBF_UCHAR) { prompt("Bit 3") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -350,6 +354,7 @@ to alarms that are common to all record types. field(B4,DBF_UCHAR) { prompt("Bit 4") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -357,6 +362,7 @@ to alarms that are common to all record types. field(B5,DBF_UCHAR) { prompt("Bit 5") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -364,6 +370,7 @@ to alarms that are common to all record types. field(B6,DBF_UCHAR) { prompt("Bit 6") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -371,6 +378,7 @@ to alarms that are common to all record types. field(B7,DBF_UCHAR) { prompt("Bit 7") promptgroup("51 - Output 0-7") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -378,6 +386,7 @@ to alarms that are common to all record types. field(B8,DBF_UCHAR) { prompt("Bit 8") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -385,6 +394,7 @@ to alarms that are common to all record types. field(B9,DBF_UCHAR) { prompt("Bit 9") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -392,6 +402,7 @@ to alarms that are common to all record types. field(BA,DBF_UCHAR) { prompt("Bit 10") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -399,6 +410,7 @@ to alarms that are common to all record types. field(BB,DBF_UCHAR) { prompt("Bit 11") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -406,6 +418,7 @@ to alarms that are common to all record types. field(BC,DBF_UCHAR) { prompt("Bit 12") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -413,6 +426,7 @@ to alarms that are common to all record types. field(BD,DBF_UCHAR) { prompt("Bit 13") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -420,6 +434,7 @@ to alarms that are common to all record types. field(BE,DBF_UCHAR) { prompt("Bit 14") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -427,6 +442,7 @@ to alarms that are common to all record types. field(BF,DBF_UCHAR) { prompt("Bit 15") promptgroup("52 - Output 8-15") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -434,6 +450,7 @@ to alarms that are common to all record types. field(B10,DBF_UCHAR) { prompt("Bit 16") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -441,6 +458,7 @@ to alarms that are common to all record types. field(B11,DBF_UCHAR) { prompt("Bit 17") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -448,6 +466,7 @@ to alarms that are common to all record types. field(B12,DBF_UCHAR) { prompt("Bit 18") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -455,6 +474,7 @@ to alarms that are common to all record types. field(B13,DBF_UCHAR) { prompt("Bit 19") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -462,6 +482,7 @@ to alarms that are common to all record types. field(B14,DBF_UCHAR) { prompt("Bit 20") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -469,6 +490,7 @@ to alarms that are common to all record types. field(B15,DBF_UCHAR) { prompt("Bit 21") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -476,6 +498,7 @@ to alarms that are common to all record types. field(B16,DBF_UCHAR) { prompt("Bit 22") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -483,6 +506,7 @@ to alarms that are common to all record types. field(B17,DBF_UCHAR) { prompt("Bit 23") promptgroup("53 - Output 16-23") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -490,6 +514,7 @@ to alarms that are common to all record types. field(B18,DBF_UCHAR) { prompt("Bit 24") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -497,6 +522,7 @@ to alarms that are common to all record types. field(B19,DBF_UCHAR) { prompt("Bit 25") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -504,6 +530,7 @@ to alarms that are common to all record types. field(B1A,DBF_UCHAR) { prompt("Bit 26") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -511,6 +538,7 @@ to alarms that are common to all record types. field(B1B,DBF_UCHAR) { prompt("Bit 27") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -518,6 +546,7 @@ to alarms that are common to all record types. field(B1C,DBF_UCHAR) { prompt("Bit 28") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -525,6 +554,7 @@ to alarms that are common to all record types. field(B1D,DBF_UCHAR) { prompt("Bit 29") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -532,6 +562,7 @@ to alarms that are common to all record types. field(B1E,DBF_UCHAR) { prompt("Bit 30") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) @@ -539,6 +570,7 @@ to alarms that are common to all record types. field(B1F,DBF_UCHAR) { prompt("Bit 31") promptgroup("54 - Output 24-31") + asl(ASL0) special(SPC_MOD) pp(TRUE) interest(1) From 96857d92bc70dbf6e70f56ab710635b53e6b948d Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 5 Apr 2023 09:27:42 +0200 Subject: [PATCH 37/66] fix problem with commands returning multiple trailing newlines --- src/tools/genVersionHeader.pl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/genVersionHeader.pl b/src/tools/genVersionHeader.pl index c4a0bef20..99598cca1 100644 --- a/src/tools/genVersionHeader.pl +++ b/src/tools/genVersionHeader.pl @@ -20,6 +20,9 @@ use POSIX qw(strftime); use strict; +# Make sure that chomp removes all trailing newlines +$/=''; + # RFC 8601 date+time w/ zone (eg "2014-08-29T09:42-0700") my $tfmt = '%Y-%m-%dT%H:%M'; $tfmt .= '%z' unless $^O eq 'MSWin32'; # %z returns zone name on Windows From 116881ad8757c964af51e06959310c9a4ae3a8e7 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Sun, 19 Nov 2023 15:47:58 +0100 Subject: [PATCH 38/66] Use split() for fetching last tag with darcs (setting $/='' breaks reading multi-line into an array) --- src/tools/genVersionHeader.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/genVersionHeader.pl b/src/tools/genVersionHeader.pl index 99598cca1..371b8db63 100644 --- a/src/tools/genVersionHeader.pl +++ b/src/tools/genVersionHeader.pl @@ -55,7 +55,7 @@ if (-d '_darcs') { # Darcs # v1-4-dirty # is tag 'v1' plus 4 patches # with uncommited modifications - my @tags = `darcs show tags`; + my @tags = split('\n', `darcs show tags`); my $count = `darcs changes --count --from-tag .` - 1; my $result = $tags[0] . '-' . $count; print "== darcs show tags, changes:\n$result\n==\n" if $opt_v; From d9d35a4eab601fd7e6113415574d9e255bcb6967 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Thu, 23 Nov 2023 15:56:21 +0100 Subject: [PATCH 39/66] Allow auto-declarations for dbdExpand.pl --- modules/database/src/tools/dbdExpand.pl | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/database/src/tools/dbdExpand.pl b/modules/database/src/tools/dbdExpand.pl index 5cd26728b..acd292a45 100644 --- a/modules/database/src/tools/dbdExpand.pl +++ b/modules/database/src/tools/dbdExpand.pl @@ -20,10 +20,14 @@ use EPICS::Getopts; use EPICS::Readfile; use EPICS::macLib; -our ($opt_D, @opt_I, @opt_S, $opt_o); +our ($opt_D, $opt_A, @opt_I, @opt_S, $opt_o); -getopts('DI@S@o:') or - die "Usage: dbdExpand [-D] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ..."; +getopts('DAI@S@o:') or + die "Usage: dbdExpand [-D] [-A] [-I dir] [-S macro=val] [-o out.dbd] in.dbd ..."; + +if ($opt_A) { + $DBD::Parser::allowAutoDeclarations = 1; +} my @path = map { split /[:;]/ } @opt_I; # FIXME: Broken on Win32? my $macros = EPICS::macLib->new(@opt_S); From 6a369acd0b655ceb60e9eddb7df7868585910270 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Tue, 5 Dec 2023 15:28:05 +0100 Subject: [PATCH 40/66] Add newline to help text --- modules/database/src/ioc/as/asIocRegister.c | 2 +- modules/libcom/src/iocsh/libComRegister.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/as/asIocRegister.c b/modules/database/src/ioc/as/asIocRegister.c index dcc2a6bdd..b0451bc17 100644 --- a/modules/database/src/ioc/as/asIocRegister.c +++ b/modules/database/src/ioc/as/asIocRegister.c @@ -90,7 +90,7 @@ static const iocshFuncDef asprulesFuncDef = { "asprules",1,asprulesArgs, "List rules of an Access Security Group.\n" "If no Group is specified then list the rules for all groups\n" - "Example: asprules mygroup" + "Example: asprules mygroup\n" }; static void asprulesCallFunc(const iocshArgBuf *args) { diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index f5469396c..5751ad070 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -193,7 +193,7 @@ static const iocshFuncDef epicsEnvShowFuncDef = {"epicsEnvShow",1,epicsEnvShowAr " (default) - show all environment variables\n" " name - show value of specific environment variable\n" "Example: epicsEnvShow\n" - "Example: epicsEnvShow PATH"}; + "Example: epicsEnvShow PATH\n"}; static void epicsEnvShowCallFunc(const iocshArgBuf *args) { epicsEnvShow (args[0].sval); From 56dbc949ffd3dd73939ca73cb6c2116008dff324 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 12 Dec 2023 13:44:08 -0600 Subject: [PATCH 41/66] Add declarations to flex, cleans up Clang 15 warnings. --- modules/libcom/src/flex/Makefile | 2 +- modules/libcom/src/flex/ccl.c | 1 - modules/libcom/src/flex/flex.c | 3 +-- modules/libcom/src/flex/flexdef.h | 38 ++++++++++++++++++++++++++----- modules/libcom/src/flex/gen.c | 3 --- modules/libcom/src/flex/parse.y | 23 +++++++++++-------- modules/libcom/src/flex/scan.c | 7 +++--- modules/libcom/src/flex/sym.c | 7 ------ 8 files changed, 50 insertions(+), 34 deletions(-) diff --git a/modules/libcom/src/flex/Makefile b/modules/libcom/src/flex/Makefile index 5c6f41bfe..9b98e33d5 100644 --- a/modules/libcom/src/flex/Makefile +++ b/modules/libcom/src/flex/Makefile @@ -19,7 +19,7 @@ parse_CPPFLAGS = -DDEFAULT_SKELETON_FILE=$(SKELETON_FILE) INC += flex.skel.static -# flex.c is included in parse.c +# flex.c, scan.c and yylex.c are #included by parse.c e_flex_SRCS += ccl.c e_flex_SRCS += dfa.c e_flex_SRCS += ecs.c diff --git a/modules/libcom/src/flex/ccl.c b/modules/libcom/src/flex/ccl.c index 4d278ba2a..48a2ccc57 100644 --- a/modules/libcom/src/flex/ccl.c +++ b/modules/libcom/src/flex/ccl.c @@ -132,7 +132,6 @@ void cclnegate(int cclp) void list_character_set(FILE *file, int cset[]) { int i; - char *readable_form(); putc( '[', file ); diff --git a/modules/libcom/src/flex/flex.c b/modules/libcom/src/flex/flex.c index 79ea51dda..349d8aff3 100644 --- a/modules/libcom/src/flex/flex.c +++ b/modules/libcom/src/flex/flex.c @@ -188,7 +188,6 @@ int main(int argc, char *argv[]) void flexend(int status) { int tblsiz; - char *flex_gettime(); if ( skelfile != NULL ) { @@ -382,7 +381,7 @@ void flexend(int status) void flexinit(int argc, char **argv) { int i, sawcmpflag; - char *arg, *flex_gettime(), *mktemp(); + char *arg; printstats = syntaxerror = trace = spprdflt = interactive = caseins = false; backtrack_report = performance_report = ddebug = fulltbl = fullspd = false; diff --git a/modules/libcom/src/flex/flexdef.h b/modules/libcom/src/flex/flexdef.h index 0a9736e6c..dd6123da2 100644 --- a/modules/libcom/src/flex/flexdef.h +++ b/modules/libcom/src/flex/flexdef.h @@ -567,8 +567,8 @@ extern int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs; extern int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave; extern int num_backtracking, bol_needed; -void *allocate_array(int size, int element_size); -void *reallocate_array(void *array, int size, int element_size); +extern void *allocate_array(int size, int element_size); +extern void *reallocate_array(void *array, int size, int element_size); #define allocate_integer_array(size) \ (int *) allocate_array( size, sizeof( int ) ) @@ -677,10 +677,20 @@ extern int all_upper (Char *); /* bubble sort an integer array */ extern void bubble (int [], int); +/* replace upper-case letter to lower-case */ +extern Char clower(int c); + +/* returns copy of a string */ +extern char *copy_string(char *str); + +/* returns copy of a (potentially) unsigned string */ +extern Char *copy_unsigned_string(Char *str); + /* shell sort a character array */ extern void cshell (Char [], int, int); -extern void dataend (void); /* finish up a block of data declarations */ +/* finish up a block of data declarations */ +extern void dataend (void); /* report an error message and terminate */ extern void flexerror (char[]) NORETURN; @@ -688,6 +698,9 @@ extern void flexerror (char[]) NORETURN; /* report a fatal error message and terminate */ extern void flexfatal (char[]); +/* return current time */ +extern char *flex_gettime(); + /* report an error message formatted with one integer argument */ extern void lerrif (char[], int); @@ -700,11 +713,18 @@ extern void line_directive_out (FILE*); /* generate a data statment for a two-dimensional array */ extern void mk2data (int); -extern void mkdata (int); /* generate a data statement */ +/* generate a data statement */ +extern void mkdata (int); /* return the integer represented by a string of digits */ extern int myctoi (Char []); +/* return character corresponding to escape sequence */ +extern Char myesc(Char *array); + +/* return the the human-readable form of a character */ +extern char *readable_form(int c); + /* write out one section of the skeleton file */ extern void skelout (void); @@ -784,8 +804,14 @@ extern void cclinstal (Char [], int); /* lookup the number associated with character class */ extern int ccllookup (Char []); -extern void ndinstal (char[], Char[]); /* install a name definition */ -extern void scinstal (char[], int); /* make a start condition */ +/* install a name definition */ +extern void ndinstal (char[], Char[]); + +/* lookup a name definition */ +extern Char *ndlookup(char *nd); + +/* make a start condition */ +extern void scinstal (char[], int); /* lookup the number associated with a start condition */ extern int sclookup (char[]); diff --git a/modules/libcom/src/flex/gen.c b/modules/libcom/src/flex/gen.c index a10fbb537..f683d136c 100644 --- a/modules/libcom/src/flex/gen.c +++ b/modules/libcom/src/flex/gen.c @@ -217,7 +217,6 @@ void genecs(void) int i, j; static char C_char_decl[] = "static const %s %s[%d] =\n { 0,\n"; int numrows; - Char clower(); if ( numecs < csize ) printf( C_char_decl, "YY_CHAR", "yy_ec", csize ); @@ -237,8 +236,6 @@ void genecs(void) if ( trace ) { - char *readable_form(); - fputs( "\n\nEquivalence Classes:\n\n", stderr ); numrows = csize / 8; diff --git a/modules/libcom/src/flex/parse.y b/modules/libcom/src/flex/parse.y index 21ac91730..09aebc5b3 100644 --- a/modules/libcom/src/flex/parse.y +++ b/modules/libcom/src/flex/parse.y @@ -34,11 +34,18 @@ int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen; int trlcontxt, xcluflg, cclsorted, varlength, variable_trail_rule; -Char clower(); static int madeany = false; /* whether we've made the '.' character class */ int previous_continued_action; /* whether the previous rule's action was '|' */ +/* forward declarations */ + +void build_eof_action( void ); +void synerr( char str[] ); +void format_pinpoint_message( char msg[], char arg[] ); +void pinpoint_message( char str[] ); +void yyerror( char msg[] ); + %} %% @@ -626,7 +633,7 @@ string : string CHAR * conditions */ -void build_eof_action() +void build_eof_action( void ) { int i; @@ -652,8 +659,7 @@ void build_eof_action() /* synerr - report a syntax error */ -void synerr( str ) -char str[]; +void synerr( char str[] ) { syntaxerror = true; @@ -665,8 +671,7 @@ char str[]; * pinpointing its location */ -void format_pinpoint_message( msg, arg ) -char msg[], arg[]; +void format_pinpoint_message( char msg[], char arg[] ) { char errmsg[MAXLINE]; @@ -678,8 +683,7 @@ char msg[], arg[]; /* pinpoint_message - write out a message, pinpointing its location */ -void pinpoint_message( str ) -char str[]; +void pinpoint_message( char str[] ) { fprintf( stderr, "\"%s\", line %d: %s\n", infilename, linenum, str ); @@ -690,8 +694,7 @@ char str[]; * currently, messages are ignore */ -void yyerror( msg ) -char msg[]; +void yyerror( char msg[] ) { } diff --git a/modules/libcom/src/flex/scan.c b/modules/libcom/src/flex/scan.c index 67c6be38c..e1fd68eb3 100644 --- a/modules/libcom/src/flex/scan.c +++ b/modules/libcom/src/flex/scan.c @@ -953,6 +953,7 @@ void yy_load_buffer_state ( void ); YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size ); void yy_delete_buffer ( YY_BUFFER_STATE b ); void yy_init_buffer ( YY_BUFFER_STATE b, FILE *file ); +void set_input_file( char *file ); #define yy_new_buffer yy_create_buffer @@ -966,7 +967,7 @@ YY_DECL static int bracelevel, didadef; int i, indented_code = false, checking_used = false, new_xlation = false; int doing_codeblock = false; - Char nmdef[MAXLINE], myesc(); + Char nmdef[MAXLINE]; if ( yy_init ) @@ -1488,7 +1489,6 @@ case 65: # line 333 "scan.l" { Char *nmdefptr; - Char *ndlookup(); (void) strcpy( nmstr, (char *) yytext ); nmstr[yyleng - 1] = '\0'; /* chop trailing brace */ @@ -2230,8 +2230,7 @@ int yywrap() /* set_input_file - open the given file (if NULL, stdin) for scanning */ -void set_input_file( file ) -char *file; +void set_input_file( char *file ) { if ( file ) diff --git a/modules/libcom/src/flex/sym.c b/modules/libcom/src/flex/sym.c index e17d59427..59dac35d8 100644 --- a/modules/libcom/src/flex/sym.c +++ b/modules/libcom/src/flex/sym.c @@ -108,8 +108,6 @@ void cclinstal(Char *ccltxt, int cclnum) /* we don't bother checking the return status because we are not called * unless the symbol is new */ - Char *copy_unsigned_string(); - (void) addsym( (char *) copy_unsigned_string( ccltxt ), (char *) 0, cclnum, ccltab, CCL_HASH_SIZE ); } @@ -191,9 +189,6 @@ int hashfunct(char *str, int hash_size) void ndinstal(char *nd, Char *def) { - char *copy_string(); - Char *copy_unsigned_string(); - if ( addsym( copy_string( nd ), (char *) copy_unsigned_string( def ), 0, ndtbl, NAME_TABLE_HASH_SIZE ) ) synerr( "name defined twice" ); @@ -227,8 +222,6 @@ Char *ndlookup(char *nd) void scinstal(char *str, int xcluflg) { - char *copy_string(); - /* bit of a hack. We know how the default start-condition is * declared, and don't put out a define for it, because it * would come out as "#define 0 1" From 5ecf7d18a8a7dd2a13296400930beb2c9014610e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 12 Dec 2023 13:53:33 -0600 Subject: [PATCH 42/66] Clean up Clang 15 sprintf() warnings in libcom and ca --- modules/ca/src/client/acctst.c | 3 ++- modules/ca/src/client/cac.cpp | 4 ++-- modules/libcom/src/osi/epicsTime.cpp | 2 +- modules/libcom/test/epicsEventTest.cpp | 2 +- modules/libcom/test/epicsMessageQueueTest.cpp | 4 ++-- modules/libcom/test/epicsMutexTest.cpp | 2 +- modules/libcom/test/epicsThreadTest.cpp | 2 +- 7 files changed, 10 insertions(+), 9 deletions(-) diff --git a/modules/ca/src/client/acctst.c b/modules/ca/src/client/acctst.c index 34298680c..44cc0673a 100644 --- a/modules/ca/src/client/acctst.c +++ b/modules/ca/src/client/acctst.c @@ -2575,7 +2575,8 @@ void monitorUpdateTest ( chid chan, unsigned interestLevel ) SEVCHK ( ca_get ( DBR_FLOAT, chan, &temp ), NULL ); SEVCHK ( ca_pend_io ( timeoutToPendIO ), NULL ); - /* printf ( "flow control bypassed %u events\n", flowCtrlCount ); */ + if (0) + printf ( "flow control bypassed %u events\n", flowCtrlCount ); showProgressEnd ( interestLevel ); } diff --git a/modules/ca/src/client/cac.cpp b/modules/ca/src/client/cac.cpp index f8d1d0800..cb09d8d78 100644 --- a/modules/ca/src/client/cac.cpp +++ b/modules/ca/src/client/cac.cpp @@ -1008,7 +1008,7 @@ bool cac::defaultExcep ( char buf[512]; char hostName[64]; iiu.getHostName ( guard, hostName, sizeof ( hostName ) ); - sprintf ( buf, "host=%s ctx=%.400s", hostName, pCtx ); + snprintf( buf, sizeof(buf), "host=%s ctx=%.400s", hostName, pCtx ); this->notify.exception ( guard, status, buf, 0, 0u ); return true; } @@ -1312,7 +1312,7 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, const char * pChannelName, const char * pAcc, const char * pRej ) { char buf[256]; - sprintf ( buf, "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s", + snprintf( buf, sizeof(buf), "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s", pChannelName, pAcc, pRej ); { callbackManager mgr ( this->notify, this->cbMutex ); diff --git a/modules/libcom/src/osi/epicsTime.cpp b/modules/libcom/src/osi/epicsTime.cpp index 43442225e..ae7eb25eb 100644 --- a/modules/libcom/src/osi/epicsTime.cpp +++ b/modules/libcom/src/osi/epicsTime.cpp @@ -238,7 +238,7 @@ size_t epicsStdCall epicsTimeToStrftime (char *pBuff, size_t bufLength, const ch // convert nanosecs to integer of correct range frac /= div[fracWid]; char fracFormat[32]; - sprintf ( fracFormat, "%%0%lulu", fracWid ); + snprintf ( fracFormat, sizeof ( fracFormat ), "%%0%lulu", fracWid ); int status = epicsSnprintf ( pBufCur, bufLenLeft, fracFormat, frac ); if ( status > 0 ) { unsigned long nChar = static_cast < unsigned long > ( status ); diff --git a/modules/libcom/test/epicsEventTest.cpp b/modules/libcom/test/epicsEventTest.cpp index cc73f8398..7f93c36a9 100644 --- a/modules/libcom/test/epicsEventTest.cpp +++ b/modules/libcom/test/epicsEventTest.cpp @@ -244,7 +244,7 @@ MAIN(epicsEventTest) name = (char **)calloc(nthreads, sizeof(char *)); for(int i = 0; i < nthreads; i++) { name[i] = (char *)calloc(16, sizeof(char)); - sprintf(name[i],"producer %d",i); + snprintf(name[i], 16, "producer %d",i); id[i] = epicsThreadCreate(name[i], 40, stackSize, producer, pinfo); epicsThreadSleep(0.1); } diff --git a/modules/libcom/test/epicsMessageQueueTest.cpp b/modules/libcom/test/epicsMessageQueueTest.cpp index d245cde89..d78cfdbd9 100644 --- a/modules/libcom/test/epicsMessageQueueTest.cpp +++ b/modules/libcom/test/epicsMessageQueueTest.cpp @@ -232,7 +232,7 @@ sender(void *arg) int i = 0; while (!sendExit) { - len = sprintf(cbuf, "%s -- %d.", epicsThreadGetNameSelf(), ++i); + len = snprintf(cbuf, sizeof(cbuf), "%s -- %d.", epicsThreadGetNameSelf(), ++i); while (q->trySend((void *)cbuf, len) < 0) epicsThreadSleep(0.005 * (randBelow(5))); epicsThreadSleep(0.005 * (randBelow(20))); @@ -421,7 +421,7 @@ extern "C" void messageQueueTest(void *parm) epicsThreadPriorityHigh, epicsThreadPriorityHigh }; - sprintf(name, "Sender %d", i+1); + snprintf(name, sizeof(name), "Sender %d", i+1); opts.priority = pri[i]; senderId[i] = epicsThreadCreateOpt(name, sender, &q1, &opts); if (!senderId[i]) diff --git a/modules/libcom/test/epicsMutexTest.cpp b/modules/libcom/test/epicsMutexTest.cpp index 3086f679a..5228e9bed 100644 --- a/modules/libcom/test/epicsMutexTest.cpp +++ b/modules/libcom/test/epicsMutexTest.cpp @@ -266,7 +266,7 @@ MAIN(epicsMutexTest) stackSize = epicsThreadGetStackSize(epicsThreadStackSmall); for(i=0; ithreadnum = i; pinfo[i]->mutex = mutex; diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index 24ca294cc..573739f39 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -73,7 +73,7 @@ void testMyThread() int startPriority = 0; for (int i = 0; i < ntasks; i++) { char name[10]; - sprintf(name, "t%d", i); + snprintf(name, sizeof(name), "t%d", i); myThreads[i] = new myThread(i, name); if (i == 0) startPriority = myThreads[i]->thread.getPriority(); From 2e6fd505d20d9c3ecf78f0f9fb9132a89cc8012d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 14 Dec 2023 11:27:30 -0600 Subject: [PATCH 43/66] Use epicsSnprintf() for old MSVC compilers --- modules/ca/src/client/cac.cpp | 5 +++-- modules/libcom/src/osi/epicsTime.cpp | 2 +- modules/libcom/test/epicsEventTest.cpp | 4 ++-- modules/libcom/test/epicsMessageQueueTest.cpp | 6 +++--- modules/libcom/test/epicsMutexTest.cpp | 4 ++-- modules/libcom/test/epicsThreadTest.cpp | 4 ++-- 6 files changed, 13 insertions(+), 12 deletions(-) diff --git a/modules/ca/src/client/cac.cpp b/modules/ca/src/client/cac.cpp index cb09d8d78..fd641ad21 100644 --- a/modules/ca/src/client/cac.cpp +++ b/modules/ca/src/client/cac.cpp @@ -25,6 +25,7 @@ #include #include // vxWorks 6.0 requires this include +#include "epicsStdio.h" #include "dbDefs.h" #include "epicsGuard.h" #include "epicsVersion.h" @@ -1008,7 +1009,7 @@ bool cac::defaultExcep ( char buf[512]; char hostName[64]; iiu.getHostName ( guard, hostName, sizeof ( hostName ) ); - snprintf( buf, sizeof(buf), "host=%s ctx=%.400s", hostName, pCtx ); + epicsSnprintf( buf, sizeof(buf), "host=%s ctx=%.400s", hostName, pCtx ); this->notify.exception ( guard, status, buf, 0, 0u ); return true; } @@ -1312,7 +1313,7 @@ void cac::pvMultiplyDefinedNotify ( msgForMultiplyDefinedPV & mfmdpv, const char * pChannelName, const char * pAcc, const char * pRej ) { char buf[256]; - snprintf( buf, sizeof(buf), "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s", + epicsSnprintf( buf, sizeof(buf), "Channel: \"%.64s\", Connecting to: %.64s, Ignored: %.64s", pChannelName, pAcc, pRej ); { callbackManager mgr ( this->notify, this->cbMutex ); diff --git a/modules/libcom/src/osi/epicsTime.cpp b/modules/libcom/src/osi/epicsTime.cpp index ae7eb25eb..b78191f69 100644 --- a/modules/libcom/src/osi/epicsTime.cpp +++ b/modules/libcom/src/osi/epicsTime.cpp @@ -238,7 +238,7 @@ size_t epicsStdCall epicsTimeToStrftime (char *pBuff, size_t bufLength, const ch // convert nanosecs to integer of correct range frac /= div[fracWid]; char fracFormat[32]; - snprintf ( fracFormat, sizeof ( fracFormat ), "%%0%lulu", fracWid ); + epicsSnprintf ( fracFormat, sizeof ( fracFormat ), "%%0%lulu", fracWid ); int status = epicsSnprintf ( pBufCur, bufLenLeft, fracFormat, frac ); if ( status > 0 ) { unsigned long nChar = static_cast < unsigned long > ( status ); diff --git a/modules/libcom/test/epicsEventTest.cpp b/modules/libcom/test/epicsEventTest.cpp index 7f93c36a9..f9fa87198 100644 --- a/modules/libcom/test/epicsEventTest.cpp +++ b/modules/libcom/test/epicsEventTest.cpp @@ -16,12 +16,12 @@ #include #include #include -#include #include #include #include #include +#include "epicsStdio.h" #include "epicsThread.h" #include "epicsEvent.h" #include "epicsMutex.h" @@ -244,7 +244,7 @@ MAIN(epicsEventTest) name = (char **)calloc(nthreads, sizeof(char *)); for(int i = 0; i < nthreads; i++) { name[i] = (char *)calloc(16, sizeof(char)); - snprintf(name[i], 16, "producer %d",i); + epicsSnprintf(name[i], 16, "producer %d",i); id[i] = epicsThreadCreate(name[i], 40, stackSize, producer, pinfo); epicsThreadSleep(0.1); } diff --git a/modules/libcom/test/epicsMessageQueueTest.cpp b/modules/libcom/test/epicsMessageQueueTest.cpp index d78cfdbd9..fc5a903b9 100644 --- a/modules/libcom/test/epicsMessageQueueTest.cpp +++ b/modules/libcom/test/epicsMessageQueueTest.cpp @@ -10,11 +10,11 @@ /* * Author W. Eric Norum */ -#include #include #include #include +#include "epicsStdio.h" #include "epicsMessageQueue.h" #include "epicsThread.h" #include "epicsExit.h" @@ -232,7 +232,7 @@ sender(void *arg) int i = 0; while (!sendExit) { - len = snprintf(cbuf, sizeof(cbuf), "%s -- %d.", epicsThreadGetNameSelf(), ++i); + len = epicsSnprintf(cbuf, sizeof(cbuf), "%s -- %d.", epicsThreadGetNameSelf(), ++i); while (q->trySend((void *)cbuf, len) < 0) epicsThreadSleep(0.005 * (randBelow(5))); epicsThreadSleep(0.005 * (randBelow(20))); @@ -421,7 +421,7 @@ extern "C" void messageQueueTest(void *parm) epicsThreadPriorityHigh, epicsThreadPriorityHigh }; - snprintf(name, sizeof(name), "Sender %d", i+1); + epicsSnprintf(name, sizeof(name), "Sender %d", i+1); opts.priority = pri[i]; senderId[i] = epicsThreadCreateOpt(name, sender, &q1, &opts); if (!senderId[i]) diff --git a/modules/libcom/test/epicsMutexTest.cpp b/modules/libcom/test/epicsMutexTest.cpp index 5228e9bed..1342b903e 100644 --- a/modules/libcom/test/epicsMutexTest.cpp +++ b/modules/libcom/test/epicsMutexTest.cpp @@ -18,10 +18,10 @@ #include #include #include -#include #include #include +#include "epicsStdio.h" #include "epicsTime.h" #include "epicsThread.h" #include "epicsMutex.h" @@ -266,7 +266,7 @@ MAIN(epicsMutexTest) stackSize = epicsThreadGetStackSize(epicsThreadStackSmall); for(i=0; ithreadnum = i; pinfo[i]->mutex = mutex; diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index 573739f39..6d43e71dc 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -13,11 +13,11 @@ #include #include #include -#include #include #include #include +#include "epicsStdio.h" #include "epicsThread.h" #include "epicsEvent.h" #include "epicsTime.h" @@ -73,7 +73,7 @@ void testMyThread() int startPriority = 0; for (int i = 0; i < ntasks; i++) { char name[10]; - snprintf(name, sizeof(name), "t%d", i); + epicsSnprintf(name, sizeof(name), "t%d", i); myThreads[i] = new myThread(i, name); if (i == 0) startPriority = myThreads[i]->thread.getPriority(); From 4a53713f3729e26f9b4faf3ea59cc5ffabc420e8 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 14 Dec 2023 16:31:42 -0600 Subject: [PATCH 44/66] Update Release Procedures/Checklist --- documentation/ReleaseChecklist.html | 95 ++++++++++++++--------------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index ac65fef3b..0db98a818 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -48,14 +48,14 @@ everything that has to be done since it's so easy to miss steps.

The following roles are used below:

-
Release Manager ()
+
Release Manager
Responsible for managing and tagging the release
-
Platform Developers (informal)
-
Responsible for individual operating system platforms
+
Core Developers
+
Responsible for maintaining the EPICS software
Application Developers
Responsible for support modules that depend on EPICS Base.
-
APS Website Editor (Andrew Johnson)
-
Responsible for the APS EPICS website
+
Website Editors
+
Responsible for the EPICS websites
@@ -72,23 +72,22 @@ everything that has to be done since it's so easy to miss steps.

  Release Manager - Email all developers about the upcoming release and ask for a list - of remaining tasks that must be finished. + Notify core developers about the upcoming release and ask about any + remaining tasks that must be finished.   All developers Check the bug tracker for any outstanding items and handle - appropriately. All bugs that have been fixed should have been marked - as Fix Committed. + appropriately.   Release Manager - Set the Feature Freeze date, by which time all Git commits for - enhancements and new functionality should have been completed. After - this date, commits should only be made to fix problems that show up - during testing. + Set a Feature Freeze date, by which time all Git branches for + enhancements and new functionality should have been merged. After this + date, commits and merges should only be made to fix problems that show + up during testing.   @@ -97,6 +96,7 @@ everything that has to be done since it's so easy to miss steps.

Ensure that documentation will be updated before the release date:
  • Release Notes
  • +
  • Doxygen annotations
  • Other documents
@@ -104,13 +104,8 @@ everything that has to be done since it's so easy to miss steps.

  Release Manager - Review and update this checklist for the upcoming release. - - -   - Release Manager - Create a release milestone on Launchpad. If a target release date is - known set "Date Targeted" to the expected release date. + Review and update this checklist for the upcoming release. + Update the release version number in the tags and messages below. Testing @@ -118,7 +113,7 @@ everything that has to be done since it's so easy to miss steps.

  Platform Developers - Run the built-in test programs on all available host platforms using + Run the internal test programs on all available host platforms using
make -s runtests
@@ -156,6 +151,7 @@ everything that has to be done since it's so easy to miss steps.

Check that documentation has been updated:
  • Release Notes
  • +
  • Doxygen annotations
  • Other documents
@@ -167,8 +163,8 @@ everything that has to be done since it's so easy to miss steps.

- Release Manager - Obtain a positive Ok to release from developers. + Core Developers + Reach a consensus that the software is ready to release. Creating the final release version @@ -191,27 +187,29 @@ everything that has to be done since it's so easy to miss steps.

cd base-7.0/modules/<module>/documentation
pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md - Commit changes (don't push). + Commit these changes (don't push).
  • Edit the module's release version file - configure/CONFIG_module_VERSION and its top-level - Doxyfile; set the DEVELOPMENT_FLAG value to 0 and - remove -dev from the PROJECT_NUMBER string. - Commit changes (don't push).
  • + configure/CONFIG_module_VERSION and the + Doxyfiles in the top-level and/or documentation + directories. In these, set DEVELOPMENT_FLAG to 0 and remove + -dev from the PROJECT_NUMBER string. Commit these + changes (don't push).
  • Tag the module:
    - git tag -m 'ANJ: Tag for EPICS 7.0.7' <module-version> + git tag -m 'ANJ: Tag for EPICS 7.0.8' <module-version>
  • Update the git submodule on the Base-7.0 branch to the - newly-tagged version, but don't commit yet: + newly-tagged version, check the module's status matches the tag:
    cd base-7.0/modules
    git add <module>
    git submodule status --cached
    + Don't commit the submodule updates yet.
  • Edit the module's release version file @@ -221,7 +219,8 @@ everything that has to be done since it's so easy to miss steps.

    PROJECT_NUMBER string, appending -dev to the new module version number. Commit changes.
  • -
  • Push commits and the new tag to the submodule's GitHub repository: +
  • Push commits and the new tag to the submodule's GitHub repository + (assumed to be the upstream remote):
    cd base-7.0/modules/<module>
    git push --follow-tags upstream master @@ -270,10 +269,9 @@ everything that has to be done since it's so easy to miss steps.

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

    Don't push anything to the Launchpad repository - yet.

    +

    Don't push to GitHub yet.

    @@ -305,12 +303,12 @@ everything that has to be done since it's so easy to miss steps.

    files and directories that are only used for continuous integration:
    cd base-7.0
    - ./.tools/make-tar.sh R7.0.7 ../base-7.0.7.tar.gz base-7.0.7/ + ./.tools/make-tar.sh R7.0.8 ../base-7.0.8.tar.gz base-7.0.8/
    Create a GPG signature file of the tarfile as follows:
    cd ..
    - gpg --armor --sign --detach-sig base-7.0.7.tar.gz + gpg --armor --sign --detach-sig base-7.0.8.tar.gz
    @@ -318,8 +316,9 @@ everything that has to be done since it's so easy to miss steps.

    Release Manager Test the tar file by extracting its contents and building it on at - least one supported platform. When this succeeds the commits and new git - tag can be pushed to the Launchpad repository: + least one supported platform. If this succeeds the commits and new git + tag can be pushed to the GitHub repository's 7.0 branch (assumed to be + the upstream remote):
    git push --follow-tags upstream 7.0
    @@ -367,7 +366,7 @@ everything that has to be done since it's so easy to miss steps.

    - Publish to epics-controls + Publish to epics-controls.org @@ -375,7 +374,7 @@ everything that has to be done since it's so easy to miss steps.

    Upload the tar file and its .asc signature file to the epics-controls web-server.
    - scp base-7.0.7.tar.gz base-7.0.7.tar.gz.asc epics-controls:download/base
    + scp base-7.0.8.tar.gz base-7.0.8.tar.gz.asc epics-controls:download/base
    @@ -392,22 +391,22 @@ everything that has to be done since it's so easy to miss steps.

    - Publish to Launchpad + Publish to GitHub Release Manager - Go to the Launchpad milestone for this release. Click the Create - release button and add the release date. Put a URL for the release page - in the Release notes box, and click the Create release button. Upload - the tar file and its .asc signature file to the new Launchpad - release page. + Go to the GitHub + + Create release from tag R7.0.8 page. + Upload the tar file and its .asc signature file to the new + GitHub release page. Release Manager - Find all Launchpad bug reports with the status Fix Committed which - have been fixed in this release and mark them Fix Released. + We used to close out bug reports in Launchpad at release-time, this + would be the time to do that if we have an equivalent on GitHub. From 331df3d7e44109868d392eacd065060301f8933b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 13 Dec 2023 14:04:40 -0600 Subject: [PATCH 45/66] UNRELEASED => 7.0.8 --- modules/database/src/std/rec/biRecord.dbd.pod | 4 ++-- modules/database/src/std/rec/calcRecord.dbd.pod | 2 +- modules/database/src/std/rec/calcoutRecord.dbd.pod | 2 +- modules/database/src/std/rec/longoutRecord.dbd.pod | 4 ++-- modules/libcom/src/calc/postfix.h | 2 +- modules/libcom/src/error/errlog.h | 4 ++-- modules/libcom/src/iocsh/initHooks.h | 8 ++++---- modules/libcom/src/iocsh/iocsh.h | 12 ++++++++---- 8 files changed, 21 insertions(+), 17 deletions(-) diff --git a/modules/database/src/std/rec/biRecord.dbd.pod b/modules/database/src/std/rec/biRecord.dbd.pod index 157c33fe6..c62b291ad 100644 --- a/modules/database/src/std/rec/biRecord.dbd.pod +++ b/modules/database/src/std/rec/biRecord.dbd.pod @@ -61,8 +61,8 @@ this chapter for information on soft device support. If the record gets its values from hardware or uses the C device support, the device support routines place the value in the RVAL field. -(Since UNRELEASED) If the MASK field is non-zero, then this MASK is applied to RVAL. -The value of RVAL is then converted using the process described in the +(Since 7.0.8) If the MASK field is non-zero, then this MASK is applied to RVAL. +The value from RVAL is then converted using the process described in the next section. =fields INP, DTYP, ZNAM, ONAM, RVAL, VAL diff --git a/modules/database/src/std/rec/calcRecord.dbd.pod b/modules/database/src/std/rec/calcRecord.dbd.pod index 23893feeb..4619dd4e3 100644 --- a/modules/database/src/std/rec/calcRecord.dbd.pod +++ b/modules/database/src/std/rec/calcRecord.dbd.pod @@ -158,7 +158,7 @@ CEIL: Ceiling (unary) FLOOR: Floor (unary) =item * -FMOD: Floating point modulo (binary) Added in UNRELEASED +FMOD: Floating point modulo (binary) Added in 7.0.8 =item * LOG: Log base 10 (unary) diff --git a/modules/database/src/std/rec/calcoutRecord.dbd.pod b/modules/database/src/std/rec/calcoutRecord.dbd.pod index b62f57520..490aec9c9 100644 --- a/modules/database/src/std/rec/calcoutRecord.dbd.pod +++ b/modules/database/src/std/rec/calcoutRecord.dbd.pod @@ -184,7 +184,7 @@ CEIL: Ceiling (unary) FLOOR: Floor (unary) =item * -FMOD: Floating point modulo (binary) Added in UNRELEASED +FMOD: Floating point modulo (binary) Added in 7.0.8 =item * LOG: Log base 10 (unary) diff --git a/modules/database/src/std/rec/longoutRecord.dbd.pod b/modules/database/src/std/rec/longoutRecord.dbd.pod index 912573749..9fead68d4 100644 --- a/modules/database/src/std/rec/longoutRecord.dbd.pod +++ b/modules/database/src/std/rec/longoutRecord.dbd.pod @@ -85,7 +85,7 @@ for information on the format of hardware addresses and database links. =head4 Menu longoutOOPT -The OOPT field was added in EPICS UNRELEASED. +The OOPT field was added in EPICS 7.0.8. It determines the condition that causes the output link to be written to. It's a menu field that has six choices: @@ -119,7 +119,7 @@ VAL is non-zero and last value was zero. =head4 Changes in OUT field when OOPT = On Change -The OOCH field was added in EPICS UNRELEASED. +The OOCH field was added in EPICS 7.0.8. If OOCH is C (its default value) and the OOPT field is C, the record will write to the device support the first time the record gets diff --git a/modules/libcom/src/calc/postfix.h b/modules/libcom/src/calc/postfix.h index c9fdc1ee7..5d75a7ddf 100644 --- a/modules/libcom/src/calc/postfix.h +++ b/modules/libcom/src/calc/postfix.h @@ -222,7 +222,7 @@ extern "C" { * - n parameter minimum value: min(a, b, ...) * - Square root: sqr(a) or sqrt(a) * - Floating point modulo: fmod(num, den) - * \since The fmod() function was added in UNRELEASED + * \since The fmod() function was added in 7.0.8 * * -# ***Trigonometric Functions*** * Standard circular trigonometric functions, with angles expressed in radians: diff --git a/modules/libcom/src/error/errlog.h b/modules/libcom/src/error/errlog.h index 4aaf054ac..44a504812 100644 --- a/modules/libcom/src/error/errlog.h +++ b/modules/libcom/src/error/errlog.h @@ -180,8 +180,8 @@ LIBCOM_API void errlogAddListener(errlogListener listener, void *pPrivate); * \param listener Function pointer of type ::errlogListener * \param pPrivate This will be passed as the first argument of listener() * - * \since UNRELEASED Safe to call from a listener callback. - * \until UNRELEASED Self-removal from a listener callback caused corruption. + * \since 7.0.8 Safe to call from a listener callback. + * \until 7.0.8 Self-removal from a listener callback caused corruption. */ LIBCOM_API int errlogRemoveListeners(errlogListener listener, void *pPrivate); diff --git a/modules/libcom/src/iocsh/initHooks.h b/modules/libcom/src/iocsh/initHooks.h index a5ad93d3f..573817f6b 100644 --- a/modules/libcom/src/iocsh/initHooks.h +++ b/modules/libcom/src/iocsh/initHooks.h @@ -111,7 +111,7 @@ typedef enum { */ initHookAfterCloseLinks, /** \brief Scan tasks stopped. - * \since UNRELEASED Triggered during normal IOC shutdown + * \since 7.0.8 Triggered during normal IOC shutdown * \since 7.0.3.1 Added, triggered only by unittest code. */ initHookAfterStopScan, @@ -120,7 +120,7 @@ typedef enum { */ initHookAfterStopCallback, /** \brief CA links stopped. - * \since UNRELEASED Triggered during normal IOC shutdown + * \since 7.0.8 Triggered during normal IOC shutdown * \since 7.0.3.1 Added, triggered only by unittest code. */ initHookAfterStopLinks, @@ -136,12 +136,12 @@ typedef enum { /** \brief Called during testdbPrepare() * Use this hook to repeat actions each time an empty test database is initialized. - * \since UNRELEASED Added, triggered only by unittest code. + * \since 7.0.8 Added, triggered only by unittest code. */ initHookAfterPrepareDatabase, /** \brief Called during testdbCleanup() * Use this hook to perform cleanup each time before a test database is free()'d. - * \since UNRELEASED Added, triggered only by unittest code. + * \since 7.0.8 Added, triggered only by unittest code. */ initHookBeforeCleanupDatabase, diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h index 2c8da0998..90a534581 100644 --- a/modules/libcom/src/iocsh/iocsh.h +++ b/modules/libcom/src/iocsh/iocsh.h @@ -66,12 +66,16 @@ typedef enum { iocshArgPdbbase, iocshArgArgv, iocshArgPersistentString, - /** Equivalent to iocshArgString with a hint for tab completion as a record name. - * @since UNRELEASED + /** + * Equivalent to iocshArgString with a hint for tab completion that the + * argument is a record name. + * @since 7.0.8 */ iocshArgStringRecord, - /** Equivalent to iocshArgString with a hint for tab completion as a file system path. - * @since UNRELEASED + /** + * Equivalent to iocshArgString with a hint for tab completion that the + * argument is a file system path. + * @since 7.0.8 */ iocshArgStringPath, }iocshArgType; From fad830bd141561807383509578471d0627ba04ca Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 13 Dec 2023 14:48:03 -0600 Subject: [PATCH 46/66] Remove example sub-module --- modules/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/Makefile b/modules/Makefile index ae221dead..8ad33f0c0 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -34,9 +34,6 @@ pvDatabase_DEPEND_DIRS = pvAccess SUBMODULES += pva2pva pva2pva_DEPEND_DIRS = pvAccess -SUBMODULES += example -example_DEPEND_DIRS = pva2pva pvaClient - # Allow sites to add extra submodules -include Makefile.local From 477e36b1f01dc3d5c2196a738339b8e152fa8520 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 13 Dec 2023 17:22:30 -0600 Subject: [PATCH 47/66] Update submodules to tagged 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 cf483d664..96061ca1c 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit cf483d664df92440443526acc276bc823c34ff31 +Subproject commit 96061ca1cc6d0e101b0033635396a8e6b6add68c diff --git a/modules/pvData b/modules/pvData index dd74289ea..0ef8a3617 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit dd74289eaf646670d1f62e2c6bbadbd400d1f17a +Subproject commit 0ef8a361721bc4972743a9c9a0112f441ba36b0f diff --git a/modules/pvDatabase b/modules/pvDatabase index 1b787c514..e4cb8d239 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit 1b787c514961f860a246cb4dc849dfbb1a10eb5e +Subproject commit e4cb8d23973723d8d943bd86bc0213da2bd53eff diff --git a/modules/pva2pva b/modules/pva2pva index 3b9990e36..3a08da445 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 3b9990e3650fca2673eebfb83645193ac0e5297d +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 448fde06711278e634aa54f046987cf0b4a0dbe9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 13 Dec 2023 17:46:02 -0600 Subject: [PATCH 48/66] Set release version numbers --- configure/CONFIG_BASE_VERSION | 6 +++--- configure/CONFIG_CA_VERSION | 2 +- configure/CONFIG_DATABASE_VERSION | 6 +++--- configure/CONFIG_LIBCOM_VERSION | 6 +++--- documentation/RELEASE_NOTES.md | 3 +-- 5 files changed, 11 insertions(+), 12 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 12120cddb..9843a80dc 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 = 7 +EPICS_MODIFICATION = 8 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included in the official EPICS version number if zero -EPICS_PATCH_LEVEL = 1 +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 1fe4f1c25..a87d87060 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -6,7 +6,7 @@ EPICS_CA_MAINTENANCE_VERSION = 3 # 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 8b4002ae6..9841da4cd 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 = 22 -EPICS_DATABASE_MAINTENANCE_VERSION = 1 +EPICS_DATABASE_MINOR_VERSION = 23 +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 898df2c67..7eb855afe 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 = 22 -EPICS_LIBCOM_MAINTENANCE_VERSION = 1 +EPICS_LIBCOM_MINOR_VERSION = 23 +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 2fe399ff3..6ce057ac1 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -18,9 +18,8 @@ should also be read to understand what has changed since earlier releases: - [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html) - [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md) -**This version of EPICS has not been released yet.** -## Changes made on the 7.0 branch since 7.0.7 +## EPICS Release 7.0.8 ### bi "Raw Soft Channel" use MASK From 8998341588112e317f4f8cf9ae3930e958b323e5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 15 Dec 2023 13:03:25 -0600 Subject: [PATCH 49/66] Update version numbers and submodules after release --- configure/CONFIG_BASE_VERSION | 4 ++-- configure/CONFIG_CA_VERSION | 4 ++-- configure/CONFIG_DATABASE_VERSION | 4 ++-- configure/CONFIG_LIBCOM_VERSION | 4 ++-- documentation/RELEASE_NOTES.md | 6 ++++++ modules/normativeTypes | 2 +- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 11 files changed, 20 insertions(+), 14 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 9843a80dc..7972433a1 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -52,11 +52,11 @@ EPICS_MODIFICATION = 8 # EPICS_PATCH_LEVEL must be a number (win32 resource file requirement) # Not included in the official EPICS version number if zero -EPICS_PATCH_LEVEL = 0 +EPICS_PATCH_LEVEL = 1 # Immediately after an official release the EPICS_PATCH_LEVEL is incremented # and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions) -EPICS_DEV_SNAPSHOT= +EPICS_DEV_SNAPSHOT=-DEV # No changes should be needed below here diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index a87d87060..2cff78816 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 = 3 +EPICS_CA_MAINTENANCE_VERSION = 4 # 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 9841da4cd..8815d2d1e 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -2,11 +2,11 @@ EPICS_DATABASE_MAJOR_VERSION = 3 EPICS_DATABASE_MINOR_VERSION = 23 -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 7eb855afe..4aab82a17 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -2,11 +2,11 @@ EPICS_LIBCOM_MAJOR_VERSION = 3 EPICS_LIBCOM_MINOR_VERSION = 23 -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 6ce057ac1..73a50594d 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -18,6 +18,12 @@ should also be read to understand what has changed since earlier releases: - [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html) - [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md) +**This version of EPICS has not been released yet.** + +## Changes made on the 7.0 branch since 7.0.8 + + +----- ## EPICS Release 7.0.8 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..7746ea3c6 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 96061ca1cc6d0e101b0033635396a8e6b6add68c +Subproject commit 7746ea3c6c366f7bf3a949613a77c9e4c7f7f2dd diff --git a/modules/pvData b/modules/pvData index 0ef8a3617..7300e6b0b 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 0ef8a361721bc4972743a9c9a0112f441ba36b0f +Subproject commit 7300e6b0bd560c0ea2355c64ea3a88c259f90fe2 diff --git a/modules/pvDatabase b/modules/pvDatabase index e4cb8d239..d18e0c913 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit e4cb8d23973723d8d943bd86bc0213da2bd53eff +Subproject commit d18e0c913a8d5a8d42cbf2d5ec28ffd362897809 diff --git a/modules/pva2pva b/modules/pva2pva index 3a08da445..949b3f63c 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 3a08da445b46e2e7029406d24425cdd3dfd7da24 +Subproject commit 949b3f63c2387bb92c1c22ca2f80f8d320805117 diff --git a/modules/pvaClient b/modules/pvaClient index a34876e36..8ed07fef9 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit a34876e36a56c9de9b172d6a83a9439bb330783d +Subproject commit 8ed07fef96e41d35d47ab61276e29eb1a81e7fec From 20f32068c339b135ffff7c76fa58efb6e09a3a79 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 7 Dec 2023 11:47:47 -0800 Subject: [PATCH 50/66] gha add workflow_dispatch --- .github/workflows/ci-scripts-build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index e8dd9c85b..65384d23b 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -29,6 +29,7 @@ on: - '.gitattributes' - '**/*.html' - '**/*.md' + workflow_dispatch: env: SETUP_PATH: .ci-local:.ci From e88a186fc38c045e4abcbc3c3591a61aa6b6eae9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 24 Nov 2023 18:38:06 -0800 Subject: [PATCH 51/66] make link::flags bit field unsigned --- modules/database/src/ioc/dbStatic/link.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/src/ioc/dbStatic/link.h b/modules/database/src/ioc/dbStatic/link.h index a7edebf57..82255bc91 100644 --- a/modules/database/src/ioc/dbStatic/link.h +++ b/modules/database/src/ioc/dbStatic/link.h @@ -193,7 +193,7 @@ struct lset; struct link { struct dbCommon *precord; /* Pointer to record owning link */ short type; - short flags; + unsigned flags; struct lset *lset; char *text; /* Raw link text */ union value value; From ea8247586f14f2850cde6cf91d40880906b1daff Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 13 Jun 2023 12:18:55 -0700 Subject: [PATCH 52/66] adjustToWorstCaseAlignment() simplify Add some STATIC_ASSERT to check assumptions. Only in-tree use is freeListLib to ensure chunks in a malloc()'d block are aligned. --- modules/libcom/src/misc/adjustment.c | 45 ++++++++++------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/modules/libcom/src/misc/adjustment.c b/modules/libcom/src/misc/adjustment.c index a5803c4e2..525394277 100644 --- a/modules/libcom/src/misc/adjustment.c +++ b/modules/libcom/src/misc/adjustment.c @@ -15,40 +15,25 @@ #include #include -/* Up to now epicsShareThings have been declared as imports - * (Appropriate for other stuff) - * After setting the following they will be declared as exports - * (Appropriate for what we implement) - */ +#include #include "adjustment.h" -LIBCOM_API size_t adjustToWorstCaseAlignment(size_t size) +size_t adjustToWorstCaseAlignment(size_t size) { - int align_size, adjust; - struct test_long_word { char c; long lw; }; - struct test_double { char c; double d; }; - struct test_ptr { char c; void *p; }; - int test_long_size = sizeof(struct test_long_word) - sizeof(long); - int test_double_size = sizeof(struct test_double) - sizeof(double); - int test_ptr_size = sizeof(struct test_ptr) - sizeof(void *); - size_t adjusted_size = size; + union aline { + /* largest primative types (so far...) */ + double dval; + size_t uval; + char *ptr; + }; - /* - * Use Jeff's alignment tests to determine worst case of long, - * double or pointer alignment requirements. - */ - align_size = test_long_size > test_ptr_size ? - test_long_size : test_ptr_size; + /* assert that alignment size is a power of 2 */ + STATIC_ASSERT((sizeof(union aline) & (sizeof(union aline)-1))==0); - align_size = align_size > test_double_size ? - align_size : test_double_size; + /* round up to aligment size */ + size--; + size |= sizeof(union aline)-1; + size++; - /* - * Increase the size to fit worst case alignment if not already - * properly aligned. - */ - adjust = align_size - size%align_size; - if (adjust != align_size) adjusted_size += adjust; - - return (adjusted_size); + return size; } From 823386573f3b9e3630eb79d3943c1d10a7034eb2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 13 Jun 2023 12:21:06 -0700 Subject: [PATCH 53/66] ipAddrToAsciiGlobal::run() keep scratch buffer as local --- modules/libcom/src/misc/ipAddrToAsciiAsynchronous.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/misc/ipAddrToAsciiAsynchronous.cpp b/modules/libcom/src/misc/ipAddrToAsciiAsynchronous.cpp index b5e863d59..43a7537b9 100644 --- a/modules/libcom/src/misc/ipAddrToAsciiAsynchronous.cpp +++ b/modules/libcom/src/misc/ipAddrToAsciiAsynchronous.cpp @@ -17,6 +17,7 @@ #include #include #include +#include //#define EPICS_FREELIST_DEBUG #define EPICS_PRIVATE_API @@ -82,7 +83,6 @@ struct ipAddrToAsciiGlobal : public epicsThreadRunable { virtual void run (); - char nameTmp [1024]; tsFreeList < ipAddrToAsciiTransactionPrivate, 0x80 > transactionFreeList; @@ -297,6 +297,8 @@ ipAddrToAsciiTransaction & ipAddrToAsciiEnginePrivate::createTransaction () void ipAddrToAsciiGlobal::run () { + std::vector nameTmp(1024); + epicsGuard < epicsMutex > guard ( this->mutex ); while ( ! this->exitFlag ) { { @@ -313,14 +315,13 @@ void ipAddrToAsciiGlobal::run () if ( this->exitFlag ) { - sockAddrToDottedIP ( & addr.sa, this->nameTmp, - sizeof ( this->nameTmp ) ); + sockAddrToDottedIP ( & addr.sa, &nameTmp[0], nameTmp.size() ); } else { epicsGuardRelease < epicsMutex > unguard ( guard ); // depending on DNS configuration, this could take a very long time // so we release the lock - sockAddrToA ( &addr.sa, this->nameTmp, sizeof ( this->nameTmp ) ); + sockAddrToA ( &addr.sa, &nameTmp[0], nameTmp.size() ); } // the ipAddrToAsciiTransactionPrivate destructor is allowed to @@ -339,7 +340,7 @@ void ipAddrToAsciiGlobal::run () { epicsGuardRelease < epicsMutex > unguard ( guard ); // don't call callback with lock applied - pCur->pCB->transactionComplete ( this->nameTmp ); + pCur->pCB->transactionComplete ( &nameTmp[0] ); } this->callbackInProgress = false; From fe4a32e425ab0a5b8fd080dae1a5f2f26a591714 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 13 Jun 2023 12:25:07 -0700 Subject: [PATCH 54/66] default/epicsMessageQueue: avoid volatile flag Only one place where eventSent was accessed without locking. Move this load earlier. --- modules/libcom/src/osi/os/default/osdMessageQueue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/osi/os/default/osdMessageQueue.cpp b/modules/libcom/src/osi/os/default/osdMessageQueue.cpp index dfbe9886c..b68787fdd 100644 --- a/modules/libcom/src/osi/os/default/osdMessageQueue.cpp +++ b/modules/libcom/src/osi/os/default/osdMessageQueue.cpp @@ -40,7 +40,7 @@ struct threadNode { struct eventNode *evp; void *buf; unsigned int size; - volatile bool eventSent; + bool eventSent; }; /* @@ -366,9 +366,10 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size, freeEventNode(pmsg, threadNode.evp, status); + bool wasSent = threadNode.eventSent; epicsMutexUnlock(pmsg->mutex); - if (threadNode.eventSent && (threadNode.size <= size)) + if (wasSent && (threadNode.size <= size)) return threadNode.size; return -1; } From a7a56912ebb6c728316465e079397d3b5cc65d88 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 13 Jun 2023 15:57:33 -0700 Subject: [PATCH 55/66] default/epicsMessageQueue: initialize threadNode --- modules/libcom/src/osi/os/default/osdMessageQueue.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/libcom/src/osi/os/default/osdMessageQueue.cpp b/modules/libcom/src/osi/os/default/osdMessageQueue.cpp index b68787fdd..89bc35562 100644 --- a/modules/libcom/src/osi/os/default/osdMessageQueue.cpp +++ b/modules/libcom/src/osi/os/default/osdMessageQueue.cpp @@ -41,6 +41,15 @@ struct threadNode { void *buf; unsigned int size; bool eventSent; + inline + threadNode() + :evp(NULL) + ,buf(NULL) + ,size(0u) + ,eventSent(false) + { + memset(&link, 0, sizeof(link)); + } }; /* From 403e2033257fbd440f6eb6eb25941fc06097a559 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 13 Jun 2023 12:17:38 -0700 Subject: [PATCH 56/66] quieting clang-tidy, use unsigned places where we shouldn't be negative anyway --- modules/libcom/src/as/asLibRoutines.c | 4 ++-- modules/libcom/src/gpHash/gpHashLib.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index 59dd80bda..571471e2a 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -366,7 +366,7 @@ long epicsStdCall asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt, { ASGMEMBER *pasgmember = asMemberPvt; ASGCLIENT *pasgclient; - int len, i; + size_t len, i; long status; if(!asActive) return(S_asLib_asNotActive); @@ -394,7 +394,7 @@ long epicsStdCall asChangeClient( { ASGCLIENT *pasgclient = asClientPvt; long status; - int len, i; + size_t len, i; if(!asActive) return(S_asLib_asNotActive); if(!pasgclient) return(S_asLib_badClient); diff --git a/modules/libcom/src/gpHash/gpHashLib.c b/modules/libcom/src/gpHash/gpHashLib.c index 3ed7de4f1..c4991a873 100644 --- a/modules/libcom/src/gpHash/gpHashLib.c +++ b/modules/libcom/src/gpHash/gpHashLib.c @@ -63,7 +63,7 @@ GPHENTRY * epicsStdCall gphFindParse(gphPvt *pgphPvt, const char *name, size_t l ELLLIST **paplist; ELLLIST *gphlist; GPHENTRY *pgphNode; - int hash; + unsigned hash; if (pgphPvt == NULL) return NULL; paplist = pgphPvt->paplist; @@ -99,7 +99,7 @@ GPHENTRY * epicsStdCall gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid) ELLLIST **paplist; ELLLIST *plist; GPHENTRY *pgphNode; - int hash; + unsigned hash; if (pgphPvt == NULL) return NULL; paplist = pgphPvt->paplist; @@ -144,7 +144,7 @@ void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid) ELLLIST **paplist; ELLLIST *plist = NULL; GPHENTRY *pgphNode; - int hash; + unsigned hash; if (pgphPvt == NULL) return; paplist = pgphPvt->paplist; From 87acb98d1e3d7efe0bb788d1dfe24a107dfa3200 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 20 Aug 2022 10:03:42 -0700 Subject: [PATCH 57/66] ca: remove hostname length limit when parsing address lists --- modules/ca/src/client/iocinf.cpp | 101 +++++++++++++------------------ 1 file changed, 42 insertions(+), 59 deletions(-) diff --git a/modules/ca/src/client/iocinf.cpp b/modules/ca/src/client/iocinf.cpp index c760a0d34..8bd42f108 100644 --- a/modules/ca/src/client/iocinf.cpp +++ b/modules/ca/src/client/iocinf.cpp @@ -21,6 +21,9 @@ #define epicsAssertAuthor "Jeff Hill johill@lanl.gov" +#include +#include + #include #include #include @@ -28,6 +31,7 @@ #include "envDefs.h" #include "epicsAssert.h" +#include "epicsString.h" #include "epicsStdioRedirect.h" #include "errlog.h" #include "osiWireFormat.h" @@ -35,39 +39,6 @@ #include "addrList.h" #include "iocinf.h" -/* - * getToken() - */ -static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze ) -{ - bool tokenFound = false; - const char *pToken; - unsigned i; - - pToken = *ppString; - while ( isspace (*pToken) && *pToken ){ - pToken++; - } - - for ( i=0u; iname); - fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken); - continue; + try { + std::vector scratch(pStr, pStr+strlen(pStr)+1); // copy chars and trailing nil + + char *save = NULL; + for(const char *pToken = epicsStrtok_r(&scratch[0], " \t\n\r", &save); + pToken; + pToken = epicsStrtok_r(NULL, " \t\n\r", &save)) + { + if(!pToken[0]) { + continue; + } + + status = aToIPAddr ( pToken, port, &addr ); + if (status<0) { + fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name); + fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken); + continue; + } + + if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) { + continue; + } + + pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode)); + if (pNewNode==NULL) { + fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n"); + break; + } + + pNewNode->addr.ia = addr; + + /* + * LOCK applied externally + */ + ellAdd (pList, &pNewNode->node); + ret = 0; /* success if anything is added to the list */ } - - if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) { - continue; - } - - pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode)); - if (pNewNode==NULL) { - fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n"); - break; - } - - pNewNode->addr.ia = addr; - - /* - * LOCK applied externally - */ - ellAdd (pList, &pNewNode->node); - ret = 0; /* success if anything is added to the list */ + } catch(std::exception&) { // only bad_alloc currently possible + ret = -1; } return ret; From c75b9ad0be663326a4c55ce13ba68e1d2d77c3db Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 13 Nov 2021 10:19:14 -0800 Subject: [PATCH 58/66] add dbRecordNode::order Keep track of parse order of record instances. --- modules/database/src/ioc/dbStatic/dbBase.h | 8 ++++++++ modules/database/src/ioc/dbStatic/dbStaticLib.c | 2 ++ 2 files changed, 10 insertions(+) diff --git a/modules/database/src/ioc/dbStatic/dbBase.h b/modules/database/src/ioc/dbStatic/dbBase.h index 35ca0a638..f0a954b50 100644 --- a/modules/database/src/ioc/dbStatic/dbBase.h +++ b/modules/database/src/ioc/dbStatic/dbBase.h @@ -118,6 +118,10 @@ typedef struct dbRecordNode { char *recordname; ELLLIST infoList; /*LIST head of info nodes*/ int flags; + /** Parse order of this record() + * @since UNRELEASED + */ + unsigned order; struct dbRecordNode *aliasedRecnode; /* NULL unless flags|DBRN_FLAGS_ISALIAS */ }dbRecordNode; @@ -184,5 +188,9 @@ typedef struct dbBase { struct gphPvt *pgpHash; short ignoreMissingMenus; short loadCdefs; + /** Total number of records. + * @since UNRELEASED + */ + unsigned no_records; }dbBase; #endif diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index eb008fb87..fda3cbf51 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -1445,6 +1445,7 @@ long dbCreateRecord(DBENTRY *pdbentry,const char *precordName) pdbentry->precnode = pNewRecNode; ppvd = dbPvdAdd(pdbentry->pdbbase,precordType,pNewRecNode); if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);} + pNewRecNode->order = pdbentry->pdbbase->no_records++; return(0); } @@ -1686,6 +1687,7 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias) } ellAdd(&precordType->recList, &pnewnode->node); + pnewnode->order = pdbentry->pdbbase->no_records++; precordType->no_aliases++; return 0; From 07cbf00187bca98d74ad1d13094b82acb5912c0e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 27 Oct 2022 10:41:28 -0400 Subject: [PATCH 59/66] posix: warn on epicsSocketCreate() without osiSockAttach() --- modules/libcom/src/osi/os/posix/osdSock.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/modules/libcom/src/osi/os/posix/osdSock.c b/modules/libcom/src/osi/os/posix/osdSock.c index f773b3357..082b7fefa 100644 --- a/modules/libcom/src/osi/os/posix/osdSock.c +++ b/modules/libcom/src/osi/os/posix/osdSock.c @@ -27,6 +27,7 @@ #include "osiSock.h" #include "epicsAssert.h" #include "errlog.h" +#include "epicsAtomic.h" /* Linux and *BSD (at least) specific way to atomically set O_CLOEXEC. * RTEMS 5.1 provides SOCK_CLOEXEC, but doesn't implement accept4() @@ -60,19 +61,18 @@ static void unlockInfo (void) epicsMutexUnlock (infoMutex); } -/* - * NOOP - */ + +static size_t nAttached; + int osiSockAttach() { + epicsAtomicIncrSizeT(&nAttached); return 1; } -/* - * NOOP - */ void osiSockRelease() { + epicsAtomicDecrSizeT(&nAttached); } /* @@ -83,6 +83,11 @@ void osiSockRelease() LIBCOM_API SOCKET epicsStdCall epicsSocketCreate ( int domain, int type, int protocol ) { + static unsigned char warnAttached; + if(!epicsAtomicGetSizeT(&nAttached) && !warnAttached) { + warnAttached = 1; + errlogPrintf(ERL_WARNING ": epicsSocketCreate() without osiSockAttach() is not portable\n"); + } SOCKET sock = socket ( domain, type | SOCK_CLOEXEC, protocol ); if ( sock < 0 ) { sock = INVALID_SOCKET; From a6977ae731c16371ffc2285927898a870e5dad90 Mon Sep 17 00:00:00 2001 From: Simon Rose Date: Mon, 12 Feb 2024 10:11:09 +0100 Subject: [PATCH 60/66] Fix issue where VSCode makefile extension can delete files The problem is that VSCode's make extension, in order to determine some information about the project, runs ``` make --dry-run --always-make ``` which despite its name will actually try to remake the configure/* files. Running `installEpics.pl` on these will delete them first, then try copy them, resulting in an error. --- configure/RULES_BUILD | 4 ++-- src/tools/installEpics.pl | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 869fba17e..cbfaae99d 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -532,11 +532,11 @@ endif # LOADABLE_SHRLIB_SUFFIX ifneq ($(INSTALL_CONFIGS),) $(INSTALL_CONFIG)/%: % $(ECHO) "Installing config file $@" - @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) + @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D)) $(INSTALL_CONFIG)/%: ../% $(ECHO) "Installing config file $@" - @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D) + @$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D)) endif $(INSTALL_INCLUDE)/%: $(COMMON_DIR)/% diff --git a/src/tools/installEpics.pl b/src/tools/installEpics.pl index 6cd06e801..c41cc6f91 100644 --- a/src/tools/installEpics.pl +++ b/src/tools/installEpics.pl @@ -57,6 +57,9 @@ foreach my $source (@ARGV) { my $temp = "$install_dir/TEMP.$name.$$"; my $target = "$install_dir/$name"; + # Don't try to install the file if it already exists + next if $source eq $target; + if (-f $target) { next if -M $target < -M $source and -C $target < -C $source; # Remove old target, making sure it is deletable first From 4383cf291e13644b61c9f1a795f894c20f6923e6 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 16 Feb 2024 16:54:15 +0100 Subject: [PATCH 61/66] allow macros with defaults in dbLoadRecords without substitutions --- .../database/src/ioc/dbStatic/dbLexRoutines.c | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 7acaaa292..cd3c6ff0d 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -247,23 +247,23 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp, } my_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char)); freeListInitPvt(&freeListPvt,sizeof(tempListNode),100); - if(substitutions) { - if(macCreateHandle(&macHandle,NULL)) { - epicsPrintf("macCreateHandle error\n"); - status = -1; - goto cleanup; - } - macParseDefns(macHandle,(char *)substitutions,&macPairs); - if(macPairs ==NULL) { - macDeleteHandle(macHandle); - macHandle = NULL; - } else { - macInstallMacros(macHandle,macPairs); - free((void *)macPairs); - mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char)); - } - macSuppressWarning(macHandle,dbQuietMacroWarnings); + if (substitutions == NULL) + substitutions = ""; + if(macCreateHandle(&macHandle,NULL)) { + epicsPrintf("macCreateHandle error\n"); + status = -1; + goto cleanup; } + macParseDefns(macHandle,substitutions,&macPairs); + if(macPairs == NULL) { + macDeleteHandle(macHandle); + macHandle = NULL; + } else { + macInstallMacros(macHandle,macPairs); + free(macPairs); + mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char)); + } + macSuppressWarning(macHandle,dbQuietMacroWarnings); pinputFile = dbCalloc(1,sizeof(inputFile)); if (filename) { pinputFile->filename = macEnvExpand(filename); From 4720b61c1f3c9db769f0e416250d43aaf3a4120e Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sun, 11 Feb 2024 21:07:08 +0000 Subject: [PATCH 62/66] Move call to setThreadName() The call to setThreadName() is moved to avoid a race condition that can happen with very short lived processes. If the process terminates very quickly e.g. is a google test runner or the msi.exe command called from a Makefile during a build, then very occasionally a crash can occur during process termination if setThreadName() when called from the newly created thread. This looks to be becauae the DLL it is trying to call gets unloaded between it getting a handle to the DLL and making the call. Moving the setThreadName() call to the creating thread avoids this problem. The issue was only ever seen with statically linked epics executables, I am unsure if the way a DLL based epics program unloads might avoid this, or just make it less likely but still possible. As mentioned above, the issue will only ever occur to threads that are created during process termination and so would not affect running IOCs --- modules/libcom/src/osi/os/WIN32/osdThread.c | 3 +-- modules/libcom/src/osi/os/WIN32/osdTime.cpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 5e9eeb435..d055b9bd9 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -500,8 +500,6 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) BOOL success; if ( pGbl ) { - setThreadName ( pParm->id, pParm->pName ); - success = FlsSetValue ( pGbl->flsIndexThreadLibraryEPICS, pParm ); if ( success ) { osdThreadHooksRun ( ( epicsThreadId ) pParm ); @@ -659,6 +657,7 @@ epicsThreadId epicsThreadCreateOpt ( pParmWIN32->id = ( DWORD ) threadId ; } + setThreadName ( pParmWIN32->id, pParmWIN32->pName ); osdPriority = epicsThreadGetOsdPriorityValue (opts->priority); bstat = SetThreadPriority ( pParmWIN32->handle, osdPriority ); if (!bstat) { diff --git a/modules/libcom/src/osi/os/WIN32/osdTime.cpp b/modules/libcom/src/osi/os/WIN32/osdTime.cpp index e2c3efbfe..0916b6c9f 100644 --- a/modules/libcom/src/osi/os/WIN32/osdTime.cpp +++ b/modules/libcom/src/osi/os/WIN32/osdTime.cpp @@ -215,6 +215,7 @@ void currentTime :: startPLL () CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, & this->threadId ); assert ( this->threadHandle ); + setThreadName ( this->threadId, "EPICS Time PLL" ); BOOL bstat = SetThreadPriority ( this->threadHandle, THREAD_PRIORITY_HIGHEST ); assert ( bstat ); @@ -496,7 +497,6 @@ static unsigned __stdcall _pllThreadEntry ( void * pCurrentTimeIn ) { currentTime * pCT = reinterpret_cast < currentTime * > ( pCurrentTimeIn ); - setThreadName ( pCT->threadId, "EPICS Time PLL" ); while ( ! pCT->threadShutdownCmd ) { Sleep ( currentTime :: pllDelay * 1000 /* mS */ ); pCT->updatePLL (); From cb49bd0133d665aafc91521538e89103044336f7 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 1 Mar 2024 18:00:40 +0100 Subject: [PATCH 63/66] Update ci-scripts to 3.4.1 Builds on AppVeyor (VS2019) started to fail because of the Python version/distutils --- .ci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci b/.ci index 130e88b70..20f8e0539 160000 --- a/.ci +++ b/.ci @@ -1 +1 @@ -Subproject commit 130e88b7095812da93e423c602651e30f39da11a +Subproject commit 20f8e053931fdef8a9413cc6229286c5d9ed152f From 5dfc6caf3c898b213c8458f4766152a1b5a3e477 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Thu, 1 Feb 2024 00:51:30 +0000 Subject: [PATCH 64/66] Accept should return SOCKET rather than int --- modules/libcom/src/log/iocLogServer.c | 2 +- modules/libcom/src/osi/os/WIN32/osdSock.c | 4 ++-- modules/libcom/src/osi/os/posix/osdSock.c | 4 ++-- modules/libcom/src/osi/os/vxWorks/osdSock.c | 4 ++-- modules/libcom/src/osi/osiSock.h | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/libcom/src/log/iocLogServer.c b/modules/libcom/src/log/iocLogServer.c index 81288d481..890176fb0 100644 --- a/modules/libcom/src/log/iocLogServer.c +++ b/modules/libcom/src/log/iocLogServer.c @@ -43,7 +43,7 @@ static char ioc_log_file_command[256]; struct iocLogClient { - int insock; + SOCKET insock; struct ioc_log_server *pserver; size_t nChar; char recvbuf[1024]; diff --git a/modules/libcom/src/osi/os/WIN32/osdSock.c b/modules/libcom/src/osi/os/WIN32/osdSock.c index 8ca80ffb9..3c8dc6ebf 100644 --- a/modules/libcom/src/osi/os/WIN32/osdSock.c +++ b/modules/libcom/src/osi/os/WIN32/osdSock.c @@ -119,8 +119,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate ( return socket ( domain, type, protocol ); } -LIBCOM_API int epicsStdCall epicsSocketAccept ( - int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ) +LIBCOM_API SOCKET epicsStdCall epicsSocketAccept ( + SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ) { return accept ( sock, pAddr, addrlen ); } diff --git a/modules/libcom/src/osi/os/posix/osdSock.c b/modules/libcom/src/osi/os/posix/osdSock.c index 082b7fefa..0d873e628 100644 --- a/modules/libcom/src/osi/os/posix/osdSock.c +++ b/modules/libcom/src/osi/os/posix/osdSock.c @@ -124,8 +124,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate ( return sock; } -LIBCOM_API int epicsStdCall epicsSocketAccept ( - int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ) +LIBCOM_API SOCKET epicsStdCall epicsSocketAccept ( + SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ) { #ifndef HAVE_SOCK_CLOEXEC int newSock = accept ( sock, pAddr, addrlen ); diff --git a/modules/libcom/src/osi/os/vxWorks/osdSock.c b/modules/libcom/src/osi/os/vxWorks/osdSock.c index 962612ca9..3f272c359 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdSock.c +++ b/modules/libcom/src/osi/os/vxWorks/osdSock.c @@ -44,8 +44,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate ( return sock; } -LIBCOM_API int epicsStdCall epicsSocketAccept ( - int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ) +LIBCOM_API SOCKET epicsStdCall epicsSocketAccept ( + SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ) { int newSock = accept ( sock, pAddr, addrlen ); if ( newSock < 0 ) { diff --git a/modules/libcom/src/osi/osiSock.h b/modules/libcom/src/osi/osiSock.h index 59332a04b..e1abb23db 100644 --- a/modules/libcom/src/osi/osiSock.h +++ b/modules/libcom/src/osi/osiSock.h @@ -63,8 +63,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate ( * peer address. * \return A new socket used for communicating with the peer just accepted, or -1 on error. */ -LIBCOM_API int epicsStdCall epicsSocketAccept ( - int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ); +LIBCOM_API SOCKET epicsStdCall epicsSocketAccept ( + SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen ); /*! * \brief Close and free resources held by a SOCKET object. * From cb1571783b4793cb9c545e5736659ee5ed7d03bb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 2 Apr 2024 08:35:25 -0700 Subject: [PATCH 65/66] link.h wrong type Change to unsigned incorrectly increased size. e88a186fc38c045e4abcbc3c3591a61aa6b6eae9 --- modules/database/src/ioc/dbStatic/link.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/src/ioc/dbStatic/link.h b/modules/database/src/ioc/dbStatic/link.h index 82255bc91..6488e8caa 100644 --- a/modules/database/src/ioc/dbStatic/link.h +++ b/modules/database/src/ioc/dbStatic/link.h @@ -193,7 +193,7 @@ struct lset; struct link { struct dbCommon *precord; /* Pointer to record owning link */ short type; - unsigned flags; + unsigned short flags; struct lset *lset; char *text; /* Raw link text */ union value value; From 1a9dc993c18fb9bfacb2ef7d0b42c30ba52c6154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89rico=20Nogueira?= Date: Mon, 29 Apr 2024 14:04:13 -0300 Subject: [PATCH 66/66] Fix gmtime messages in epicsTimeZoneTest. --- modules/libcom/test/epicsTimeZoneTest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/libcom/test/epicsTimeZoneTest.c b/modules/libcom/test/epicsTimeZoneTest.c index 4067c3f7d..f10688765 100644 --- a/modules/libcom/test/epicsTimeZoneTest.c +++ b/modules/libcom/test/epicsTimeZoneTest.c @@ -60,11 +60,11 @@ void test_gmtime(time_t T, int sec, int min, int hour, struct tm B; testDiag("test_gmtime(%ld, ...)", (long)T); if(epicsTime_gmtime(&T, &B)!=epicsTimeOK) { - testFail("epicsTime_localtime() error"); - testSkip(9, "epicsTime_localtime() failed"); + testFail("epicsTime_gmtime() error"); + testSkip(9, "epicsTime_gmtime() failed"); } else { B.tm_year += 1900; /* for readability */ - testPass("epicsTime_localtime() success"); + testPass("epicsTime_gmtime() success"); #define TEST(FLD) testOk(B.tm_##FLD==FLD, "%s %d==%d", #FLD, B.tm_##FLD, FLD) TEST(sec); TEST(min);