From ca800fa57dcfa76d03666571ee6cdaa75ec55e19 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 4 Apr 2018 11:01:45 -0700 Subject: [PATCH 001/281] libCom: add epicsThreadCreateOpt() Variant of epicsThreadCreate() which accepts optional arguments via a structure to allow for compatible addition of new arguments. --- modules/libcom/src/osi/epicsThread.cpp | 11 +++++++ modules/libcom/src/osi/epicsThread.h | 16 +++++++++ modules/libcom/src/osi/os/RTEMS/osdThread.c | 19 ++++++++--- modules/libcom/src/osi/os/WIN32/osdThread.c | 21 +++++++++--- modules/libcom/src/osi/os/posix/osdThread.c | 33 ++++++++++++++----- modules/libcom/src/osi/os/vxWorks/osdThread.c | 24 ++++++++++---- 6 files changed, 100 insertions(+), 24 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 892d73de0..372806edb 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -31,6 +31,17 @@ using namespace std; +epicsThreadId epicsShareAPI epicsThreadCreate ( + const char * name, unsigned int priority, unsigned int stackSize, + EPICSTHREADFUNC funptr,void * parm ) +{ + epicsThreadOpts opts; + opts.priority = priority; + opts.stackSize = stackSize; + + return epicsThreadCreateOpt(name, funptr, parm, &opts); +} + epicsThreadRunable::~epicsThreadRunable () {} void epicsThreadRunable::run () {} void epicsThreadRunable::show ( unsigned int ) const {} diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index 84b2c4788..d0879a8eb 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -65,6 +65,22 @@ epicsShareFunc void epicsThreadRealtimeLock(void); epicsShareFunc void epicsShareAPI epicsThreadExitMain(void); +typedef struct epicsThreadOpts { + /** Thread priority in OSI range (cf. epicsThreadPriority*) */ + unsigned int priority; + /** Thread stack size, as returned by epicsThreadGetStackSize(). + * + * @warning Do not pass enum epicsThreadStackSizeClass directly! + */ + unsigned int stackSize; +} epicsThreadOpts; + +epicsShareFunc void epicsThreadOptsDefaults(epicsThreadOpts *opts); + +epicsShareFunc epicsThreadId epicsThreadCreateOpt ( + const char * name, + EPICSTHREADFUNC funptr, void * parm, + const epicsThreadOpts *opts ); epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ); diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index 769e95820..7b478df65 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -148,6 +148,13 @@ epicsThreadGetStackSize (epicsThreadStackSizeClass size) return stackSize; } +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 5000}; + +void epicsThreadOptsDefaults(epicsThreadOpts *opts) +{ + *opts = opts_default; +} + /* * Ensure integrity of task variable list */ @@ -263,13 +270,17 @@ void epicsThreadRealtimeLock(void) * Create and start a new thread */ epicsThreadId -epicsThreadCreate (const char *name, - unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm) +epicsThreadCreateOpt ( + const char * name, + EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { rtems_id tid; rtems_status_code sc; char c[4]; + unsigned stackSize; + + if(!opts) opts = &opts_default; + stackSize = opts->stackSize; if (!initialized) epicsThreadInit(); if (stackSize < RTEMS_MINIMUM_STACK_SIZE) { @@ -279,7 +290,7 @@ epicsThreadCreate (const char *name, } strncpy (c, name, sizeof c); sc = rtems_task_create (rtems_build_name (c[0], c[1], c[2], c[3]), - epicsThreadGetOssPriorityValue (priority), + epicsThreadGetOssPriorityValue (opts->priority), stackSize, RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), RTEMS_FLOATING_POINT|RTEMS_LOCAL, diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 8cdb4a3f4..f78c7c0f4 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -464,6 +464,13 @@ epicsShareFunc unsigned int epicsShareAPI return stackSizeTable[stackSizeClass]; } +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1)}; + +void epicsThreadOptsDefaults(epicsThreadOpts *opts) +{ + *opts = opts_default; +} + void epicsThreadCleanupWIN32 () { win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); @@ -579,8 +586,10 @@ static win32ThreadParam * epicsThreadImplicitCreate ( void ) /* * epicsThreadCreate () */ -epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, - unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC pFunc,void *pParm) +epicsThreadId epicsThreadCreateOpt ( + const char * pName, + EPICSTHREADFUNC pFunc, void * pParm, + const epicsThreadOpts *opts ) { win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); win32ThreadParam * pParmWIN32; @@ -592,18 +601,20 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, return NULL; } + if(!opts) opts = &opts_default; + pParmWIN32 = epicsThreadParmCreate ( pName ); if ( pParmWIN32 == 0 ) { return ( epicsThreadId ) pParmWIN32; } pParmWIN32->funptr = pFunc; pParmWIN32->parm = pParm; - pParmWIN32->epicsPriority = priority; + pParmWIN32->epicsPriority = opts->priority; { unsigned threadId; pParmWIN32->handle = (HANDLE) _beginthreadex ( - 0, stackSize, epicsWin32ThreadEntry, + 0, opts->stackSize, epicsWin32ThreadEntry, pParmWIN32, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, & threadId ); @@ -615,7 +626,7 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (const char *pName, pParmWIN32->id = ( DWORD ) threadId ; } - osdPriority = epicsThreadGetOsdPriorityValue (priority); + osdPriority = epicsThreadGetOsdPriorityValue (opts->priority); bstat = SetThreadPriority ( pParmWIN32->handle, osdPriority ); if (!bstat) { CloseHandle ( pParmWIN32->handle ); diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 755390eed..65e1929ec 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -430,15 +430,22 @@ void epicsThreadRealtimeLock(void) #endif } -epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) -{ #if defined (OSITHREAD_USE_DEFAULT_STACK) - return 0; +#define STACK_SIZE(f) (0) #elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0 #define STACK_SIZE(f) (f * 0x10000 * sizeof(void *)) static const unsigned stackSizeTable[epicsThreadStackBig+1] = { STACK_SIZE(1), STACK_SIZE(2), STACK_SIZE(4) }; +#else +#define STACK_SIZE(f) (0) +#endif /*_POSIX_THREAD_ATTR_STACKSIZE*/ + +epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) +{ +#if defined (OSITHREAD_USE_DEFAULT_STACK) + return 0; +#elif defined(_POSIX_THREAD_ATTR_STACKSIZE) && _POSIX_THREAD_ATTR_STACKSIZE > 0 if (stackSizeClasspriority,opts->stackSize,funptr,parm); if(pthreadInfo==0) return 0; pthreadInfo->isEpicsThread = 1; setSchedulingPolicy(pthreadInfo,SCHED_FIFO); @@ -518,7 +535,7 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate(const char *name, if(status==EPERM){ /* Try again without SCHED_FIFO*/ free_threadInfo(pthreadInfo); - pthreadInfo = init_threadInfo(name,priority,stackSize,funptr,parm); + pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm); if(pthreadInfo==0) return 0; pthreadInfo->isEpicsThread = 1; status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr, diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index ce01ea609..6a71301a2 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -133,6 +133,13 @@ unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) return stackSizeTable[stackSizeClass]; } +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 4000*ARCH_STACK_FACTOR}; + +void epicsThreadOptsDefaults(epicsThreadOpts *opts) +{ + *opts = opts_default; +} + struct epicsThreadOSD {}; /* Strictly speaking this should be a WIND_TCB, but we only need it to * be able to create an epicsThreadId that is guaranteed never to be @@ -190,19 +197,22 @@ static void createFunction(EPICSTHREADFUNC func, void *parm) #else #define TASK_FLAGS (VX_FP_TASK) #endif -epicsThreadId epicsThreadCreate(const char *name, - unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm) +epicsThreadId +epicsThreadCreateOpt ( + const char * name, + EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { int tid; + if(!opts) opts = &opts_default; + epicsThreadInit(); - if(stackSize<100) { - errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,stackSize); + if(opts->stackSize<100) { + errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,opts->stackSize); return(0); } - tid = taskSpawn((char *)name,getOssPriorityValue(priority), - TASK_FLAGS, stackSize, + tid = taskSpawn((char *)name,getOssPriorityValue(opts->priority), + TASK_FLAGS, opts->stackSize, (FUNCPTR)createFunction,(int)funptr,(int)parm, 0,0,0,0,0,0,0,0); if(tid==ERROR) { From d989c8fade61a2fbff0823276f3a52449022a96c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 4 Apr 2018 11:23:53 -0700 Subject: [PATCH 002/281] libCom: joinable threads (posix only) Add epicsThreadJoin() and epicsThreadOpts::joinable. For compatibility, default threads aren't joinable by default. Currently only POSIX can join. --- modules/libcom/src/osi/epicsThread.cpp | 1 + modules/libcom/src/osi/epicsThread.h | 5 +- modules/libcom/src/osi/os/Linux/osdThread.h | 5 ++ modules/libcom/src/osi/os/RTEMS/osdThread.c | 4 +- modules/libcom/src/osi/os/RTEMS/osdThread.h | 3 + modules/libcom/src/osi/os/WIN32/osdThread.c | 4 +- modules/libcom/src/osi/os/WIN32/osdThread.h | 4 +- modules/libcom/src/osi/os/posix/osdThread.c | 56 ++++++++++++++++--- modules/libcom/src/osi/os/posix/osdThread.h | 5 ++ modules/libcom/src/osi/os/vxWorks/osdThread.c | 4 +- modules/libcom/src/osi/os/vxWorks/osdThread.h | 3 + 11 files changed, 80 insertions(+), 14 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 372806edb..4f983f0e3 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -38,6 +38,7 @@ epicsThreadId epicsShareAPI epicsThreadCreate ( epicsThreadOpts opts; opts.priority = priority; opts.stackSize = stackSize; + opts.joinable = 0; return epicsThreadCreateOpt(name, funptr, parm, &opts); } diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index d0879a8eb..0482bea34 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -73,6 +73,8 @@ typedef struct epicsThreadOpts { * @warning Do not pass enum epicsThreadStackSizeClass directly! */ unsigned int stackSize; + /** Should thread be joinable? (default (0) is not joinable). */ + unsigned int joinable; } epicsThreadOpts; epicsShareFunc void epicsThreadOptsDefaults(epicsThreadOpts *opts); @@ -86,7 +88,8 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( EPICSTHREADFUNC funptr,void * parm ); epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate ( const char * name, unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void * parm ); + EPICSTHREADFUNC funptr,void * parm ); +epicsShareFunc void epicsThreadJoin(epicsThreadId id); epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void); epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id); epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority( diff --git a/modules/libcom/src/osi/os/Linux/osdThread.h b/modules/libcom/src/osi/os/Linux/osdThread.h index 7d2a4868d..40a837e9f 100644 --- a/modules/libcom/src/osi/os/Linux/osdThread.h +++ b/modules/libcom/src/osi/os/Linux/osdThread.h @@ -16,12 +16,16 @@ #include "ellLib.h" #include "epicsEvent.h" +/* This target supports joining threads */ +#define EPICS_THREAD_CAN_JOIN (1) + #ifdef __cplusplus extern "C" { #endif typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; pthread_t tid; pid_t lwpId; pthread_attr_t attr; @@ -35,6 +39,7 @@ typedef struct epicsThreadOSD { int isRealTimeScheduled; int isOnThreadList; unsigned int osiPriority; + int joinable; char name[1]; /* actually larger */ } epicsThreadOSD; diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index 7b478df65..8df2415c0 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -148,7 +148,7 @@ epicsThreadGetStackSize (epicsThreadStackSizeClass size) return stackSize; } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 5000}; +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 5000, 0}; void epicsThreadOptsDefaults(epicsThreadOpts *opts) { @@ -316,6 +316,8 @@ threadMustCreate (const char *name, return tid; } +void epicsThreadJoin(epicsThreadId id) {} + void epicsThreadSuspendSelf (void) { diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.h b/modules/libcom/src/osi/os/RTEMS/osdThread.h index 4451f845a..7307603eb 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.h +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.h @@ -8,5 +8,8 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +/* This target does not support joining threads */ +#define EPICS_THREAD_CAN_JOIN (0) + int epicsThreadGetOssPriorityValue(unsigned int osiPriority); diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index f78c7c0f4..fb3f39f88 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -464,7 +464,7 @@ epicsShareFunc unsigned int epicsShareAPI return stackSizeTable[stackSizeClass]; } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1)}; +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1), 0}; void epicsThreadOptsDefaults(epicsThreadOpts *opts) { @@ -651,6 +651,8 @@ epicsThreadId epicsThreadCreateOpt ( return ( epicsThreadId ) pParmWIN32; } +void epicsThreadJoin(epicsThreadId id) {} + /* * epicsThreadSuspendSelf () */ diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.h b/modules/libcom/src/osi/os/WIN32/osdThread.h index 136e96bf4..10025d2ad 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.h +++ b/modules/libcom/src/osi/os/WIN32/osdThread.h @@ -11,5 +11,7 @@ #ifndef osdThreadh #define osdThreadh - +/* This target does not support joining threads */ +#define EPICS_THREAD_CAN_JOIN (0) + #endif /* osdThreadh */ diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 65e1929ec..d34edf694 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -38,6 +38,7 @@ #include "errlog.h" #include "epicsAssert.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void epicsThreadShowInfo(epicsThreadOSD *pthreadInfo, unsigned int level); epicsShareFunc void osdThreadHooksRun(epicsThreadId id); @@ -167,12 +168,14 @@ static epicsThreadOSD * create_threadInfo(const char *name) return NULL; } strcpy(pthreadInfo->name, name); + epicsAtomicIncrIntT(&pthreadInfo->refcnt); /* initial ref for the thread itself */ return pthreadInfo; } static epicsThreadOSD * init_threadInfo(const char *name, unsigned int priority, unsigned int stackSize, - EPICSTHREADFUNC funptr,void *parm) + EPICSTHREADFUNC funptr,void *parm, + unsigned joinable) { epicsThreadOSD *pthreadInfo; int status; @@ -182,12 +185,15 @@ static epicsThreadOSD * init_threadInfo(const char *name, return NULL; pthreadInfo->createFunc = funptr; pthreadInfo->createArg = parm; + pthreadInfo->joinable = joinable; status = pthread_attr_init(&pthreadInfo->attr); checkStatusOnce(status,"pthread_attr_init"); if(status) return 0; - status = pthread_attr_setdetachstate( - &pthreadInfo->attr, PTHREAD_CREATE_DETACHED); - checkStatusOnce(status,"pthread_attr_setdetachstate"); + if(!joinable){ + status = pthread_attr_setdetachstate( + &pthreadInfo->attr, PTHREAD_CREATE_DETACHED); + checkStatusOnce(status,"pthread_attr_setdetachstate"); + } #if defined (_POSIX_THREAD_ATTR_STACKSIZE) #if ! defined (OSITHREAD_USE_DEFAULT_STACK) status = pthread_attr_setstacksize( &pthreadInfo->attr,(size_t)stackSize); @@ -204,6 +210,8 @@ static void free_threadInfo(epicsThreadOSD *pthreadInfo) { int status; + if(epicsAtomicDecrIntT(&pthreadInfo->refcnt) > 0) return; + status = mutexLock(&listLock); checkStatusQuit(status,"pthread_mutex_lock","free_threadInfo"); if(pthreadInfo->isOnThreadList) ellDelete(&pthreadList,&pthreadInfo->node); @@ -366,7 +374,7 @@ static void once(void) if(errVerbose) fprintf(stderr,"task priorities are not implemented\n"); #endif /* _POSIX_THREAD_PRIORITY_SCHEDULING */ - pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0); + pthreadInfo = init_threadInfo("_main_",0,epicsThreadGetStackSize(epicsThreadStackSmall),0,0,0); assert(pthreadInfo!=NULL); status = pthread_setspecific(getpthreadInfo,(void *)pthreadInfo); checkStatusOnceQuit(status,"pthread_setspecific","epicsThreadInit"); @@ -462,7 +470,7 @@ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadSt #endif /*_POSIX_THREAD_ATTR_STACKSIZE*/ } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1)}; +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1), 0}; void epicsThreadOptsDefaults(epicsThreadOpts *opts) { @@ -525,7 +533,7 @@ epicsThreadCreateOpt ( assert(pcommonAttr); sigfillset(&blockAllSig); pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig); - pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm); + pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm,opts->joinable); if(pthreadInfo==0) return 0; pthreadInfo->isEpicsThread = 1; setSchedulingPolicy(pthreadInfo,SCHED_FIFO); @@ -535,7 +543,7 @@ epicsThreadCreateOpt ( if(status==EPERM){ /* Try again without SCHED_FIFO*/ free_threadInfo(pthreadInfo); - pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm); + pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm,opts->joinable); if(pthreadInfo==0) return 0; pthreadInfo->isEpicsThread = 1; status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr, @@ -548,6 +556,10 @@ epicsThreadCreateOpt ( } status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL); checkStatusOnce(status,"pthread_sigmask"); + if(pthreadInfo->joinable) { + /* extra ref for epicsThreadJoin() */ + epicsAtomicIncrIntT(&pthreadInfo->refcnt); + } return(pthreadInfo); } @@ -587,7 +599,33 @@ static epicsThreadOSD *createImplicit(void) } return pthreadInfo; } - + +void epicsThreadJoin(epicsThreadId id) +{ + void *ret = NULL; + int status; + + if(!id) { + return; + } else if(!id->joinable) { + /* try to error nicely, however in all likelyhood de-ref of + * 'id' has already caused SIGSEGV as we are racing thread exit, + * which free's 'id'. + */ + cantProceed("%s join not enabled for thread.\n", id->name); + } + + status = pthread_join(id->tid, &ret); + if(status == EDEADLK) { + /* Thread can't join itself (directly or indirectly) + * so we detach instead. + */ + status = pthread_detach(id->tid); + checkStatusOnce(status, "pthread_detach"); + } else checkStatusOnce(status, "pthread_join"); + free_threadInfo(id); +} + epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void) { epicsThreadOSD *pthreadInfo; diff --git a/modules/libcom/src/osi/os/posix/osdThread.h b/modules/libcom/src/osi/os/posix/osdThread.h index 3a80b537c..eee0c825d 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.h +++ b/modules/libcom/src/osi/os/posix/osdThread.h @@ -16,12 +16,16 @@ #include "ellLib.h" #include "epicsEvent.h" +/* This target supports joining threads */ +#define EPICS_THREAD_CAN_JOIN (1) + #ifdef __cplusplus extern "C" { #endif typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; pthread_t tid; pthread_attr_t attr; struct sched_param schedParam; @@ -34,6 +38,7 @@ typedef struct epicsThreadOSD { int isRealTimeScheduled; int isOnThreadList; unsigned int osiPriority; + int joinable; char name[1]; /* actually larger */ } epicsThreadOSD; diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 6a71301a2..7a0fe7b9f 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -133,7 +133,7 @@ unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) return stackSizeTable[stackSizeClass]; } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 4000*ARCH_STACK_FACTOR}; +static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 4000*ARCH_STACK_FACTOR, 0}; void epicsThreadOptsDefaults(epicsThreadOpts *opts) { @@ -223,6 +223,8 @@ epicsThreadCreateOpt ( return((epicsThreadId)tid); } +void epicsThreadJoin(epicsThreadId id) {} + void epicsThreadSuspendSelf() { STATUS status; diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.h b/modules/libcom/src/osi/os/vxWorks/osdThread.h index 2ee9f2d46..09704b667 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.h +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.h @@ -10,4 +10,7 @@ #ifndef osdThreadh #define osdThreadh +/* This target does not support joining threads */ +#define EPICS_THREAD_CAN_JOIN (0) + #endif /* osdThreadh */ From c9dcab95a6aa7376edde322d3b9473e9a89c2b38 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 4 Apr 2018 11:28:08 -0700 Subject: [PATCH 003/281] class epicsThread is joinable --- modules/libcom/src/osi/epicsThread.cpp | 22 +++++++++++++++++++--- modules/libcom/src/osi/epicsThread.h | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 4f983f0e3..52819c8eb 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -153,6 +153,10 @@ bool epicsThread::exitWait ( const double delay ) throw () if ( this->pThreadDestroyed ) { *this->pThreadDestroyed = true; } + if(!joined) { + epicsThreadJoin(this->id); + joined = true; + } return true; } epicsTime exitWaitBegin = epicsTime::getCurrent (); @@ -166,6 +170,10 @@ bool epicsThread::exitWait ( const double delay ) throw () epicsTime current = epicsTime::getCurrent (); exitWaitElapsed = current - exitWaitBegin; } + if(!joined) { + epicsThreadJoin(this->id); + joined = true; + } } catch ( std :: exception & except ) { errlogPrintf ( @@ -190,10 +198,18 @@ epicsThread::epicsThread ( unsigned stackSize, unsigned priority ) : runable ( runableIn ), id ( 0 ), pThreadDestroyed ( 0 ), begin ( false ), cancel ( false ), terminated ( false ) + , joined(false) { - this->id = epicsThreadCreate ( - pName, priority, stackSize, epicsThreadCallEntryPoint, - static_cast < void * > ( this ) ); + epicsThreadOpts opts; + epicsThreadOptsDefaults(&opts); + opts.stackSize = stackSize; + opts.priority = priority; + opts.joinable = 1; + + this->id = epicsThreadCreateOpt( + pName, epicsThreadCallEntryPoint, + static_cast < void * > ( this ), + &opts); if ( ! this->id ) { throw unableToCreateThread (); } diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index 0482bea34..c43d7fb01 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -197,6 +197,7 @@ private: bool begin; bool cancel; bool terminated; + bool joined; bool beginWait () throw (); epicsThread ( const epicsThread & ); From 460e58e3e5624501a4831eb6f45e9f9d8deb5a78 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 5 Apr 2018 09:04:46 -0700 Subject: [PATCH 004/281] libCom "join" win32 threads Wait for completion --- modules/libcom/src/osi/os/WIN32/osdThread.c | 37 ++++++++++++++++++++- modules/libcom/src/osi/os/WIN32/osdThread.h | 4 +-- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index fb3f39f88..eba41645f 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -32,6 +32,7 @@ #include "epicsAssert.h" #include "ellLib.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void osdThreadHooksRun(epicsThreadId id); @@ -46,6 +47,7 @@ typedef struct win32ThreadGlobal { typedef struct epicsThreadOSD { ELLNODE node; + int refcnt; HANDLE handle; EPICSTHREADFUNC funptr; void * parm; @@ -53,6 +55,7 @@ typedef struct epicsThreadOSD { DWORD id; unsigned epicsPriority; char isSuspended; + char joinable; } win32ThreadParam; typedef struct epicsThreadPrivateOSD { @@ -238,6 +241,8 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) } if ( pParm ) { + if(epicsAtomicDecrIntT(&pParm->refcnt) > 0) return; + /* fprintf ( stderr, "thread %s is exiting\n", pParm->pName ); */ EnterCriticalSection ( & pGbl->mutex ); ellDelete ( & pGbl->threadList, & pParm->node ); @@ -533,6 +538,7 @@ static win32ThreadParam * epicsThreadParmCreate ( const char *pName ) pParmWIN32->pName = (char *) ( pParmWIN32 + 1 ); strcpy ( pParmWIN32->pName, pName ); pParmWIN32->isSuspended = 0; + epicsAtomicIncrIntT(&pParmWIN32->refcnt); } return pParmWIN32; } @@ -648,10 +654,39 @@ epicsThreadId epicsThreadCreateOpt ( return NULL; } + if(opts->joinable) { + pParmWIN32->joinable = 1; + epicsAtomicIncrIntT(&pParmWIN32->refcnt); + } + return ( epicsThreadId ) pParmWIN32; } -void epicsThreadJoin(epicsThreadId id) {} +void epicsThreadJoin(epicsThreadId id) +{ + win32ThreadParam * pParmWIN32 = id; + + if(!id) { + /* no-op */ + } else if(!pParmWIN32->joinable) { + /* try to error nicely, however in all likelyhood de-ref of + * 'pParmWIN32' has already crashed us as we are racing thread exit, + * which free's 'pParmWIN32'. + */ + cantProceed("%s join not enabled for thread.\n", pParmWIN32->pName); + + } else if(epicsThreadGetIdSelf() != id) { + DWORD status = WaitForSingleObject(pParmWIN32->handle, INFINITE); + if(status != WAIT_OBJECT_0) { + /* TODO: signal error? */ + } + + epicsParmCleanupWIN32(pParmWIN32); + } else { + /* join self silently does nothing */ + epicsParmCleanupWIN32(pParmWIN32); + } +} /* * epicsThreadSuspendSelf () diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.h b/modules/libcom/src/osi/os/WIN32/osdThread.h index 10025d2ad..fe60564d1 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.h +++ b/modules/libcom/src/osi/os/WIN32/osdThread.h @@ -11,7 +11,7 @@ #ifndef osdThreadh #define osdThreadh -/* This target does not support joining threads */ -#define EPICS_THREAD_CAN_JOIN (0) +/* This target supports joining threads */ +#define EPICS_THREAD_CAN_JOIN (1) #endif /* osdThreadh */ From 149ab1186ad6e8b8e7a8879bf40d56c905ccce3a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 21 Apr 2018 10:15:35 -0700 Subject: [PATCH 005/281] epicsThread fix join --- modules/libcom/src/osi/epicsThread.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 52819c8eb..7092900b1 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -154,8 +154,11 @@ bool epicsThread::exitWait ( const double delay ) throw () *this->pThreadDestroyed = true; } if(!joined) { + { + epicsGuard < epicsMutex > guard ( this->mutex ); + joined = true; + } epicsThreadJoin(this->id); - joined = true; } return true; } @@ -170,9 +173,11 @@ bool epicsThread::exitWait ( const double delay ) throw () epicsTime current = epicsTime::getCurrent (); exitWaitElapsed = current - exitWaitBegin; } - if(!joined) { - epicsThreadJoin(this->id); + if(this->terminated && !joined) { joined = true; + + epicsGuardRelease < epicsMutex > unguard ( guard ); + epicsThreadJoin(this->id); } } catch ( std :: exception & except ) { From f9092783f89d3626fdbd431457f15a084b2fb884 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 23 Jun 2018 12:36:07 -0700 Subject: [PATCH 006/281] RTEMS thread join --- modules/libcom/RTEMS/rtems_config.c | 1 + modules/libcom/src/osi/os/RTEMS/osdThread.c | 105 +++++++++++++++++--- modules/libcom/src/osi/os/RTEMS/osdThread.h | 4 +- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/modules/libcom/RTEMS/rtems_config.c b/modules/libcom/RTEMS/rtems_config.c index 147c08b10..796b1049b 100644 --- a/modules/libcom/RTEMS/rtems_config.c +++ b/modules/libcom/RTEMS/rtems_config.c @@ -27,6 +27,7 @@ #endif #define CONFIGURE_MAXIMUM_TASKS rtems_resource_unlimited(30) +#define CONFIGURE_MAXIMUM_BARRIERS rtems_resource_unlimited(30) #define CONFIGURE_MAXIMUM_SEMAPHORES rtems_resource_unlimited(500) #define CONFIGURE_MAXIMUM_TIMERS rtems_resource_unlimited(20) #define CONFIGURE_MAXIMUM_MESSAGE_QUEUES rtems_resource_unlimited(5) diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index 8df2415c0..a22e2f87f 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -35,6 +35,7 @@ #include "osiUnistd.h" #include "osdInterrupt.h" #include "epicsExit.h" +#include "epicsAtomic.h" epicsShareFunc void osdThreadHooksRun(epicsThreadId id); epicsShareFunc void osdThreadHooksRunMain(epicsThreadId id); @@ -47,6 +48,9 @@ struct taskVar { struct taskVar *back; char *name; rtems_id id; + rtems_id join_barrier; /* only valid if joinable */ + int refcnt; + int joinable; EPICSTHREADFUNC funptr; void *parm; unsigned int threadVariableCapacity; @@ -170,6 +174,22 @@ taskVarUnlock (void) epicsMutexOsdUnlock (taskVarMutex); } +static +void taskUnref(struct taskVar *v) +{ + int ref = epicsAtomicDecrIntT(&v->refcnt); + assert(ref>=0); + if(ref>0) return; + + + if (v->joinable) { + rtems_barrier_delete(v->join_barrier); + } + free (v->threadVariables); + free (v->name); + free (v); +} + /* * EPICS threads destroy themselves by returning from the thread entry function. * This simple wrapper provides the same semantics on RTEMS. @@ -190,9 +210,12 @@ threadWrapper (rtems_task_argument arg) if (v->forw) v->forw->back = v->back; taskVarUnlock (); - free (v->threadVariables); - free (v->name); - free (v); + if(v->joinable) { + rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT); + if(sc!=RTEMS_SUCCESSFUL) + cantProceed("oops %s\n", rtems_status_text(sc)); + } + taskUnref(v); rtems_task_delete (RTEMS_SELF); } @@ -203,21 +226,34 @@ void epicsThreadExitMain (void) { } -static void +static rtems_status_code setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr, - void *parm) + void *parm, int joinable) { struct taskVar *v; uint32_t note; - rtems_status_code sc; + rtems_status_code sc = RTEMS_SUCCESSFUL; v = mallocMustSucceed (sizeof *v, "epicsThreadCreate_vars"); v->name = epicsStrDup(name); v->id = tid; v->funptr = funptr; v->parm = parm; + v->joinable = joinable; + v->refcnt = joinable ? 2 : 1; v->threadVariableCapacity = 0; v->threadVariables = NULL; + if (joinable) { + char c[3]; + strncpy(c, v->name, 3); + sc = rtems_barrier_create(rtems_build_name('~', c[0], c[1], c[2]), + RTEMS_BARRIER_AUTOMATIC_RELEASE | RTEMS_LOCAL, + 2, &v->join_barrier); + if (sc != RTEMS_SUCCESSFUL) { + free(v); + return sc; + } + } note = (uint32_t)v; rtems_task_set_note (tid, RTEMS_NOTEPAD_TASKVAR, note); taskVarLock (); @@ -229,10 +265,14 @@ setThreadInfo(rtems_id tid, const char *name, EPICSTHREADFUNC funptr, taskVarUnlock (); if (funptr) { sc = rtems_task_start (tid, threadWrapper, (rtems_task_argument)v); - if (sc != RTEMS_SUCCESSFUL) - errlogPrintf ("setThreadInfo: Can't start %s: %s\n", - name, rtems_status_text(sc)); } + if (sc != RTEMS_SUCCESSFUL) { + if (joinable) { + rtems_barrier_delete(v->join_barrier); + } + free(v); + } + return sc; } /* @@ -254,7 +294,8 @@ epicsThreadInit (void) if (!onceMutex || !taskVarMutex) cantProceed("epicsThreadInit() can't create global mutexes\n"); rtems_task_ident (RTEMS_SELF, 0, &tid); - setThreadInfo (tid, "_main_", NULL, NULL); + if(setThreadInfo (tid, "_main_", NULL, NULL, 0) != RTEMS_SUCCESSFUL) + cantProceed("epicsThreadInit() unable to setup _main_"); osdThreadHooksRunMain((epicsThreadId)tid); initialized = 1; epicsThreadCreate ("ImsgDaemon", 99, @@ -300,7 +341,13 @@ epicsThreadCreateOpt ( name, rtems_status_text(sc)); return 0; } - setThreadInfo (tid, name, funptr,parm); + sc = setThreadInfo (tid, name, funptr, parm, opts->joinable); + if (sc != RTEMS_SUCCESSFUL) { + errlogPrintf ("epicsThreadCreate create failure during setup for %s: %s\n", + name, rtems_status_text(sc)); + rtems_task_delete(tid); + return 0; + } return (epicsThreadId)tid; } @@ -316,7 +363,41 @@ threadMustCreate (const char *name, return tid; } -void epicsThreadJoin(epicsThreadId id) {} +void epicsThreadJoin(epicsThreadId id) +{ + rtems_id target_tid = (rtems_id)id, self_tid; + struct taskVar *v; + + rtems_task_ident (RTEMS_SELF, 0, &self_tid); + + { + uint32_t note; + rtems_task_get_note (target_tid, RTEMS_NOTEPAD_TASKVAR, ¬e); + v = (void *)note; + } + + if(!v->joinable) { + /* try to error nicely, however in all likelyhood rtems_task_get_note failed, + * or gave us the wrong thread as we are racing thread exit. + */ + cantProceed("%s join not enabled for thread.\n", v->name); + + } else if(target_tid!=self_tid) { + /* wait for target to complete */ + rtems_status_code sc = rtems_barrier_wait(v->join_barrier, RTEMS_NO_TIMEOUT); + if(sc!=RTEMS_SUCCESSFUL) + cantProceed("oopsj %s\n", rtems_status_text(sc)); + + if(sc != RTEMS_SUCCESSFUL) { + errlogPrintf("epicsThreadJoin('%s') -> %s\n", v->name, rtems_status_text(sc)); + } + } + + taskUnref(v); + /* target task may be deleted. + * self task is not deleted, even for self join. + */ +} void epicsThreadSuspendSelf (void) diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.h b/modules/libcom/src/osi/os/RTEMS/osdThread.h index 7307603eb..84d579c0f 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.h +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.h @@ -8,8 +8,8 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ -/* This target does not support joining threads */ -#define EPICS_THREAD_CAN_JOIN (0) +/* This target supports joining threads */ +#define EPICS_THREAD_CAN_JOIN (1) int epicsThreadGetOssPriorityValue(unsigned int osiPriority); From 530eba133fd1fc3af91457bad73220cfcfbbe2cc Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 16 Jun 2018 09:45:00 -0700 Subject: [PATCH 007/281] as,rsrv: use real client IP instead of untrusted host name --- modules/database/src/ioc/rsrv/camessage.c | 8 +++++ modules/database/src/ioc/rsrv/caservertask.c | 14 +++++++++ modules/database/src/ioc/rsrv/server.h | 2 +- modules/libcom/src/as/asLib.h | 5 +++ modules/libcom/src/as/asLibRoutines.c | 32 +++++++++++++++++--- modules/libcom/src/iocsh/libComRegister.c | 6 ++++ 6 files changed, 61 insertions(+), 6 deletions(-) diff --git a/modules/database/src/ioc/rsrv/camessage.c b/modules/database/src/ioc/rsrv/camessage.c index 72a4b17a1..40448d018 100644 --- a/modules/database/src/ioc/rsrv/camessage.c +++ b/modules/database/src/ioc/rsrv/camessage.c @@ -861,6 +861,14 @@ static int host_name_action ( caHdrLargeArray *mp, void *pPayload, return RSRV_ERROR; } + /* after all validation */ + if(asUseIP) { + + DLOG (2, ( "CAS: host_name_action for \"%s\" ignores clist provided host name\n", + client->pHostName ) ); + return RSRV_OK; + } + /* * user name will not change if there isnt enough memory */ diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index f377d837f..048487b20 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -1421,6 +1421,20 @@ struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr) } client->addr = peerAddr->ia; + if(asUseIP) { + epicsUInt32 ip = ntohl(client->addr.sin_addr.s_addr); + client->pHostName = malloc(24); + if(!client->pHostName) { + destroy_client ( client ); + return NULL; + } + epicsSnprintf(client->pHostName, 24, + "%u.%u.%u.%u", + (ip>>24)&0xff, + (ip>>16)&0xff, + (ip>>8)&0xff, + (ip>>0)&0xff); + } /* * see TCP(4P) this seems to make unsolicited single events much diff --git a/modules/database/src/ioc/rsrv/server.h b/modules/database/src/ioc/rsrv/server.h index 4d502f77f..6392c692b 100644 --- a/modules/database/src/ioc/rsrv/server.h +++ b/modules/database/src/ioc/rsrv/server.h @@ -86,7 +86,7 @@ typedef struct client { ELLLIST chanList; ELLLIST chanPendingUpdateARList; ELLLIST putNotifyQue; - struct sockaddr_in addr; + struct sockaddr_in addr; /* peer address, TCP only */ epicsTimeStamp time_at_last_send; epicsTimeStamp time_at_last_recv; void *evuser; diff --git a/modules/libcom/src/as/asLib.h b/modules/libcom/src/as/asLib.h index 261e5ed7d..b4e5139ce 100644 --- a/modules/libcom/src/as/asLib.h +++ b/modules/libcom/src/as/asLib.h @@ -21,6 +21,11 @@ extern "C" { #endif +/* 0 - Use (unverified) client provided host name string. + * 1 - Use actual client IP address. HAG() are resolved to IPs at ACF load time. + */ +epicsShareExtern int asUseIP; + typedef struct asgMember *ASMEMBERPVT; typedef struct asgClient *ASCLIENTPVT; typedef int (*ASINPUTFUNCPTR)(char *buf,int max_size); diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index 3f5713efc..ceade030e 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -15,6 +15,8 @@ #include #define epicsExportSharedSymbols +#include "osiSock.h" +#include "epicsTypes.h" #include "epicsStdio.h" #include "dbDefs.h" #include "epicsThread.h" @@ -27,6 +29,8 @@ #include "postfix.h" #include "asLib.h" +int asUseIP; + static epicsMutexId asLock; #define LOCK epicsMutexMustLock(asLock) #define UNLOCK epicsMutexUnlock(asLock) @@ -1206,11 +1210,29 @@ static long asHagAddHost(HAG *phag,const char *host) int len, i; if (!phag) return 0; - len = strlen(host); - phagname = asCalloc(1, sizeof(HAGNAME) + len + 1); - phagname->host = (char *)(phagname + 1); - for (i = 0; i < len; i++) { - phagname->host[i] = (char)tolower((int)host[i]); + if(!asUseIP) { + len = strlen(host); + phagname = asCalloc(1, sizeof(HAGNAME) + len + 1); + phagname->host = (char *)(phagname + 1); + for (i = 0; i < len; i++) { + phagname->host[i] = (char)tolower((int)host[i]); + } + } else { + struct sockaddr_in addr; + epicsUInt32 ip; + if(aToIPAddr(host, 0, &addr)) { + errlogPrintf("Unable to resolve host '%s'\n", host); + return S_asLib_noHag; + } + ip = ntohl(addr.sin_addr.s_addr); + phagname = asCalloc(1, sizeof(HAGNAME) + 24); + phagname->host = (char *)(phagname + 1); + epicsSnprintf(phagname->host, 24, + "%u.%u.%u.%u", + (ip>>24)&0xff, + (ip>>16)&0xff, + (ip>>8)&0xff, + (ip>>0)&0xff); } ellAdd(&phag->list, &phagname->node); return 0; diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index 0d8c5678c..2bbb09f3e 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -12,6 +12,7 @@ #define epicsExportSharedSymbols #include "iocsh.h" +#include "asLib.h" #include "epicsStdioRedirect.h" #include "epicsString.h" #include "epicsTime.h" @@ -392,6 +393,8 @@ static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) installLastResortEventProvider(); } +static iocshVarDef asUseIPDef = {"asUseIP", iocshArgInt, 0}; + void epicsShareAPI libComRegister(void) { iocshRegister(&dateFuncDef, dateCallFunc); @@ -424,4 +427,7 @@ void epicsShareAPI libComRegister(void) iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc); iocshRegister(&installLastResortEventProviderFuncDef, installLastResortEventProviderCallFunc); + + asUseIPDef.pval = &asUseIP; + iocshRegisterVariable(&asUseIPDef); } From dced29c4752a224cafd85e9dc5ca65dea7b50960 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 14 Nov 2018 14:41:45 -0800 Subject: [PATCH 008/281] asLib: test asUseIP --- modules/libcom/test/aslibtest.c | 39 +++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/modules/libcom/test/aslibtest.c b/modules/libcom/test/aslibtest.c index 875aa56fd..367a12426 100644 --- a/modules/libcom/test/aslibtest.c +++ b/modules/libcom/test/aslibtest.c @@ -81,8 +81,8 @@ static const char hostname_config[] = "" static void testHostNames(void) { - testDiag("testHostNames()"); + asUseIP = 0; testOk1(asInitMem(hostname_config, NULL)==0); @@ -109,11 +109,46 @@ static void testHostNames(void) testAccess("ro", 0); testAccess("rw", 0); } + +static void testUseIP(void) +{ + testDiag("testUseIP()"); + asUseIP = 1; + + /* still host names in .acf */ + testOk1(asInitMem(hostname_config, NULL)==0); + /* now resolved to IPs */ + + setUser("testing"); + setHost("localhost"); /* will not match against resolved IP */ + asAsl = 0; + + testAccess("invalid", 0); + testAccess("DEFAULT", 0); + testAccess("ro", 0); + testAccess("rw", 0); + + setHost("127.0.0.1"); + + testAccess("invalid", 0); + testAccess("DEFAULT", 0); + testAccess("ro", 1); + testAccess("rw", 3); + + setHost("nosuchhost"); + + testAccess("invalid", 0); + testAccess("DEFAULT", 0); + testAccess("ro", 0); + testAccess("rw", 0); +} + MAIN(aslibtest) { - testPlan(14); + testPlan(27); testSyntaxErrors(); testHostNames(); + testUseIP(); errlogFlush(); return testDone(); } From 4ee3cbf382d0694dd06b9cb53bfcfd2752545ddf Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 14 Mar 2018 20:52:22 -0700 Subject: [PATCH 009/281] LINKER_USE_RPATH=ORIGIN Use Linux specific linker trick to allow relocation of built tree. relative rpath use $ORIGIN to reference libraries in other modules by relative path. fix rel. RPATH --- configure/CONFIG_BASE | 2 ++ configure/CONFIG_COMMON | 2 ++ configure/CONFIG_SITE | 9 ++++++- configure/RULES_BUILD | 7 ++++++ configure/os/CONFIG.Common.linuxCommon | 2 ++ src/tools/Makefile | 2 ++ src/tools/makeRPath.py | 33 ++++++++++++++++++++++++++ 7 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/tools/makeRPath.py diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE index 137ce0098..32349ebd5 100644 --- a/configure/CONFIG_BASE +++ b/configure/CONFIG_BASE @@ -44,6 +44,8 @@ FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl GENVERSIONHEADER = $(PERL) $(TOOLS)/genVersionHeader.pl $(QUIET_FLAG) $(QUESTION_FLAG) +MAKERPATH = $(PYTHON) $(TOOLS)/makeRPath.py + #--------------------------------------------------------------- # tools for installing libraries and products INSTALL = $(PERL) $(TOOLS)/installEpics.pl $(QUIET_FLAG) diff --git a/configure/CONFIG_COMMON b/configure/CONFIG_COMMON index eef4d6745..d7766e50a 100644 --- a/configure/CONFIG_COMMON +++ b/configure/CONFIG_COMMON @@ -38,6 +38,8 @@ BUILD_ARCHS = $(EPICS_HOST_ARCH) $(CROSS1) $(CROSS2) # otherwise override this in os/CONFIG_SITE..Common PERL = perl -CSD +PYTHON = python + #------------------------------------------------------- # Check configure/RELEASE file for consistency CHECK_RELEASE_YES = checkRelease diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index b657f5b65..49f82c7a8 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -169,10 +169,17 @@ EPICS_SITE_VERSION = GCC_PIPE = NO # Set RPATH when linking executables and libraries. -# Must be either YES or NO. If you set this to NO you must also provide a +# Must be either YES, NO, or ORIGIN. If you set this to NO you must also provide a # way for Base executables to find their shared libraries when they are # run at build-time, e.g. set the LD_LIBRARY_PATH environment variable. +# ORIGIN is Linux specific. LINKER_USE_RPATH = YES +# Only used when LINKER_USE_RPATH=ORIGIN +# The build time root of the relocatable tree. +# Linking to libraries under this root directory will be relative. +# Linking to libraries outside of this root will be absolute. +LINKER_ORIGIN_ROOT = $(INSTALL_LOCATION) + # Overrides for the settings above may appear in a CONFIG_SITE.local file -include $(CONFIG)/CONFIG_SITE.local diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 21a838790..f2f4d8873 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -194,6 +194,13 @@ ifeq ($(EPICS_HOST_ARCH),$(T_A)) $(info Warning: RELEASE file consistency checks have been disabled) endif +# $(FINAL_DIR) signals eventual install locations to makeRPath script +$(TESTPRODNAME): FINAL_DIR=. +$(PRODNAME): FINAL_DIR=$(INSTALL_BIN) +$(TESTSHRLIBNAME): FINAL_DIR=. +$(SHRLIBNAME): FINAL_DIR=$(INSTALL_SHRLIB) +$(LOADABLE_SHRLIBNAME): FINAL_DIR=$(INSTALL_SHRLIB) + #--------------------------------------------------------------- # The order of the following rules is # VERY IMPORTANT !!!! diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index 965de09b8..e8e9ab3ca 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -25,11 +25,13 @@ STATIC_LDLIBS_YES= -Wl,-Bdynamic # Set runtime path for shared libraries if USE_RPATH=YES and STATIC_BUILD=NO SHRLIBDIR_RPATH_LDFLAGS_YES_NO = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) +SHRLIBDIR_RPATH_LDFLAGS_ORIGIN_NO = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(SHRLIB_DEPLIB_DIRS)) SHRLIBDIR_LDFLAGS += \ $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD)) # Set runtime path for products if USE_RPATH=YES and STATIC_BUILD=NO PRODDIR_RPATH_LDFLAGS_YES_NO = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) +PRODDIR_RPATH_LDFLAGS_ORIGIN_NO = $(shell $(MAKERPATH) -O '\$$ORIGIN' -F $(FINAL_DIR) -R $(LINKER_ORIGIN_ROOT) $(PROD_DEPLIB_DIRS)) PRODDIR_LDFLAGS += \ $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD)) diff --git a/src/tools/Makefile b/src/tools/Makefile index 39497a417..8c4f25adc 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -39,6 +39,8 @@ PERL_SCRIPTS += tap-to-junit-xml.pl PERL_SCRIPTS += useManifestTool.pl PERL_SCRIPTS += genVersionHeader.pl +PERL_SCRIPTS += makeRPath.py + HTMLS = style.css HTMLS += EPICS/Getopts.html HTMLS += EPICS/Path.html diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py new file mode 100644 index 000000000..edad80085 --- /dev/null +++ b/src/tools/makeRPath.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import sys +import os + +from argparse import ArgumentParser + +if os.environ.get('EPICS_DEBUG_RPATH','')=='YES': + sys.stderr.write('%s'%sys.argv) + +P = ArgumentParser() +P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file') +P.add_argument('-R','--root',default='/') +P.add_argument('-O', '--origin', default='$ORIGIN') +P.add_argument('path', nargs='*') +args = P.parse_args() + +fdir = os.path.abspath(args.final) + +output = [] +for path in args.path: + path = os.path.abspath(path) + + if args.root and os.path.relpath(path, args.root).startswith('../'): + pass # absolute rpath + else: + path = os.path.relpath(path, fdir) + + output.append('-Wl,-rpath,'+os.path.join(args.origin, path)) + +print(' '.join(output)) From 32340584b4fee7e3080e8d19332d959ef6de0e0a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 25 Apr 2018 22:57:03 -0700 Subject: [PATCH 010/281] epicsGetExecDir() paths relative to executable For linux, enable softIoc to find .dbd relative to the executable location. The same could be done for other targets *bsd may have symlink /proc/curproc/file fallback to sysctl() with KERN_PROC_PATHNAME solaris getexecname() mac _NSGetExecutablePath() WIN32 GetModuleFileName(NULL) others out of luck... --- modules/database/src/std/softIoc/softMain.cpp | 41 ++++++++++++++- modules/libcom/src/misc/unixFileName.h | 22 ++++++++ modules/libcom/src/osi/Makefile | 1 + modules/libcom/src/osi/os/Linux/osdgetexec.c | 50 +++++++++++++++++++ modules/libcom/src/osi/os/WIN32/osiFileName.h | 22 ++++++++ .../libcom/src/osi/os/cygwin32/osiFileName.h | 22 ++++++++ .../libcom/src/osi/os/default/osdgetexec.c | 14 ++++++ 7 files changed, 170 insertions(+), 2 deletions(-) create mode 100644 modules/libcom/src/osi/os/Linux/osdgetexec.c create mode 100644 modules/libcom/src/osi/os/default/osdgetexec.c diff --git a/modules/database/src/std/softIoc/softMain.cpp b/modules/database/src/std/softIoc/softMain.cpp index 8400a6554..01ef19b2f 100644 --- a/modules/database/src/std/softIoc/softMain.cpp +++ b/modules/database/src/std/softIoc/softMain.cpp @@ -62,23 +62,59 @@ #include "epicsThread.h" #include "epicsExit.h" #include "epicsStdio.h" +#include "epicsString.h" #include "dbStaticLib.h" #include "subRecord.h" #include "dbAccess.h" #include "asDbLib.h" #include "iocInit.h" #include "iocsh.h" +#include "osiFileName.h" #include "epicsInstallDir.h" extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); -#define DBD_FILE EPICS_BASE "/dbd/softIoc.dbd" -#define EXIT_FILE EPICS_BASE "/db/softIocExit.db" +#define DBD_BASE "dbd/softIoc.dbd" +#define EXIT_BASE "db/softIocExit.db" +#define DBD_FILE_REL "../../" DBD_BASE +#define EXIT_FILE_REL "../../" EXIT_BASE +#define DBD_FILE EPICS_BASE "/" DBD_BASE +#define EXIT_FILE EPICS_BASE "/" EXIT_BASE const char *arg0; const char *base_dbd = DBD_FILE; const char *exit_db = EXIT_FILE; +static void preparePath(void) +{ + FILE *fp; + char *prefix = epicsGetExecDir(); + char *dbd, *exit; + if(!prefix) return; + + dbd = (char*)malloc(strlen(prefix) + strlen(DBD_FILE_REL) + 1); + if(dbd) { + dbd[0] = '\0'; + strcat(dbd, prefix); + strcat(dbd, DBD_FILE_REL); + printf("Testing '%s'\n", dbd); + if((fp = fopen(dbd, "rb"))!=NULL) { + fclose(fp); + base_dbd = dbd; + } + } + + exit = (char*)malloc(strlen(prefix) + strlen(EXIT_FILE_REL) + 1); + if(exit) { + exit[0] = '\0'; + strcat(exit, prefix); + strcat(exit, EXIT_FILE_REL); + if((fp = fopen(exit, "rb"))!=NULL) { + fclose(fp); + exit_db = exit; + } + } +} static void exitSubroutine(subRecord *precord) { epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE); @@ -96,6 +132,7 @@ static void usage(int status) { int main(int argc, char *argv[]) { + preparePath(); char *dbd_file = const_cast(base_dbd); char *macros = NULL; char xmacro[PVNAME_STRINGSZ + 4]; diff --git a/modules/libcom/src/misc/unixFileName.h b/modules/libcom/src/misc/unixFileName.h index 36e818c8f..9d7af252c 100644 --- a/modules/libcom/src/misc/unixFileName.h +++ b/modules/libcom/src/misc/unixFileName.h @@ -14,7 +14,29 @@ #ifndef unixFileNameH #define unixFileNameH +#include + +#ifdef __cplusplus +extern "C" { +#endif + #define OSI_PATH_LIST_SEPARATOR ":" #define OSI_PATH_SEPARATOR "/" +/** Return the absolute path of the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecName(void); + +/** Return the absolute path of the directory containing the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecDir(void); + +#ifdef __cplusplus +} +#endif + #endif /* unixFileNameH */ diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile index ecbf4c23b..0352e9ffe 100644 --- a/modules/libcom/src/osi/Makefile +++ b/modules/libcom/src/osi/Makefile @@ -123,6 +123,7 @@ Com_SRCS += osdMonotonic.c Com_SRCS += osdProcess.c Com_SRCS += osdNetIntf.c Com_SRCS += osdMessageQueue.c +Com_SRCS += osdgetexec.c Com_SRCS += devLibVME.c Com_SRCS += devLibVMEOSD.c diff --git a/modules/libcom/src/osi/os/Linux/osdgetexec.c b/modules/libcom/src/osi/os/Linux/osdgetexec.c new file mode 100644 index 000000000..2ea8ca4ae --- /dev/null +++ b/modules/libcom/src/osi/os/Linux/osdgetexec.c @@ -0,0 +1,50 @@ + +#include +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = PATH_MAX; + char *ret = NULL; + ssize_t n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = readlink("/proc/self/exe", ret, max); + if(n < max) { + /* readlink() never adds a nil */ + ret[n] = '\0'; + break; + } + + max += 64; + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/WIN32/osiFileName.h b/modules/libcom/src/osi/os/WIN32/osiFileName.h index 6ff0308b2..ced745f71 100644 --- a/modules/libcom/src/osi/os/WIN32/osiFileName.h +++ b/modules/libcom/src/osi/os/WIN32/osiFileName.h @@ -15,7 +15,29 @@ #ifndef osiFileNameH #define osiFileNameH +#include + +#ifdef __cplusplus +extern "C" { +#endif + #define OSI_PATH_LIST_SEPARATOR ";" #define OSI_PATH_SEPARATOR "\\" +/** Return the absolute path of the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecName(void); + +/** Return the absolute path of the directory containing the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecDir(void); + +#ifdef __cplusplus +} +#endif + #endif /* osiFileNameH */ diff --git a/modules/libcom/src/osi/os/cygwin32/osiFileName.h b/modules/libcom/src/osi/os/cygwin32/osiFileName.h index 6d7fd6eb9..1e7799098 100644 --- a/modules/libcom/src/osi/os/cygwin32/osiFileName.h +++ b/modules/libcom/src/osi/os/cygwin32/osiFileName.h @@ -14,7 +14,29 @@ #ifndef osiFileNameH #define osiFileNameH +#include + +#ifdef __cplusplus +extern "C" { +#endif + #define OSI_PATH_LIST_SEPARATOR ";" #define OSI_PATH_SEPARATOR "\\" +/** Return the absolute path of the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecName(void); + +/** Return the absolute path of the directory containing the current executable. + @returns NULL or the path. Caller must free() + */ +epicsShareFunc +char *epicsGetExecDir(void); + +#ifdef __cplusplus +} +#endif + #endif /* osiFileNameH */ diff --git a/modules/libcom/src/osi/os/default/osdgetexec.c b/modules/libcom/src/osi/os/default/osdgetexec.c new file mode 100644 index 000000000..0bec9ead9 --- /dev/null +++ b/modules/libcom/src/osi/os/default/osdgetexec.c @@ -0,0 +1,14 @@ +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + return NULL; +} + +char *epicsGetExecDir(void) +{ + return NULL; +} From 84831e13e7bfea253c5a545c1c9c9f059d4b02bb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 26 Apr 2018 14:33:58 -0700 Subject: [PATCH 011/281] epicsGetExecName WIN32, Darwin, solaris, freebsd --- modules/libcom/src/osi/os/Darwin/osdgetexec.c | 50 ++++++++++++++ modules/libcom/src/osi/os/Linux/osdgetexec.c | 6 +- modules/libcom/src/osi/os/WIN32/osdgetexec.c | 52 ++++++++++++++ .../libcom/src/osi/os/freebsd/osdgetexec.c | 68 +++++++++++++++++++ .../libcom/src/osi/os/solaris/osdgetexec.c | 30 ++++++++ modules/libcom/test/Makefile | 5 ++ modules/libcom/test/testexecname.c | 24 +++++++ 7 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 modules/libcom/src/osi/os/Darwin/osdgetexec.c create mode 100644 modules/libcom/src/osi/os/WIN32/osdgetexec.c create mode 100644 modules/libcom/src/osi/os/freebsd/osdgetexec.c create mode 100644 modules/libcom/src/osi/os/solaris/osdgetexec.c create mode 100644 modules/libcom/test/testexecname.c diff --git a/modules/libcom/src/osi/os/Darwin/osdgetexec.c b/modules/libcom/src/osi/os/Darwin/osdgetexec.c new file mode 100644 index 000000000..4e4961c59 --- /dev/null +++ b/modules/libcom/src/osi/os/Darwin/osdgetexec.c @@ -0,0 +1,50 @@ + +#include +#include + +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + uint32_t max = 64u; + char *ret = NULL; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + /* cf. "man 3 dyld" */ + if(_NSGetExecutablePath(ret, &max)==0) { + /* max left unchanged */ + ret[max-1] = '\0'; + break; + } + /* max has been updated with required size */ + } + + /* TODO: _NSGetExecutablePath() doesn't follow symlinks */ + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/Linux/osdgetexec.c b/modules/libcom/src/osi/os/Linux/osdgetexec.c index 2ea8ca4ae..cba5d78a8 100644 --- a/modules/libcom/src/osi/os/Linux/osdgetexec.c +++ b/modules/libcom/src/osi/os/Linux/osdgetexec.c @@ -24,7 +24,11 @@ char *epicsGetExecName(void) ret = temp; n = readlink("/proc/self/exe", ret, max); - if(n < max) { + if(n == -1) { + free(ret); + ret = NULL; + break; + } else if(n < max) { /* readlink() never adds a nil */ ret[n] = '\0'; break; diff --git a/modules/libcom/src/osi/os/WIN32/osdgetexec.c b/modules/libcom/src/osi/os/WIN32/osdgetexec.c new file mode 100644 index 000000000..a46ce50cd --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdgetexec.c @@ -0,0 +1,52 @@ + +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = 128; + char *ret = NULL; + DWORD n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = GetModuleFileName(NULL, ret, max); + if(n == 0) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + ret[n] = '\0'; + break; + } + + max += 64; + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '\\'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/freebsd/osdgetexec.c b/modules/libcom/src/osi/os/freebsd/osdgetexec.c new file mode 100644 index 000000000..39c0a163d --- /dev/null +++ b/modules/libcom/src/osi/os/freebsd/osdgetexec.c @@ -0,0 +1,68 @@ + +#include +#include +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + size_t max = PATH_MAX; + char *ret = NULL; + ssize_t n; + + while(1) { + char *temp = realloc(ret, max); + if(!temp) { + /* we treat alloc failure as terminal */ + free(ret); + ret = NULL; + break; + } + ret = temp; + + n = readlink("/proc/curproc/file", ret, max); + if(n == -1) { + free(ret); + ret = NULL; + break; + } else if(n < max) { + /* readlink() never adds a nil */ + ret[n] = '\0'; + break; + } + + max += 64; + } + + if(!ret) { + int mib[4]; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PATHNAME; + mib[3] = -1; + + ret = malloc(max); + if(ret) { + sysctl(mib, 4, ret, &cb, NULL, 0); + /* TODO: error check */ + } + } + + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/src/osi/os/solaris/osdgetexec.c b/modules/libcom/src/osi/os/solaris/osdgetexec.c new file mode 100644 index 000000000..ff9739ca9 --- /dev/null +++ b/modules/libcom/src/osi/os/solaris/osdgetexec.c @@ -0,0 +1,30 @@ + +#include +#include + +#define epicsExportSharedSymbols +#include + +char *epicsGetExecName(void) +{ + const char *raw = getexecname(); + char *ret = NULL; + /* manpage says getexecname() might return a relative path. we treat this as an error */ + if(raw[0]=='/') { + ret = strdup(raw); + } + return ret; +} + +char *epicsGetExecDir(void) +{ + char *ret = epicsGetExecName(); + if(ret) { + char *sep = strrchr(ret, '/'); + if(sep) { + /* nil the charactor after the / */ + sep[1] = '\0'; + } + } + return ret; +} diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index 1c26c44b7..7e1ff1abc 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -232,6 +232,11 @@ osiSockTest_SRCS += osiSockTest.c testHarness_SRCS += osiSockTest.c TESTS += osiSockTest +TESTPROD_HOST += testexecname +testexecname_SRCS += testexecname.c +# no point in including in testHarness. Not implemented for RTEMS/vxWorks. +TESTS += testexecname + ifeq ($(BUILD_CLASS),HOST) ifneq ($(OS_CLASS),WIN32) # This test can only be run on a build host, and is broken on Windows diff --git a/modules/libcom/test/testexecname.c b/modules/libcom/test/testexecname.c new file mode 100644 index 000000000..87be847a0 --- /dev/null +++ b/modules/libcom/test/testexecname.c @@ -0,0 +1,24 @@ + +#include + +#include +#include + +#include + +MAIN(testexecname) +{ + testPlan(1); + + { + char *buf = epicsGetExecName(); + if(!buf) { + testSkip(1, "epicsGetExecName() not available for this target"); + } else { + char *loc = strstr(buf, "testexecname"); + testOk(!!loc, "Find \"testexecname\" in \"%s\"", buf); + } + } + + return testDone(); +} From 7bdbded47d78232d7871f523ea0d713c76d4deef Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 20 Nov 2018 21:59:34 -0800 Subject: [PATCH 012/281] travis-ci test rpath $ORIGIN --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d6130c753..e7b1ed57a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ addons: script: - .ci/travis-build.sh env: - - CMPLR=gcc + - CMPLR=gcc EXTRA=LINKER_USE_RPATH=ORIGIN - CMPLR=clang - CMPLR=gcc STATIC=YES - CMPLR=clang STATIC=YES From f5194b2274360cabab8ce9097ed31665f07e4ef4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 13 Dec 2018 11:22:07 -0800 Subject: [PATCH 013/281] older binutils compat --- src/tools/makeRPath.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py index edad80085..5d151a41a 100644 --- a/src/tools/makeRPath.py +++ b/src/tools/makeRPath.py @@ -26,6 +26,10 @@ for path in args.path: if args.root and os.path.relpath(path, args.root).startswith('../'): pass # absolute rpath else: + # some older binutils don't seem to handle $ORIGIN correctly + # when locating dependencies of libraries. So also provide + # the absolute path for internal use by 'ld' only. + output.append('-Wl,-rpath-link,'+path) path = os.path.relpath(path, fdir) output.append('-Wl,-rpath,'+os.path.join(args.origin, path)) From 5087c4cb2f9897828829f5b15076ab29d8106ac3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Dec 2018 20:44:57 -0800 Subject: [PATCH 014/281] monotonic adapt to regular time APIs --- modules/libcom/src/osi/epicsGeneralTime.c | 8 ++++++++ modules/libcom/src/osi/epicsTime.cpp | 7 +++++++ modules/libcom/src/osi/epicsTime.h | 2 ++ 3 files changed, 17 insertions(+) diff --git a/modules/libcom/src/osi/epicsGeneralTime.c b/modules/libcom/src/osi/epicsGeneralTime.c index d08e9c6a9..10854ae55 100644 --- a/modules/libcom/src/osi/epicsGeneralTime.c +++ b/modules/libcom/src/osi/epicsGeneralTime.c @@ -204,6 +204,14 @@ int epicsShareAPI epicsTimeGetCurrent(epicsTimeStamp *pDest) return status; } +int epicsTimeGetMonotonic ( epicsTimeStamp * pDest ) +{ + epicsUInt64 now = epicsMonotonicGet(); + pDest->nsec = now%1000000000ul; + pDest->secPastEpoch = now/1000000000ul; + return 0; +} + int epicsTimeGetCurrentInt(epicsTimeStamp *pDest) { gtProvider *ptp = gtPvt.lastTimeProvider; diff --git a/modules/libcom/src/osi/epicsTime.cpp b/modules/libcom/src/osi/epicsTime.cpp index 6dd1d3f97..ddced3a65 100644 --- a/modules/libcom/src/osi/epicsTime.cpp +++ b/modules/libcom/src/osi/epicsTime.cpp @@ -218,6 +218,13 @@ epicsTime epicsTime::getCurrent () return epicsTime ( current ); } +epicsTime epicsTime::getMonotonic() +{ + epicsTimeStamp current; + epicsTimeGetMonotonic (¤t); // can't fail + return epicsTime ( current ); +} + epicsTime epicsTime::getEvent (const epicsTimeEvent &event) { epicsTimeStamp current; diff --git a/modules/libcom/src/osi/epicsTime.h b/modules/libcom/src/osi/epicsTime.h index 862bc22d2..90ad4e1d0 100644 --- a/modules/libcom/src/osi/epicsTime.h +++ b/modules/libcom/src/osi/epicsTime.h @@ -86,6 +86,7 @@ public: static epicsTime getEvent ( const epicsTimeEvent & ); static epicsTime getCurrent (); + static epicsTime getMonotonic (); /* convert to and from EPICS epicsTimeStamp format */ operator epicsTimeStamp () const; @@ -192,6 +193,7 @@ extern "C" { epicsShareFunc int epicsShareAPI epicsTimeGetCurrent ( epicsTimeStamp * pDest ); epicsShareFunc int epicsShareAPI epicsTimeGetEvent ( epicsTimeStamp *pDest, int eventNumber); +epicsShareFunc int epicsTimeGetMonotonic ( epicsTimeStamp * pDest ); /* These are callable from an Interrupt Service Routine */ epicsShareFunc int epicsTimeGetCurrentInt(epicsTimeStamp *pDest); From 8b9ad212c4eb43dca632bcc08d47677081d6fa70 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Dec 2018 20:45:21 -0800 Subject: [PATCH 015/281] dbScan periodic scan use monotonic time --- modules/database/src/ioc/db/dbScan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/db/dbScan.c b/modules/database/src/ioc/db/dbScan.c index 9224ed504..268e89c49 100644 --- a/modules/database/src/ioc/db/dbScan.c +++ b/modules/database/src/ioc/db/dbScan.c @@ -787,7 +787,7 @@ static void periodicTask(void *arg) taskwdInsert(0, NULL, NULL); epicsEventSignal(startStopEvent); - epicsTimeGetCurrent(&next); + epicsTimeGetMonotonic(&next); reported = next; while (ppsl->scanCtl != ctlExit) { @@ -798,7 +798,7 @@ static void periodicTask(void *arg) scanList(&ppsl->scan_list); epicsTimeAddSeconds(&next, ppsl->period); - epicsTimeGetCurrent(&now); + epicsTimeGetMonotonic(&now); delay = epicsTimeDiffInSeconds(&next, &now); if (delay <= 0.0) { if (overtime == 0.0) { From 4f2228fb1d7527fb5ebc8b2d747c309f1dd7698d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Dec 2018 20:48:58 -0800 Subject: [PATCH 016/281] replace most internal getCurrent() -> getMonotonic() every place where a time delta is computed, and then some. --- modules/ca/src/client/CASG.cpp | 4 ++-- modules/ca/src/client/ca_client_context.cpp | 8 ++++---- modules/ca/src/client/cac.cpp | 2 +- modules/ca/src/client/casw.cpp | 4 ++-- modules/ca/src/client/searchTimer.cpp | 2 +- modules/ca/src/client/tcpiiu.cpp | 4 ++-- modules/ca/src/client/udpiiu.cpp | 2 +- .../database/src/ioc/db/dbPutNotifyBlocker.cpp | 4 ++-- modules/libcom/src/fdmgr/fdManager.cpp | 6 +++--- modules/libcom/src/osi/epicsThread.cpp | 4 ++-- modules/libcom/src/timer/epicsTimer.cpp | 2 +- modules/libcom/src/timer/epicsTimer.h | 2 +- modules/libcom/src/timer/timer.cpp | 6 +++--- modules/libcom/src/timer/timerQueue.cpp | 4 ++-- modules/libcom/src/timer/timerQueueActive.cpp | 4 ++-- modules/libcom/test/cvtFastPerform.cpp | 4 ++-- modules/libcom/test/epicsAtomicPerform.cpp | 12 ++++++------ modules/libcom/test/epicsEventTest.cpp | 4 ++-- modules/libcom/test/epicsMutexTest.cpp | 12 ++++++------ modules/libcom/test/epicsThreadPerform.cpp | 16 ++++++++-------- modules/libcom/test/epicsTimerTest.cpp | 8 ++++---- 21 files changed, 57 insertions(+), 57 deletions(-) diff --git a/modules/ca/src/client/CASG.cpp b/modules/ca/src/client/CASG.cpp index b2dbaac4d..4ffb414c7 100644 --- a/modules/ca/src/client/CASG.cpp +++ b/modules/ca/src/client/CASG.cpp @@ -83,7 +83,7 @@ int CASG::block ( return ECA_TIMEOUT; } - cur_time = epicsTime::getCurrent (); + cur_time = epicsTime::getMonotonic (); this->client.flush ( guard ); @@ -121,7 +121,7 @@ int CASG::block ( /* * force a time update */ - cur_time = epicsTime::getCurrent (); + cur_time = epicsTime::getMonotonic (); delay = cur_time - beg_time; } diff --git a/modules/ca/src/client/ca_client_context.cpp b/modules/ca/src/client/ca_client_context.cpp index 2bb3e24a8..3305e8d3e 100644 --- a/modules/ca/src/client/ca_client_context.cpp +++ b/modules/ca/src/client/ca_client_context.cpp @@ -481,7 +481,7 @@ int ca_client_context::pendIO ( const double & timeout ) } int status = ECA_NORMAL; - epicsTime beg_time = epicsTime::getCurrent (); + epicsTime beg_time = epicsTime::getMonotonic (); double remaining = timeout; epicsGuard < epicsMutex > guard ( this->mutex ); @@ -499,7 +499,7 @@ int ca_client_context::pendIO ( const double & timeout ) this->blockForEventAndEnableCallbacks ( this->ioDone, remaining ); } - double delay = epicsTime::getCurrent () - beg_time; + double delay = epicsTime::getMonotonic () - beg_time; if ( delay < timeout ) { remaining = timeout - delay; } @@ -528,7 +528,7 @@ int ca_client_context::pendEvent ( const double & timeout ) return ECA_EVDISALLOW; } - epicsTime current = epicsTime::getCurrent (); + epicsTime current = epicsTime::getMonotonic (); { epicsGuard < epicsMutex > guard ( this->mutex ); @@ -569,7 +569,7 @@ int ca_client_context::pendEvent ( const double & timeout ) this->noWakeupSincePend = true; } - double elapsed = epicsTime::getCurrent() - current; + double elapsed = epicsTime::getMonotonic() - current; double delay; if ( timeout > elapsed ) { diff --git a/modules/ca/src/client/cac.cpp b/modules/ca/src/client/cac.cpp index 5748353bd..485b83d89 100644 --- a/modules/ca/src/client/cac.cpp +++ b/modules/ca/src/client/cac.cpp @@ -130,7 +130,7 @@ cac::cac ( epicsMutex & callbackControlIn, cacContextNotify & notifyIn ) : _refLocalHostName ( localHostNameCache.getReference () ), - programBeginTime ( epicsTime::getCurrent() ), + programBeginTime ( epicsTime::getMonotonic() ), connTMO ( CA_CONN_VERIFY_PERIOD ), mutex ( mutualExclusionIn ), cbMutex ( callbackControlIn ), diff --git a/modules/ca/src/client/casw.cpp b/modules/ca/src/client/casw.cpp index f69632c13..bdb08e04d 100644 --- a/modules/ca/src/client/casw.cpp +++ b/modules/ca/src/client/casw.cpp @@ -59,7 +59,7 @@ int main ( int argc, char ** argv ) epicsMutex mutex; epicsGuard < epicsMutex > guard ( mutex ); bheFreeStoreMgr bheFreeList; - epicsTime programBeginTime = epicsTime::getCurrent (); + epicsTime programBeginTime = epicsTime::getMonotonic (); bool validCommandLine = false; unsigned interest = 0u; SOCKET sock; @@ -244,7 +244,7 @@ int main ( int argc, char ** argv ) ca_uint32_t beaconNumber = ntohl ( pCurMsg->m_cid ); unsigned protocolRevision = ntohs ( pCurMsg->m_dataType ); - epicsTime currentTime = epicsTime::getCurrent(); + epicsTime currentTime = epicsTime::getMonotonic(); /* * look for it in the hash table diff --git a/modules/ca/src/client/searchTimer.cpp b/modules/ca/src/client/searchTimer.cpp index e55e49eab..bb9b9a91c 100644 --- a/modules/ca/src/client/searchTimer.cpp +++ b/modules/ca/src/client/searchTimer.cpp @@ -43,7 +43,7 @@ searchTimer::searchTimer ( const unsigned indexIn, epicsMutex & mutexIn, bool boostPossibleIn ) : - timeAtLastSend ( epicsTime::getCurrent () ), + timeAtLastSend ( epicsTime::getMonotonic () ), timer ( queueIn.createTimer () ), iiu ( iiuIn ), mutex ( mutexIn ), diff --git a/modules/ca/src/client/tcpiiu.cpp b/modules/ca/src/client/tcpiiu.cpp index 045f8d57e..9d174ab84 100644 --- a/modules/ca/src/client/tcpiiu.cpp +++ b/modules/ca/src/client/tcpiiu.cpp @@ -476,7 +476,7 @@ void tcpRecvThread::run () statusWireIO stat; pComBuf->fillFromWire ( this->iiu, stat ); - epicsTime currentTime = epicsTime::getCurrent (); + epicsTime currentTime = epicsTime::getMonotonic (); { epicsGuard < epicsMutex > guard ( this->iiu.mutex ); @@ -1669,7 +1669,7 @@ bool tcpiiu::sendThreadFlush ( epicsGuard < epicsMutex > & guard ) if ( this->sendQue.occupiedBytes() > 0 ) { while ( comBuf * pBuf = this->sendQue.popNextComBufToSend () ) { - epicsTime current = epicsTime::getCurrent (); + epicsTime current = epicsTime::getMonotonic (); unsigned bytesToBeSent = pBuf->occupiedBytes (); bool success = false; diff --git a/modules/ca/src/client/udpiiu.cpp b/modules/ca/src/client/udpiiu.cpp index 1bcb03716..c378881f7 100644 --- a/modules/ca/src/client/udpiiu.cpp +++ b/modules/ca/src/client/udpiiu.cpp @@ -435,7 +435,7 @@ void udpRecvThread::run () } else if ( status > 0 ) { this->iiu.postMsg ( src, this->iiu.recvBuf, - (arrayElementCount) status, epicsTime::getCurrent() ); + (arrayElementCount) status, epicsTime::getMonotonic() ); } } while ( ! this->iiu.shutdownCmd ); diff --git a/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp b/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp index 1a796cdbd..2215f8468 100644 --- a/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp +++ b/modules/database/src/ioc/db/dbPutNotifyBlocker.cpp @@ -144,12 +144,12 @@ void dbPutNotifyBlocker::initiatePutNotify ( break; } if ( beginTimeInit ) { - if ( epicsTime::getCurrent () - begin > 30.0 ) { + if ( epicsTime::getMonotonic () - begin > 30.0 ) { throw cacChannel::requestTimedOut (); } } else { - begin = epicsTime::getCurrent (); + begin = epicsTime::getMonotonic (); beginTimeInit = true; } { diff --git a/modules/libcom/src/fdmgr/fdManager.cpp b/modules/libcom/src/fdmgr/fdManager.cpp index 00f4d4a87..f43fab25d 100644 --- a/modules/libcom/src/fdmgr/fdManager.cpp +++ b/modules/libcom/src/fdmgr/fdManager.cpp @@ -97,7 +97,7 @@ epicsShareFunc void fdManager::process (double delay) // more than once here so that fd activity get serviced // in a reasonable length of time. // - double minDelay = this->pTimerQueue->process(epicsTime::getCurrent()); + double minDelay = this->pTimerQueue->process(epicsTime::getMonotonic()); if ( minDelay >= delay ) { minDelay = delay; @@ -121,7 +121,7 @@ epicsShareFunc void fdManager::process (double delay) fd_set * pExceptSet = & this->fdSetsPtr[fdrException]; int status = select (this->maxFD, pReadSet, pWriteSet, pExceptSet, &tv); - this->pTimerQueue->process(epicsTime::getCurrent()); + this->pTimerQueue->process(epicsTime::getMonotonic()); if ( status > 0 ) { @@ -204,7 +204,7 @@ epicsShareFunc void fdManager::process (double delay) * of select() */ epicsThreadSleep(minDelay); - this->pTimerQueue->process(epicsTime::getCurrent()); + this->pTimerQueue->process(epicsTime::getMonotonic()); } this->processInProg = false; return; diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 892d73de0..da7116476 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -143,7 +143,7 @@ bool epicsThread::exitWait ( const double delay ) throw () } return true; } - epicsTime exitWaitBegin = epicsTime::getCurrent (); + epicsTime exitWaitBegin = epicsTime::getMonotonic (); double exitWaitElapsed = 0.0; epicsGuard < epicsMutex > guard ( this->mutex ); this->cancel = true; @@ -151,7 +151,7 @@ bool epicsThread::exitWait ( const double delay ) throw () epicsGuardRelease < epicsMutex > unguard ( guard ); this->event.signal (); this->exitEvent.wait ( delay - exitWaitElapsed ); - epicsTime current = epicsTime::getCurrent (); + epicsTime current = epicsTime::getMonotonic (); exitWaitElapsed = current - exitWaitBegin; } } diff --git a/modules/libcom/src/timer/epicsTimer.cpp b/modules/libcom/src/timer/epicsTimer.cpp index e55280e7e..15bebef7f 100644 --- a/modules/libcom/src/timer/epicsTimer.cpp +++ b/modules/libcom/src/timer/epicsTimer.cpp @@ -173,7 +173,7 @@ extern "C" double epicsShareAPI epicsTimerQueuePassiveProcess ( epicsTimerQueuePassiveId pQueue ) { try { - return pQueue->process ( epicsTime::getCurrent() ); + return pQueue->process ( epicsTime::getMonotonic() ); } catch ( ... ) { return 1.0; diff --git a/modules/libcom/src/timer/epicsTimer.h b/modules/libcom/src/timer/epicsTimer.h index 72270f273..6e054ed4f 100644 --- a/modules/libcom/src/timer/epicsTimer.h +++ b/modules/libcom/src/timer/epicsTimer.h @@ -118,7 +118,7 @@ inline double epicsTimer::getExpireDelay () { epicsTimer::expireInfo info = this->getExpireInfo (); if ( info.active ) { - double delay = info.expireTime - epicsTime::getCurrent (); + double delay = info.expireTime - epicsTime::getMonotonic (); if ( delay < 0.0 ) { delay = 0.0; } diff --git a/modules/libcom/src/timer/timer.cpp b/modules/libcom/src/timer/timer.cpp index 35d6e47bf..6f0c7ea4a 100644 --- a/modules/libcom/src/timer/timer.cpp +++ b/modules/libcom/src/timer/timer.cpp @@ -54,7 +54,7 @@ void timer::destroy () void timer::start ( epicsTimerNotify & notify, double delaySeconds ) { - this->start ( notify, epicsTime::getCurrent () + delaySeconds ); + this->start ( notify, epicsTime::getMonotonic () + delaySeconds ); } void timer::start ( epicsTimerNotify & notify, const epicsTime & expire ) @@ -129,7 +129,7 @@ void timer::privateStart ( epicsTimerNotify & notify, const epicsTime & expire ) debugPrintf ( ("Start of \"%s\" with delay %f at %p preempting %u\n", typeid ( this->notify ).name (), - expire - epicsTime::getCurrent (), + expire - epicsTime::getMonotonic (), this, preemptCount ) ); } @@ -190,7 +190,7 @@ void timer::show ( unsigned int level ) const double delay; if ( this->curState == statePending || this->curState == stateActive ) { try { - delay = this->exp - epicsTime::getCurrent(); + delay = this->exp - epicsTime::getMonotonic(); } catch ( ... ) { delay = - DBL_MAX; diff --git a/modules/libcom/src/timer/timerQueue.cpp b/modules/libcom/src/timer/timerQueue.cpp index 5a798d4d4..d209bcbee 100644 --- a/modules/libcom/src/timer/timerQueue.cpp +++ b/modules/libcom/src/timer/timerQueue.cpp @@ -29,7 +29,7 @@ timerQueue::timerQueue ( epicsTimerQueueNotify & notifyIn ) : pExpireTmr ( 0 ), processThread ( 0 ), exceptMsgTimeStamp ( - epicsTime :: getCurrent () - exceptMsgMinPeriod ), + epicsTime :: getMonotonic () - exceptMsgMinPeriod ), cancelPending ( false ) { } @@ -48,7 +48,7 @@ void timerQueue :: char date[64]; double delay; try { - epicsTime cur = epicsTime :: getCurrent (); + epicsTime cur = epicsTime :: getMonotonic (); delay = cur - this->exceptMsgTimeStamp; cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f" ); diff --git a/modules/libcom/src/timer/timerQueueActive.cpp b/modules/libcom/src/timer/timerQueueActive.cpp index 5d8b72951..3611f1ad1 100644 --- a/modules/libcom/src/timer/timerQueueActive.cpp +++ b/modules/libcom/src/timer/timerQueueActive.cpp @@ -72,7 +72,7 @@ void timerQueueActive :: _printLastChanceExceptionMessage ( { char date[64]; try { - epicsTime cur = epicsTime :: getCurrent (); + epicsTime cur = epicsTime :: getMonotonic (); cur.strftime ( date, sizeof ( date ), "%a %b %d %Y %H:%M:%S.%f"); } catch ( ... ) { @@ -90,7 +90,7 @@ void timerQueueActive :: run () this->exitFlag = false; while ( ! this->terminateFlag ) { try { - double delay = this->queue.process ( epicsTime::getCurrent() ); + double delay = this->queue.process ( epicsTime::getMonotonic() ); debugPrintf ( ( "timer thread sleeping for %g sec (max)\n", delay ) ); this->rescheduleEvent.wait ( delay ); } diff --git a/modules/libcom/test/cvtFastPerform.cpp b/modules/libcom/test/cvtFastPerform.cpp index c3f99dc61..28c831349 100644 --- a/modules/libcom/test/cvtFastPerform.cpp +++ b/modules/libcom/test/cvtFastPerform.cpp @@ -147,11 +147,11 @@ void Perf :: measure (double srcD, float srcF, int prec) std::memset(buf, 0, sizeof(buf)); - epicsTime beg = epicsTime :: getCurrent (); + epicsTime beg = epicsTime :: getMonotonic (); for ( unsigned i = 0; i < nIterations; i++ ) { c->target (srcD, srcF, buf, sizeof(buf) - 1, prec); } - epicsTime end = epicsTime :: getCurrent (); + epicsTime end = epicsTime :: getMonotonic (); double elapsed = end - beg; elapsed /= nIterations * nUnrolled; diff --git a/modules/libcom/test/epicsAtomicPerform.cpp b/modules/libcom/test/epicsAtomicPerform.cpp index 2ef005efe..98eaf1778 100644 --- a/modules/libcom/test/epicsAtomicPerform.cpp +++ b/modules/libcom/test/epicsAtomicPerform.cpp @@ -394,12 +394,12 @@ static const unsigned N = 10000; void recursiveOwnershipRetPerformance () { RefCtr refCtr; - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); for ( size_t i = 0; i < N; i++ ) { Ownership ownership ( refCtr ); recurRetOwner1000 ( ownership ); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= N * 1000u; // convert to delay per call delay *= 1e6; // convert to micro seconds testDiag ( "retOwnership() takes %f microseconds", delay ); @@ -408,13 +408,13 @@ void recursiveOwnershipRetPerformance () void ownershipPassRefPerformance () { RefCtr refCtr; - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); for ( size_t i = 0; i < N; i++ ) { Ownership ownershipSrc ( refCtr ); Ownership ownershipDest; passRefOwnership1000 ( ownershipSrc, ownershipDest ); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= N * 1000u; // convert to delay per call delay *= 1e6; // convert to micro seconds testDiag ( "passRefOwnership() takes %f microseconds", delay ); @@ -456,7 +456,7 @@ void Ten < T > :: diagnostic ( double delay ) template < class T > void measurePerformance () { - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); T target; for ( size_t i = 0; i < N; i++ ) { target.run (); @@ -470,7 +470,7 @@ void measurePerformance () target.run (); target.run (); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= ( N * 10u ); // convert to delay per call target.diagnostic ( delay ); } diff --git a/modules/libcom/test/epicsEventTest.cpp b/modules/libcom/test/epicsEventTest.cpp index 7c1a24141..b3e48f8f2 100644 --- a/modules/libcom/test/epicsEventTest.cpp +++ b/modules/libcom/test/epicsEventTest.cpp @@ -156,9 +156,9 @@ static void eventWakeupTest(void) static double eventWaitMeasureDelayError( const epicsEventId &id, const double & delay ) { - epicsTime beg = epicsTime::getCurrent(); + epicsTime beg = epicsTime::getMonotonic(); epicsEventWaitWithTimeout ( id, delay ); - epicsTime end = epicsTime::getCurrent(); + epicsTime end = epicsTime::getMonotonic(); double meas = end - beg; double error = fabs ( delay - meas ); testDiag("epicsEventWaitWithTimeout(%.6f) delay error %.6f sec", diff --git a/modules/libcom/test/epicsMutexTest.cpp b/modules/libcom/test/epicsMutexTest.cpp index d44e5c0f1..e3ad5868f 100644 --- a/modules/libcom/test/epicsMutexTest.cpp +++ b/modules/libcom/test/epicsMutexTest.cpp @@ -168,32 +168,32 @@ void epicsMutexPerformance () unsigned i; // test a single lock pair - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); static const unsigned N = 1000; for ( i = 0; i < N; i++ ) { tenLockPairsSquared ( mutex ); } - double delay = epicsTime::getCurrent () - begin; + double delay = epicsTime::getMonotonic () - begin; delay /= N * 100u; // convert to delay per lock pair delay *= 1e6; // convert to micro seconds testDiag("lock()*1/unlock()*1 takes %f microseconds", delay); // test a two times recursive lock pair - begin = epicsTime::getCurrent (); + begin = epicsTime::getMonotonic (); for ( i = 0; i < N; i++ ) { tenDoubleRecursiveLockPairsSquared ( mutex ); } - delay = epicsTime::getCurrent () - begin; + delay = epicsTime::getMonotonic () - begin; delay /= N * 100u; // convert to delay per lock pair delay *= 1e6; // convert to micro seconds testDiag("lock()*2/unlock()*2 takes %f microseconds", delay); // test a four times recursive lock pair - begin = epicsTime::getCurrent (); + begin = epicsTime::getMonotonic (); for ( i = 0; i < N; i++ ) { tenQuadRecursiveLockPairsSquared ( mutex ); } - delay = epicsTime::getCurrent () - begin; + delay = epicsTime::getMonotonic () - begin; delay /= N * 100u; // convert to delay per lock pair delay *= 1e6; // convert to micro seconds testDiag("lock()*4/unlock()*4 takes %f microseconds", delay); diff --git a/modules/libcom/test/epicsThreadPerform.cpp b/modules/libcom/test/epicsThreadPerform.cpp index c8fd34515..b73d90c9e 100644 --- a/modules/libcom/test/epicsThreadPerform.cpp +++ b/modules/libcom/test/epicsThreadPerform.cpp @@ -55,9 +55,9 @@ static void epicsThreadPriorityTest() static double threadSleepMeasureDelayError ( const double & delay ) { - epicsTime beg = epicsTime::getCurrent(); + epicsTime beg = epicsTime::getMonotonic(); epicsThreadSleep ( delay ); - epicsTime end = epicsTime::getCurrent(); + epicsTime end = epicsTime::getMonotonic(); double meas = end - beg; double error = fabs ( delay - meas ); return error; @@ -76,10 +76,10 @@ static double measureSleepQuantum ( double interval = rand (); interval /= RAND_MAX; interval *= testInterval; - epicsTime start = epicsTime::getCurrent (); + epicsTime start = epicsTime::getMonotonic (); epicsTime current = start; while ( current - start < interval ) { - current = epicsTime::getCurrent (); + current = epicsTime::getMonotonic (); } errorSum += threadSleepMeasureDelayError ( testInterval ); if ( i % ( iterations / 10 ) == 0 ) { @@ -150,7 +150,7 @@ static void epicsThreadGetIdSelfPerfTest () { static const unsigned N = 10000; static const double microSecPerSec = 1e6; - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); for ( unsigned i = 0u; i < N; i++ ) { epicsThreadGetIdSelf (); epicsThreadGetIdSelf (); @@ -164,7 +164,7 @@ static void epicsThreadGetIdSelfPerfTest () epicsThreadGetIdSelf (); epicsThreadGetIdSelf (); }; - epicsTime end = epicsTime::getCurrent (); + epicsTime end = epicsTime::getMonotonic (); printf ( "It takes %f micro sec to call epicsThreadGetIdSelf ()\n", microSecPerSec * ( end - begin ) / (10 * N) ); } @@ -204,12 +204,12 @@ static void timeEpicsThreadPrivateGet () { priv.set ( 0 ); - epicsTime begin = epicsTime::getCurrent (); + epicsTime begin = epicsTime::getMonotonic (); static const unsigned N = 1000u; for ( unsigned i = 0u; i < N; i++ ) { callItTenTimesSquared (); } - double delay = epicsTime::getCurrent() - begin; + double delay = epicsTime::getMonotonic() - begin; delay /= N * 100u; // convert to sec per call delay *= 1e6; // convert to micro sec printf("epicsThreadPrivateGet() takes %f microseconds\n", delay); diff --git a/modules/libcom/test/epicsTimerTest.cpp b/modules/libcom/test/epicsTimerTest.cpp index f2a510819..55ce82eeb 100644 --- a/modules/libcom/test/epicsTimerTest.cpp +++ b/modules/libcom/test/epicsTimerTest.cpp @@ -156,7 +156,7 @@ void testAccuracy () expireCount = nTimers; for ( i = 0u; i < nTimers; i++ ) { - epicsTime cur = epicsTime::getCurrent (); + epicsTime cur = epicsTime::getMonotonic (); pTimers[i]->setBegin ( cur ); pTimers[i]->start ( cur + pTimers[i]->delay () ); } @@ -253,7 +253,7 @@ void testCancel () testDiag ( "cancelCount = %u", cancelVerify::cancelCount ); testDiag ( "starting %d timers", nTimers ); - epicsTime exp = epicsTime::getCurrent () + 4.0; + epicsTime exp = epicsTime::getMonotonic () + 4.0; for ( i = 0u; i < nTimers; i++ ) { pTimers[i]->start ( exp ); } @@ -339,7 +339,7 @@ void testExpireDestroy () testOk1 ( expireDestroyVerify::destroyCount == 0 ); testDiag ( "starting %d timers", nTimers ); - epicsTime cur = epicsTime::getCurrent (); + epicsTime cur = epicsTime::getMonotonic (); for ( i = 0u; i < nTimers; i++ ) { pTimers[i]->start ( cur ); } @@ -432,7 +432,7 @@ void testPeriodic () testOk1 ( timerCount == nTimers ); testDiag ( "starting %d timers", nTimers ); - epicsTime cur = epicsTime::getCurrent (); + epicsTime cur = epicsTime::getMonotonic (); for ( i = 0u; i < nTimers; i++ ) { pTimers[i]->start ( cur ); } From 49b323b93c4aba4dbdc5d49094eaea56db876b7a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 5 Nov 2018 15:57:55 -0800 Subject: [PATCH 017/281] avoided embedded TOP for non sub-modules --- .../configure => configure}/CONFIG_CA_MODULE | 0 .../configure => configure}/CONFIG_CA_VERSION | 0 .../CONFIG_DATABASE_MODULE | 0 .../CONFIG_DATABASE_VERSION | 0 .../CONFIG_LIBCOM_MODULE | 0 .../CONFIG_LIBCOM_VERSION | 0 configure/Makefile | 9 ++ modules/Makefile | 8 +- modules/ca/.ci/travis-build.sh | 21 --- modules/ca/.ci/travis-prepare.sh | 132 ----------------- modules/ca/.travis.yml | 26 ---- modules/ca/Makefile | 6 +- modules/ca/configure/CONFIG | 28 ---- modules/ca/configure/CONFIG_SITE | 42 ------ modules/ca/configure/Makefile | 15 -- modules/ca/configure/RELEASE | 39 ----- modules/ca/configure/RULES | 6 - modules/ca/configure/RULES_DIRS | 2 - modules/ca/configure/RULES_TOP | 2 - modules/ca/src/Makefile | 2 +- modules/ca/src/client/Makefile | 6 +- modules/ca/src/perl/Makefile | 2 +- modules/ca/src/template/Makefile | 2 +- modules/ca/src/tools/Makefile | 2 +- modules/database/.ci/travis-build.sh | 21 --- modules/database/.ci/travis-prepare.sh | 133 ------------------ modules/database/.travis.yml | 26 ---- modules/database/Makefile | 5 +- modules/database/configure/CONFIG | 36 ----- modules/database/configure/CONFIG_SITE | 42 ------ modules/database/configure/Makefile | 15 -- modules/database/configure/RELEASE | 40 ------ modules/database/configure/RULES | 6 - modules/database/configure/RULES.ioc | 2 - modules/database/configure/RULES_DIRS | 2 - modules/database/configure/RULES_TOP | 2 - modules/database/src/Makefile | 2 +- modules/database/src/ioc/Makefile | 8 +- modules/database/src/std/Makefile | 8 +- modules/database/src/template/Makefile | 2 +- modules/database/src/tools/Makefile | 2 +- modules/database/test/Makefile | 2 +- modules/database/test/ioc/db/Makefile | 7 +- modules/database/test/ioc/dbtemplate/Makefile | 2 +- modules/database/test/std/filters/Makefile | 4 +- modules/database/test/std/link/Makefile | 2 + modules/database/test/std/rec/Makefile | 4 +- modules/database/test/tools/Makefile | 2 +- modules/libcom/.ci/travis-build.sh | 21 --- modules/libcom/.ci/travis-prepare.sh | 123 ---------------- modules/libcom/.travis.yml | 26 ---- modules/libcom/Makefile | 7 +- modules/libcom/RTEMS/Makefile | 2 +- modules/libcom/configure/CONFIG | 44 ------ modules/libcom/configure/CONFIG_SITE | 42 ------ modules/libcom/configure/Makefile | 15 -- modules/libcom/configure/RELEASE | 38 ----- modules/libcom/configure/RULES | 6 - modules/libcom/configure/RULES_DIRS | 2 - modules/libcom/configure/RULES_TOP | 2 - modules/libcom/src/Makefile | 6 +- modules/libcom/test/Makefile | 2 +- modules/libcom/vxWorks/Makefile | 2 +- 63 files changed, 60 insertions(+), 1003 deletions(-) rename {modules/ca/configure => configure}/CONFIG_CA_MODULE (100%) rename {modules/ca/configure => configure}/CONFIG_CA_VERSION (100%) rename {modules/database/configure => configure}/CONFIG_DATABASE_MODULE (100%) rename {modules/database/configure => configure}/CONFIG_DATABASE_VERSION (100%) rename {modules/libcom/configure => configure}/CONFIG_LIBCOM_MODULE (100%) rename {modules/libcom/configure => configure}/CONFIG_LIBCOM_VERSION (100%) delete mode 100755 modules/ca/.ci/travis-build.sh delete mode 100755 modules/ca/.ci/travis-prepare.sh delete mode 100644 modules/ca/.travis.yml delete mode 100644 modules/ca/configure/CONFIG delete mode 100644 modules/ca/configure/CONFIG_SITE delete mode 100644 modules/ca/configure/Makefile delete mode 100644 modules/ca/configure/RELEASE delete mode 100644 modules/ca/configure/RULES delete mode 100644 modules/ca/configure/RULES_DIRS delete mode 100644 modules/ca/configure/RULES_TOP delete mode 100755 modules/database/.ci/travis-build.sh delete mode 100755 modules/database/.ci/travis-prepare.sh delete mode 100644 modules/database/.travis.yml delete mode 100644 modules/database/configure/CONFIG delete mode 100644 modules/database/configure/CONFIG_SITE delete mode 100644 modules/database/configure/Makefile delete mode 100644 modules/database/configure/RELEASE delete mode 100644 modules/database/configure/RULES delete mode 100644 modules/database/configure/RULES.ioc delete mode 100644 modules/database/configure/RULES_DIRS delete mode 100644 modules/database/configure/RULES_TOP delete mode 100755 modules/libcom/.ci/travis-build.sh delete mode 100755 modules/libcom/.ci/travis-prepare.sh delete mode 100644 modules/libcom/.travis.yml delete mode 100644 modules/libcom/configure/CONFIG delete mode 100644 modules/libcom/configure/CONFIG_SITE delete mode 100644 modules/libcom/configure/Makefile delete mode 100644 modules/libcom/configure/RELEASE delete mode 100644 modules/libcom/configure/RULES delete mode 100644 modules/libcom/configure/RULES_DIRS delete mode 100644 modules/libcom/configure/RULES_TOP diff --git a/modules/ca/configure/CONFIG_CA_MODULE b/configure/CONFIG_CA_MODULE similarity index 100% rename from modules/ca/configure/CONFIG_CA_MODULE rename to configure/CONFIG_CA_MODULE diff --git a/modules/ca/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION similarity index 100% rename from modules/ca/configure/CONFIG_CA_VERSION rename to configure/CONFIG_CA_VERSION diff --git a/modules/database/configure/CONFIG_DATABASE_MODULE b/configure/CONFIG_DATABASE_MODULE similarity index 100% rename from modules/database/configure/CONFIG_DATABASE_MODULE rename to configure/CONFIG_DATABASE_MODULE diff --git a/modules/database/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION similarity index 100% rename from modules/database/configure/CONFIG_DATABASE_VERSION rename to configure/CONFIG_DATABASE_VERSION diff --git a/modules/libcom/configure/CONFIG_LIBCOM_MODULE b/configure/CONFIG_LIBCOM_MODULE similarity index 100% rename from modules/libcom/configure/CONFIG_LIBCOM_MODULE rename to configure/CONFIG_LIBCOM_MODULE diff --git a/modules/libcom/configure/CONFIG_LIBCOM_VERSION b/configure/CONFIG_LIBCOM_VERSION similarity index 100% rename from modules/libcom/configure/CONFIG_LIBCOM_VERSION rename to configure/CONFIG_LIBCOM_VERSION diff --git a/configure/Makefile b/configure/Makefile index 377879766..f48278dd3 100644 --- a/configure/Makefile +++ b/configure/Makefile @@ -20,5 +20,14 @@ CONFIGS += $(subst ../,,$(wildcard ../os/CONFIG*)) CONFIGS += $(subst ../,,$(wildcard ../RELEASE*)) CONFIGS += $(subst ../,,$(wildcard ../RULES*)) +CFG += CONFIG_LIBCOM_MODULE +CFG += CONFIG_LIBCOM_VERSION + +CFG += CONFIG_CA_MODULE +CFG += CONFIG_CA_VERSION + +CFG += CONFIG_DATABASE_MODULE +CFG += CONFIG_DATABASE_VERSION + include $(TOP)/configure/RULES diff --git a/modules/Makefile b/modules/Makefile index 214e914f1..e1ce468c4 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -6,15 +6,15 @@ TOP = .. include $(TOP)/configure/CONFIG -# Submodules for bundle build -SUBMODULES += libcom +DIRS += libcom -SUBMODULES += ca +DIRS += ca ca_DEPEND_DIRS = libcom -SUBMODULES += database +DIRS += database database_DEPEND_DIRS = ca +# Submodules for bundle build SUBMODULES += pvData pvData_DEPEND_DIRS = libcom diff --git a/modules/ca/.ci/travis-build.sh b/modules/ca/.ci/travis-build.sh deleted file mode 100755 index 622979b9d..000000000 --- a/modules/ca/.ci/travis-build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -x - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 $EXTRA - -if [ "$TEST" != "NO" ] -then - make -j2 tapfiles - make -s test-results -fi diff --git a/modules/ca/.ci/travis-prepare.sh b/modules/ca/.ci/travis-prepare.sh deleted file mode 100755 index 85dc8d7ce..000000000 --- a/modules/ca/.ci/travis-prepare.sh +++ /dev/null @@ -1,132 +0,0 @@ -#!/bin/sh -set -e -x - -CURDIR="$PWD" - -QDIR="$HOME/.cache/qemu" - -if [ -n "$RTEMS" -a "$TEST" = "YES" ] -then - git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu" - cd "$HOME/.build/qemu" - - HEAD=`git log -n1 --pretty=format:%H` - echo "HEAD revision $HEAD" - - [ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"` - echo "Cached revision $BUILT" - - if [ "$HEAD" != "$BUILT" ] - then - echo "Building QEMU" - git submodule --quiet update --init - - install -d "$HOME/.build/qemu/build" - cd "$HOME/.build/qemu/build" - - "$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror - make -j2 - make install - - echo "$HEAD" > "$HOME/.cache/qemu/built" - fi -fi - -cd "$CURDIR" - -cat << EOF > configure/RELEASE.local -EPICS_BASE=$HOME/.source/epics-base -EOF - -install -d "$HOME/.source" -cd "$HOME/.source" - -add_base_module() { - MODULE=$1 - BRANCH=$2 - ( cd epics-base/modules && \ - git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \ - cd "$MODULE" && git log -n1 ) -} - -git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base -( cd epics-base && git log -n1 ) -add_base_module libcom "${BRLIBCOM:-master}" - -EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch` - -# requires wine and g++-mingw-w64-i686 -if [ "$WINE" = "32" ] -then - echo "Cross mingw32" - sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw - cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw -CMPLR_PREFIX=i686-w64-mingw32- -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw -EOF -fi - -if [ "$STATIC" = "YES" ] -then - echo "Build static libraries/executables" - cat << EOF >> epics-base/configure/CONFIG_SITE -SHARED_LIBRARIES=NO -STATIC_BUILD=YES -EOF -fi - -case "$CMPLR" in -clang) - echo "Host compiler is clang" - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH -GNU = NO -CMPLR_CLASS = clang -CC = clang -CCC = clang++ -EOF - - # hack - sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon - - clang --version - ;; -*) - echo "Host compiler is default" - gcc --version - ;; -esac - -cat <> epics-base/configure/CONFIG_SITE -USR_CPPFLAGS += $USR_CPPFLAGS -USR_CFLAGS += $USR_CFLAGS -USR_CXXFLAGS += $USR_CXXFLAGS -EOF - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - echo "Cross RTEMS${RTEMS} for pc386" - install -d /home/travis/.cache - curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ - | tar -C /home/travis/.cache -xj - - sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS -RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 -EOF - - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 -C epics-base $EXTRA diff --git a/modules/ca/.travis.yml b/modules/ca/.travis.yml deleted file mode 100644 index 5a99b886a..000000000 --- a/modules/ca/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -dist: trusty -language: c -compiler: - - gcc -addons: - apt: - packages: - - libreadline6-dev - - libncurses5-dev - - perl - - clang - - g++-mingw-w64-i686 -install: - - ./.ci/travis-prepare.sh -script: - - ./.ci/travis-build.sh -env: - - BRCORE=master BRLIBCOM=master TEST=NO - - CMPLR=clang TEST=NO - - USR_CXXFLAGS=-std=c++11 TEST=NO - - CMPLR=clang USR_CXXFLAGS=-std=c++11 TEST=NO - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO diff --git a/modules/ca/Makefile b/modules/ca/Makefile index 13feff6c2..eeb147b07 100644 --- a/modules/ca/Makefile +++ b/modules/ca/Makefile @@ -7,11 +7,9 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = . +TOP = ../.. include $(TOP)/configure/CONFIG -DIRS += configure src - -src_DEPEND_DIRS = configure +DIRS += src include $(TOP)/configure/RULES_TOP diff --git a/modules/ca/configure/CONFIG b/modules/ca/configure/CONFIG deleted file mode 100644 index 331fd7024..000000000 --- a/modules/ca/configure/CONFIG +++ /dev/null @@ -1,28 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif diff --git a/modules/ca/configure/CONFIG_SITE b/modules/ca/configure/CONFIG_SITE deleted file mode 100644 index d78c7f514..000000000 --- a/modules/ca/configure/CONFIG_SITE +++ /dev/null @@ -1,42 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local diff --git a/modules/ca/configure/Makefile b/modules/ca/configure/Makefile deleted file mode 100644 index e2f373893..000000000 --- a/modules/ca/configure/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -#************************************************************************* -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -TOP = .. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -CFG += CONFIG_CA_MODULE -CFG += CONFIG_CA_VERSION - -include $(TOP)/configure/RULES diff --git a/modules/ca/configure/RELEASE b/modules/ca/configure/RELEASE deleted file mode 100644 index a2d9f554a..000000000 --- a/modules/ca/configure/RELEASE +++ /dev/null @@ -1,39 +0,0 @@ -# RELEASE - Location of external support modules -# -# IF YOU CHANGE ANY PATHS in this file or make API changes to -# any modules it refers to, you should do a "make rebuild" in -# this application's top level directory. -# -# The EPICS build process does not check dependencies against -# any files from outside the application, so it is safest to -# rebuild it completely if any modules it depends on change. -# -# Host- or target-specific settings can be given in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) -# -# This file is parsed by both GNUmake and an EPICS Perl script, -# so it may ONLY contain definititions of paths to other support -# modules, variable definitions that are used in module paths, -# and include statements that pull in other RELEASE files. -# Variables may be used before their values have been set. -# Build variables that are NOT used in paths should be set in -# the CONFIG_SITE file. - -# Variables and paths to dependent modules: -#MODULES = /path/to/modules -#MYMODULE = $(MODULES)/my-module - -# If building the EPICS modules individually, set these: -#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0 -#EPICS_BASE = $(MODULES)/core-7.0.1 - -# Set RULES here if you want to use build rules from elsewhere: -#RULES = $(MODULES)/build-rules - -# These lines allow developers to override these RELEASE settings -# without having to modify this file directly. --include $(TOP)/../RELEASE.local --include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local --include $(TOP)/configure/RELEASE.local diff --git a/modules/ca/configure/RULES b/modules/ca/configure/RULES deleted file mode 100644 index 6d56e14e8..000000000 --- a/modules/ca/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/modules/ca/configure/RULES_DIRS b/modules/ca/configure/RULES_DIRS deleted file mode 100644 index 3ba269dcc..000000000 --- a/modules/ca/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/modules/ca/configure/RULES_TOP b/modules/ca/configure/RULES_TOP deleted file mode 100644 index 2b8cbc6da..000000000 --- a/modules/ca/configure/RULES_TOP +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP diff --git a/modules/ca/src/Makefile b/modules/ca/src/Makefile index 650b3550f..335cec67e 100644 --- a/modules/ca/src/Makefile +++ b/modules/ca/src/Makefile @@ -7,7 +7,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG # Channel Access Client diff --git a/modules/ca/src/client/Makefile b/modules/ca/src/client/Makefile index c5fc5c49d..cae6ee065 100644 --- a/modules/ca/src/client/Makefile +++ b/modules/ca/src/client/Makefile @@ -6,8 +6,8 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* - -TOP = ../.. +CURDIR := $(or $(dir $(lastword $(MAKEFILE_LIST))), .) +TOP = ../../../.. include $(TOP)/configure/CONFIG @@ -109,7 +109,7 @@ EXPAND += S99caRepeater@ EXPAND += caRepeater.service@ EXPAND_VARS = INSTALL_BIN=$(abspath $(INSTALL_BIN)) -SRC_DIRS += $(TOP)/src/client/test +SRC_DIRS += $(CURDIR)/test PROD_HOST += ca_test ca_test_SRCS = ca_test_main.c ca_test.c ca_test_LIBS = ca Com diff --git a/modules/ca/src/perl/Makefile b/modules/ca/src/perl/Makefile index 5b2bd5920..65f42ee3a 100644 --- a/modules/ca/src/perl/Makefile +++ b/modules/ca/src/perl/Makefile @@ -5,7 +5,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../.. +TOP = ../../../.. include $(TOP)/configure/CONFIG # Special settings for Darwin: diff --git a/modules/ca/src/template/Makefile b/modules/ca/src/template/Makefile index 913d92bf4..8683dfd3c 100644 --- a/modules/ca/src/template/Makefile +++ b/modules/ca/src/template/Makefile @@ -1,4 +1,4 @@ -TOP=../.. +TOP=../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/ca/src/tools/Makefile b/modules/ca/src/tools/Makefile index 7ebcc021b..c56e21eca 100644 --- a/modules/ca/src/tools/Makefile +++ b/modules/ca/src/tools/Makefile @@ -9,7 +9,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../.. +TOP = ../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/.ci/travis-build.sh b/modules/database/.ci/travis-build.sh deleted file mode 100755 index 622979b9d..000000000 --- a/modules/database/.ci/travis-build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -x - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 $EXTRA - -if [ "$TEST" != "NO" ] -then - make -j2 tapfiles - make -s test-results -fi diff --git a/modules/database/.ci/travis-prepare.sh b/modules/database/.ci/travis-prepare.sh deleted file mode 100755 index ce2c18b5d..000000000 --- a/modules/database/.ci/travis-prepare.sh +++ /dev/null @@ -1,133 +0,0 @@ -#!/bin/sh -set -e -x - -CURDIR="$PWD" - -QDIR="$HOME/.cache/qemu" - -if [ -n "$RTEMS" -a "$TEST" = "YES" ] -then - git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu" - cd "$HOME/.build/qemu" - - HEAD=`git log -n1 --pretty=format:%H` - echo "HEAD revision $HEAD" - - [ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"` - echo "Cached revision $BUILT" - - if [ "$HEAD" != "$BUILT" ] - then - echo "Building QEMU" - git submodule --quiet update --init - - install -d "$HOME/.build/qemu/build" - cd "$HOME/.build/qemu/build" - - "$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror - make -j2 - make install - - echo "$HEAD" > "$HOME/.cache/qemu/built" - fi -fi - -cd "$CURDIR" - -cat << EOF > configure/RELEASE.local -EPICS_BASE=$HOME/.source/epics-base -EOF - -install -d "$HOME/.source" -cd "$HOME/.source" - -add_base_module() { - MODULE=$1 - BRANCH=$2 - ( cd epics-base/modules && \ - git clone --quiet --depth 5 --branch "$MODULE"/"$BRANCH" https://github.com/${REPOBASE:-epics-base}/epics-base.git "$MODULE" && \ - cd "$MODULE" && git log -n1 ) -} - -git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base -( cd epics-base && git log -n1 ) -add_base_module libcom "${BRLIBCOM:-master}" -add_base_module ca "${BRCA:-master}" - -EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch` - -# requires wine and g++-mingw-w64-i686 -if [ "$WINE" = "32" ] -then - echo "Cross mingw32" - sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw - cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw -CMPLR_PREFIX=i686-w64-mingw32- -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw -EOF -fi - -if [ "$STATIC" = "YES" ] -then - echo "Build static libraries/executables" - cat << EOF >> epics-base/configure/CONFIG_SITE -SHARED_LIBRARIES=NO -STATIC_BUILD=YES -EOF -fi - -case "$CMPLR" in -clang) - echo "Host compiler is clang" - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH -GNU = NO -CMPLR_CLASS = clang -CC = clang -CCC = clang++ -EOF - - # hack - sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon - - clang --version - ;; -*) - echo "Host compiler is default" - gcc --version - ;; -esac - -cat <> epics-base/configure/CONFIG_SITE -USR_CPPFLAGS += $USR_CPPFLAGS -USR_CFLAGS += $USR_CFLAGS -USR_CXXFLAGS += $USR_CXXFLAGS -EOF - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - echo "Cross RTEMS${RTEMS} for pc386" - install -d /home/travis/.cache - curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ - | tar -C /home/travis/.cache -xj - - sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS -RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 -EOF - - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 -C epics-base $EXTRA diff --git a/modules/database/.travis.yml b/modules/database/.travis.yml deleted file mode 100644 index 127ae7bc9..000000000 --- a/modules/database/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -dist: trusty -language: c -compiler: - - gcc -addons: - apt: - packages: - - libreadline6-dev - - libncurses5-dev - - perl - - clang - - g++-mingw-w64-i686 -install: - - ./.ci/travis-prepare.sh -script: - - ./.ci/travis-build.sh -env: - - BRCORE=master BRLIBCOM=master BRCA=master - - CMPLR=clang - - USR_CXXFLAGS=-std=c++11 - - CMPLR=clang USR_CXXFLAGS=-std=c++11 - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO diff --git a/modules/database/Makefile b/modules/database/Makefile index 9998e6cf5..9bb746e82 100644 --- a/modules/database/Makefile +++ b/modules/database/Makefile @@ -7,11 +7,10 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = . +TOP = ../.. include $(TOP)/configure/CONFIG -DIRS += configure src -src_DEPEND_DIRS = configure +DIRS += src DIRS += test test_DEPEND_DIRS = src diff --git a/modules/database/configure/CONFIG b/modules/database/configure/CONFIG deleted file mode 100644 index c471407c4..000000000 --- a/modules/database/configure/CONFIG +++ /dev/null @@ -1,36 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -BUILDING_DATABASE = DEFINED - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# Use new RSET definition -BASE_CPPFLAGS += -DUSE_TYPED_RSET - -# Shared library ABI version. -SHRLIB_VERSION = $(EPICS_DATABASE_MAJOR_VERSION).$(EPICS_DATABASE_MINOR_VERSION).$(EPICS_DATABASE_MAINTENANCE_VERSION) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif diff --git a/modules/database/configure/CONFIG_SITE b/modules/database/configure/CONFIG_SITE deleted file mode 100644 index d78c7f514..000000000 --- a/modules/database/configure/CONFIG_SITE +++ /dev/null @@ -1,42 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local diff --git a/modules/database/configure/Makefile b/modules/database/configure/Makefile deleted file mode 100644 index dd292091c..000000000 --- a/modules/database/configure/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -#************************************************************************* -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -TOP = .. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -CFG += CONFIG_DATABASE_MODULE -CFG += CONFIG_DATABASE_VERSION - -include $(TOP)/configure/RULES diff --git a/modules/database/configure/RELEASE b/modules/database/configure/RELEASE deleted file mode 100644 index 9b685a13e..000000000 --- a/modules/database/configure/RELEASE +++ /dev/null @@ -1,40 +0,0 @@ -# RELEASE - Location of external support modules -# -# IF YOU CHANGE ANY PATHS in this file or make API changes to -# any modules it refers to, you should do a "make rebuild" in -# this application's top level directory. -# -# The EPICS build process does not check dependencies against -# any files from outside the application, so it is safest to -# rebuild it completely if any modules it depends on change. -# -# Host- or target-specific settings can be given in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) -# -# This file is parsed by both GNUmake and an EPICS Perl script, -# so it may ONLY contain definititions of paths to other support -# modules, variable definitions that are used in module paths, -# and include statements that pull in other RELEASE files. -# Variables may be used before their values have been set. -# Build variables that are NOT used in paths should be set in -# the CONFIG_SITE file. - -# Variables and paths to dependent modules: -#MODULES = /path/to/modules -#MYMODULE = $(MODULES)/my-module - -# If building the EPICS modules individually, set these: -#EPICS_CA = $(MODULES)/ca-4.13.1 -#EPICS_LIBCOM = $(MODULES)/libcom-3.17.0 -#EPICS_BASE = $(MODULES)/core-7.0.1 - -# Set RULES here if you want to use build rules from elsewhere: -#RULES = $(MODULES)/build-rules - -# These lines allow developers to override these RELEASE settings -# without having to modify this file directly. --include $(TOP)/../RELEASE.local --include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local --include $(TOP)/configure/RELEASE.local diff --git a/modules/database/configure/RULES b/modules/database/configure/RULES deleted file mode 100644 index 6d56e14e8..000000000 --- a/modules/database/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/modules/database/configure/RULES.ioc b/modules/database/configure/RULES.ioc deleted file mode 100644 index 901987c6c..000000000 --- a/modules/database/configure/RULES.ioc +++ /dev/null @@ -1,2 +0,0 @@ -#RULES.ioc -include $(CONFIG)/RULES.ioc diff --git a/modules/database/configure/RULES_DIRS b/modules/database/configure/RULES_DIRS deleted file mode 100644 index 3ba269dcc..000000000 --- a/modules/database/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/modules/database/configure/RULES_TOP b/modules/database/configure/RULES_TOP deleted file mode 100644 index 2b8cbc6da..000000000 --- a/modules/database/configure/RULES_TOP +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP diff --git a/modules/database/src/Makefile b/modules/database/src/Makefile index dfd1d3be9..0cc46fa40 100644 --- a/modules/database/src/Makefile +++ b/modules/database/src/Makefile @@ -7,7 +7,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG # PDB Tools diff --git a/modules/database/src/ioc/Makefile b/modules/database/src/ioc/Makefile index 325872826..9ff00407d 100644 --- a/modules/database/src/ioc/Makefile +++ b/modules/database/src/ioc/Makefile @@ -6,12 +6,14 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* -TOP=../.. +IOCDIR := $(or $(dir $(lastword $(MAKEFILE_LIST))), .) +TOP=../../../.. include $(TOP)/configure/CONFIG -SRC = $(TOP)/src -IOCDIR = $(SRC)/ioc +USR_CPPFLAGS += -DUSE_TYPED_RSET + +SHRLIB_VERSION = 3.17.0 LIBRARY_IOC += dbCore dbCore_LIBS += ca Com diff --git a/modules/database/src/std/Makefile b/modules/database/src/std/Makefile index 20a8658cb..2434bf0a4 100644 --- a/modules/database/src/std/Makefile +++ b/modules/database/src/std/Makefile @@ -6,11 +6,13 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* - -TOP = ../.. +STDDIR := $(or $(dir $(lastword $(MAKEFILE_LIST))), .) +TOP = ../../../.. include $(TOP)/configure/CONFIG -STDDIR=$(TOP)/src/std +USR_CPPFLAGS += -DUSE_TYPED_RSET + +SHRLIB_VERSION = 3.17.0 LIBRARY_IOC += dbRecStd dbRecStd_LIBS = dbCore ca Com diff --git a/modules/database/src/template/Makefile b/modules/database/src/template/Makefile index 6259b6fca..8dfc6c6f3 100644 --- a/modules/database/src/template/Makefile +++ b/modules/database/src/template/Makefile @@ -1,4 +1,4 @@ -TOP=../.. +TOP=../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/src/tools/Makefile b/modules/database/src/tools/Makefile index e19c0c58f..bfd329fbe 100644 --- a/modules/database/src/tools/Makefile +++ b/modules/database/src/tools/Makefile @@ -4,7 +4,7 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* -TOP=../.. +TOP=../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/test/Makefile b/modules/database/test/Makefile index 0f2c64263..b54d01757 100644 --- a/modules/database/test/Makefile +++ b/modules/database/test/Makefile @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG DIRS += ioc/db diff --git a/modules/database/test/ioc/db/Makefile b/modules/database/test/ioc/db/Makefile index e1f06cd3b..ee2ab7632 100644 --- a/modules/database/test/ioc/db/Makefile +++ b/modules/database/test/ioc/db/Makefile @@ -6,12 +6,13 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution. #************************************************************************* - -TOP = ../../.. +CURDIR := $(or $(dir $(lastword $(MAKEFILE_LIST))), .) +TOP = ../../../../.. include $(TOP)/configure/CONFIG # Allow access to private headers in db/ -USR_CPPFLAGS = -I $(TOP)/src/ioc/db +USR_CPPFLAGS += -I $(CURDIR)/../../../src/ioc/db +USR_CPPFLAGS += -DUSE_TYPED_RSET TESTLIBRARY = dbTestIoc diff --git a/modules/database/test/ioc/dbtemplate/Makefile b/modules/database/test/ioc/dbtemplate/Makefile index 4442a4ff8..dbb13f337 100644 --- a/modules/database/test/ioc/dbtemplate/Makefile +++ b/modules/database/test/ioc/dbtemplate/Makefile @@ -5,7 +5,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../../.. +TOP = ../../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/database/test/std/filters/Makefile b/modules/database/test/std/filters/Makefile index 718b8d523..c95e10861 100644 --- a/modules/database/test/std/filters/Makefile +++ b/modules/database/test/std/filters/Makefile @@ -7,10 +7,12 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../../.. +TOP = ../../../../.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -DUSE_TYPED_RSET + TESTLIBRARY = Recs Recs_SRCS += xRecord.c diff --git a/modules/database/test/std/link/Makefile b/modules/database/test/std/link/Makefile index 8540cdf84..c72301bea 100644 --- a/modules/database/test/std/link/Makefile +++ b/modules/database/test/std/link/Makefile @@ -8,6 +8,8 @@ TOP=../../.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -DUSE_TYPED_RSET + TESTLIBRARY = Recs Recs_SRCS += ioRecord.c diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile index 185c2c0c1..872087521 100644 --- a/modules/database/test/std/rec/Makefile +++ b/modules/database/test/std/rec/Makefile @@ -7,9 +7,11 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../../.. +TOP = ../../../../.. include $(TOP)/configure/CONFIG +USR_CPPFLAGS += -DUSE_TYPED_RSET + TESTLIBRARY = dbRecStdTest dbRecStdTest_SRCS += asTestLib.c diff --git a/modules/database/test/tools/Makefile b/modules/database/test/tools/Makefile index ac7f42071..2dd045e8e 100644 --- a/modules/database/test/tools/Makefile +++ b/modules/database/test/tools/Makefile @@ -5,7 +5,7 @@ # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP = ../.. +TOP = ../../../.. include $(TOP)/configure/CONFIG diff --git a/modules/libcom/.ci/travis-build.sh b/modules/libcom/.ci/travis-build.sh deleted file mode 100755 index 622979b9d..000000000 --- a/modules/libcom/.ci/travis-build.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -set -e -x - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 $EXTRA - -if [ "$TEST" != "NO" ] -then - make -j2 tapfiles - make -s test-results -fi diff --git a/modules/libcom/.ci/travis-prepare.sh b/modules/libcom/.ci/travis-prepare.sh deleted file mode 100755 index 9a4d23772..000000000 --- a/modules/libcom/.ci/travis-prepare.sh +++ /dev/null @@ -1,123 +0,0 @@ -#!/bin/sh -set -e -x - -CURDIR="$PWD" - -QDIR="$HOME/.cache/qemu" - -if [ -n "$RTEMS" -a "$TEST" = "YES" ] -then - git clone --quiet --branch vme --depth 10 https://github.com/mdavidsaver/qemu.git "$HOME/.build/qemu" - cd "$HOME/.build/qemu" - - HEAD=`git log -n1 --pretty=format:%H` - echo "HEAD revision $HEAD" - - [ -e "$HOME/.cache/qemu/built" ] && BUILT=`cat "$HOME/.cache/qemu/built"` - echo "Cached revision $BUILT" - - if [ "$HEAD" != "$BUILT" ] - then - echo "Building QEMU" - git submodule --quiet update --init - - install -d "$HOME/.build/qemu/build" - cd "$HOME/.build/qemu/build" - - "$HOME/.build/qemu/configure" --prefix="$HOME/.cache/qemu/usr" --target-list=i386-softmmu --disable-werror - make -j2 - make install - - echo "$HEAD" > "$HOME/.cache/qemu/built" - fi -fi - -cd "$CURDIR" - -cat << EOF > configure/RELEASE.local -EPICS_BASE=$HOME/.source/epics-base -EOF - -install -d "$HOME/.source" -cd "$HOME/.source" - -git clone --quiet --depth 5 --branch core/"${BRCORE:-master}" https://github.com/${REPOBASE:-epics-base}/epics-base.git epics-base -(cd epics-base && git log -n1 ) - -EPICS_HOST_ARCH=`sh epics-base/startup/EpicsHostArch` - -# requires wine and g++-mingw-w64-i686 -if [ "$WINE" = "32" ] -then - echo "Cross mingw32" - sed -i -e '/CMPLR_PREFIX/d' epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw - cat << EOF >> epics-base/configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw -CMPLR_PREFIX=i686-w64-mingw32- -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=win32-x86-mingw -EOF -fi - -if [ "$STATIC" = "YES" ] -then - echo "Build static libraries/executables" - cat << EOF >> epics-base/configure/CONFIG_SITE -SHARED_LIBRARIES=NO -STATIC_BUILD=YES -EOF -fi - -case "$CMPLR" in -clang) - echo "Host compiler is clang" - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.$EPICS_HOST_ARCH -GNU = NO -CMPLR_CLASS = clang -CC = clang -CCC = clang++ -EOF - - # hack - sed -i -e 's/CMPLR_CLASS = gcc/CMPLR_CLASS = clang/' epics-base/configure/CONFIG.gnuCommon - - clang --version - ;; -*) - echo "Host compiler is default" - gcc --version - ;; -esac - -cat <> epics-base/configure/CONFIG_SITE -USR_CPPFLAGS += $USR_CPPFLAGS -USR_CFLAGS += $USR_CFLAGS -USR_CXXFLAGS += $USR_CXXFLAGS -EOF - -# set RTEMS to eg. "4.9" or "4.10" -# requires qemu, bison, flex, texinfo, install-info -if [ -n "$RTEMS" ] -then - echo "Cross RTEMS${RTEMS} for pc386" - install -d /home/travis/.cache - curl -L "https://github.com/mdavidsaver/rsb/releases/download/travis-20160306-2/rtems${RTEMS}-i386-trusty-20190306-2.tar.gz" \ - | tar -C /home/travis/.cache -xj - - sed -i -e '/^RTEMS_VERSION/d' -e '/^RTEMS_BASE/d' epics-base/configure/os/CONFIG_SITE.Common.RTEMS - cat << EOF >> epics-base/configure/os/CONFIG_SITE.Common.RTEMS -RTEMS_VERSION=$RTEMS -RTEMS_BASE=/home/travis/.cache/rtems${RTEMS}-i386 -EOF - cat << EOF >> epics-base/configure/CONFIG_SITE -CROSS_COMPILER_TARGET_ARCHS+=RTEMS-pc386 -EOF - - # find local qemu-system-i386 - export PATH="$HOME/.cache/qemu/usr/bin:$PATH" - echo -n "Using QEMU: " - type qemu-system-i386 || echo "Missing qemu" - EXTRA=RTEMS_QEMU_FIXUPS=YES -fi - -make -j2 -C epics-base $EXTRA diff --git a/modules/libcom/.travis.yml b/modules/libcom/.travis.yml deleted file mode 100644 index 8b1e2ab3e..000000000 --- a/modules/libcom/.travis.yml +++ /dev/null @@ -1,26 +0,0 @@ -sudo: false -dist: trusty -language: c -compiler: - - gcc -addons: - apt: - packages: - - libreadline6-dev - - libncurses5-dev - - perl - - clang - - g++-mingw-w64-i686 -install: - - ./.ci/travis-prepare.sh -script: - - ./.ci/travis-build.sh -env: - - BRCORE=master - - CMPLR=clang - - USR_CXXFLAGS=-std=c++11 - - CMPLR=clang USR_CXXFLAGS=-std=c++11 - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO diff --git a/modules/libcom/Makefile b/modules/libcom/Makefile index 442a6f7d1..5a03a4348 100644 --- a/modules/libcom/Makefile +++ b/modules/libcom/Makefile @@ -7,11 +7,10 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = . +TOP = ../.. include $(TOP)/configure/CONFIG -DIRS += configure src -src_DEPEND_DIRS = configure +DIRS += src DIRS += RTEMS RTEMS_DEPEND_DIRS = src @@ -22,4 +21,4 @@ vxWorks_DEPEND_DIRS = src DIRS += test test_DEPEND_DIRS = RTEMS vxWorks -include $(TOP)/configure/RULES_TOP +include $(TOP)/configure/RULES_DIRS diff --git a/modules/libcom/RTEMS/Makefile b/modules/libcom/RTEMS/Makefile index 311c25024..b46889db1 100644 --- a/modules/libcom/RTEMS/Makefile +++ b/modules/libcom/RTEMS/Makefile @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG include $(TOP)/configure/CONFIG_LIBCOM_VERSION diff --git a/modules/libcom/configure/CONFIG b/modules/libcom/configure/CONFIG deleted file mode 100644 index 774ed251c..000000000 --- a/modules/libcom/configure/CONFIG +++ /dev/null @@ -1,44 +0,0 @@ -# CONFIG - Load build configuration data -# -# Do not make changes to this file! - -ifeq ($(strip $(EPICS_HOST_ARCH)),) - $(warning EPICS_HOST_ARCH is not set.) -endif - -# Allow user to override where the build rules come from -RULES = $(EPICS_BASE) - -# RELEASE files point to other application tops -include $(TOP)/configure/RELEASE --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common -ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) -endif - -ifeq ($(strip $(RULES)),) - ifeq ($(strip $(EPICS_BASE)),) - $(warning Build error: EPICS_BASE not set after including RELEASE files.) - else - $(warning Build error: EPICS_BASE set but RULES variable empty.) - endif - $(error Makefiles loaded: $(MAKEFILE_LIST)) - # Die before the include of $(CONFIG)/CONFIG below does -endif - -BUILDING_LIBCOM = DEFINED - -CONFIG = $(RULES)/configure -include $(CONFIG)/CONFIG - -# Override the Base definition: -INSTALL_LOCATION = $(TOP) - -# CONFIG_SITE files contain other build configuration settings -include $(TOP)/configure/CONFIG_SITE --include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common -ifdef T_A - -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) - -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) -endif diff --git a/modules/libcom/configure/CONFIG_SITE b/modules/libcom/configure/CONFIG_SITE deleted file mode 100644 index d78c7f514..000000000 --- a/modules/libcom/configure/CONFIG_SITE +++ /dev/null @@ -1,42 +0,0 @@ -# CONFIG_SITE - -# Make any application-specific changes to the EPICS build -# configuration variables in this file. -# -# Host/target specific settings can be specified in files named -# CONFIG_SITE.$(EPICS_HOST_ARCH).Common -# CONFIG_SITE.Common.$(T_A) -# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - -# CHECK_RELEASE controls the consistency checking of the support -# applications pointed to by the RELEASE* files. -# Normally CHECK_RELEASE should be set to YES. -# Set CHECK_RELEASE to NO to disable checking completely. -# Set CHECK_RELEASE to WARN to perform consistency checking but -# continue building even if conflicts are found. -CHECK_RELEASE = YES - -# Set this when you only want to compile this application -# for a subset of the cross-compiled target architectures -# that Base is built for. -#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 - -# To install files into a location other than $(TOP) define -# INSTALL_LOCATION here. -#INSTALL_LOCATION= - -# Set this when the IOC and build host use different paths -# to the install location. This may be needed to boot from -# a Microsoft FTP server say, or on some NFS configurations. -#IOCS_APPL_TOP = - -# For application debugging purposes, override the HOST_OPT and/ -# or CROSS_OPT settings from base/configure/CONFIG_SITE -#HOST_OPT = NO -#CROSS_OPT = NO - -# These allow developers to override the CONFIG_SITE variable -# settings without having to modify the configure/CONFIG_SITE -# file itself. --include $(TOP)/../CONFIG_SITE.local --include $(TOP)/configure/CONFIG_SITE.local diff --git a/modules/libcom/configure/Makefile b/modules/libcom/configure/Makefile deleted file mode 100644 index 85a7b5843..000000000 --- a/modules/libcom/configure/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -#************************************************************************* -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* -TOP = .. - -include $(TOP)/configure/CONFIG - -TARGETS = $(CONFIG_TARGETS) -CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) - -CFG += CONFIG_LIBCOM_MODULE -CFG += CONFIG_LIBCOM_VERSION - -include $(TOP)/configure/RULES diff --git a/modules/libcom/configure/RELEASE b/modules/libcom/configure/RELEASE deleted file mode 100644 index 819b441e7..000000000 --- a/modules/libcom/configure/RELEASE +++ /dev/null @@ -1,38 +0,0 @@ -# RELEASE - Location of external support modules -# -# IF YOU CHANGE ANY PATHS in this file or make API changes to -# any modules it refers to, you should do a "make rebuild" in -# this application's top level directory. -# -# The EPICS build process does not check dependencies against -# any files from outside the application, so it is safest to -# rebuild it completely if any modules it depends on change. -# -# Host- or target-specific settings can be given in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) -# -# This file is parsed by both GNUmake and an EPICS Perl script, -# so it may ONLY contain definititions of paths to other support -# modules, variable definitions that are used in module paths, -# and include statements that pull in other RELEASE files. -# Variables may be used before their values have been set. -# Build variables that are NOT used in paths should be set in -# the CONFIG_SITE file. - -# Variables and paths to dependent modules: -#MODULES = /path/to/modules -#MYMODULE = $(MODULES)/my-module - -# If building the EPICS modules individually, set these: -#EPICS_BASE = $(MODULES)/core-7.0.1 - -# Set RULES here if you want to use build rules from elsewhere: -#RULES = $(MODULES)/build-rules - -# These lines allow developers to override these RELEASE settings -# without having to modify this file directly. --include $(TOP)/../RELEASE.local --include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local --include $(TOP)/configure/RELEASE.local diff --git a/modules/libcom/configure/RULES b/modules/libcom/configure/RULES deleted file mode 100644 index 6d56e14e8..000000000 --- a/modules/libcom/configure/RULES +++ /dev/null @@ -1,6 +0,0 @@ -# RULES - -include $(CONFIG)/RULES - -# Library should be rebuilt because LIBOBJS may have changed. -$(LIBNAME): ../Makefile diff --git a/modules/libcom/configure/RULES_DIRS b/modules/libcom/configure/RULES_DIRS deleted file mode 100644 index 3ba269dcc..000000000 --- a/modules/libcom/configure/RULES_DIRS +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_DIRS -include $(CONFIG)/RULES_DIRS diff --git a/modules/libcom/configure/RULES_TOP b/modules/libcom/configure/RULES_TOP deleted file mode 100644 index 2b8cbc6da..000000000 --- a/modules/libcom/configure/RULES_TOP +++ /dev/null @@ -1,2 +0,0 @@ -#RULES_TOP -include $(CONFIG)/RULES_TOP diff --git a/modules/libcom/src/Makefile b/modules/libcom/src/Makefile index d61b26803..4a1c61e38 100644 --- a/modules/libcom/src/Makefile +++ b/modules/libcom/src/Makefile @@ -6,15 +6,13 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* - -TOP = .. +LIBCOM := $(or $(dir $(lastword $(MAKEFILE_LIST))), .) +TOP = ../../.. include $(TOP)/configure/CONFIG # Uncomment this to remove the (benign) valgrind helper stubs #USR_CFLAGS += -DNVALGRIND -LIBCOM = $(TOP)/src - INC += valgrind/valgrind.h INC += libComVersion.h diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index 1c26c44b7..87405f72f 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG PROD_LIBS += Com diff --git a/modules/libcom/vxWorks/Makefile b/modules/libcom/vxWorks/Makefile index e2c0b5d2d..3eced3b08 100644 --- a/modules/libcom/vxWorks/Makefile +++ b/modules/libcom/vxWorks/Makefile @@ -5,7 +5,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -TOP = .. +TOP = ../../.. include $(TOP)/configure/CONFIG # Install Boost smart_ptr headers needed by VxWorks 6.x From d7841f407a7a62773fcab625384fa80d18fcf02a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 31 Dec 2018 10:25:17 -0800 Subject: [PATCH 018/281] drop unnecessary *ModuleDirs --- modules/ca/src/perl/Makefile | 2 -- modules/ca/src/perl/capr.pl | 1 - modules/database/src/tools/Makefile | 2 -- modules/database/src/tools/dbExpand.pl | 1 - modules/database/src/tools/dbdExpand.pl | 1 - modules/database/src/tools/dbdReport.pl | 1 - modules/database/src/tools/dbdToHtml.pl | 1 - modules/database/src/tools/dbdToMenuH.pl | 1 - modules/database/src/tools/dbdToRecordtypeH.pl | 1 - modules/database/src/tools/registerRecordDeviceDriver.pl | 1 - modules/libcom/src/env/Makefile | 1 - modules/libcom/src/env/RULES | 2 +- modules/libcom/src/env/bldEnvData.pl | 1 - 13 files changed, 1 insertion(+), 15 deletions(-) diff --git a/modules/ca/src/perl/Makefile b/modules/ca/src/perl/Makefile index 65f42ee3a..12e0c82b5 100644 --- a/modules/ca/src/perl/Makefile +++ b/modules/ca/src/perl/Makefile @@ -42,8 +42,6 @@ ifeq ($(findstring $(OS_CLASS),WIN32 cygwin32),) # Doesn't build on WIN32 PERL_MODULES += CA.pm PERL_MODULES += $(PERL_ARCHPATH)/$(LOADABLE_SHRLIB_PREFIX)Cap5$(LOADABLE_SHRLIB_SUFFIX) - PERL_SCRIPTS += caModuleDirs.pm - HTMLS_DIR = . HTMLS = CA.html endif diff --git a/modules/ca/src/perl/capr.pl b/modules/ca/src/perl/capr.pl index e551afcef..ba5998a14 100644 --- a/modules/ca/src/perl/capr.pl +++ b/modules/ca/src/perl/capr.pl @@ -11,7 +11,6 @@ use strict; use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use caModuleDirs; no lib $Bin; use Getopt::Std; diff --git a/modules/database/src/tools/Makefile b/modules/database/src/tools/Makefile index bfd329fbe..f54ab9c07 100644 --- a/modules/database/src/tools/Makefile +++ b/modules/database/src/tools/Makefile @@ -27,8 +27,6 @@ PERL_MODULES += DBD/Variable.pm PERL_MODULES += EPICS/IOC.pm HTMLS += EPICS/IOC.html -PERL_SCRIPTS += databaseModuleDirs.pm - PERL_SCRIPTS += makeIncludeDbd.pl PERL_SCRIPTS += dbdToMenuH.pl diff --git a/modules/database/src/tools/dbExpand.pl b/modules/database/src/tools/dbExpand.pl index 25cab26cc..35d7750d9 100644 --- a/modules/database/src/tools/dbExpand.pl +++ b/modules/database/src/tools/dbExpand.pl @@ -13,7 +13,6 @@ use strict; use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdExpand.pl b/modules/database/src/tools/dbdExpand.pl index a87ef47bb..5f12dc23e 100644 --- a/modules/database/src/tools/dbdExpand.pl +++ b/modules/database/src/tools/dbdExpand.pl @@ -11,7 +11,6 @@ use strict; use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdReport.pl b/modules/database/src/tools/dbdReport.pl index 0d4c85494..adc268345 100644 --- a/modules/database/src/tools/dbdReport.pl +++ b/modules/database/src/tools/dbdReport.pl @@ -9,7 +9,6 @@ use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdToHtml.pl b/modules/database/src/tools/dbdToHtml.pl index e9711f757..fa1cc99d7 100644 --- a/modules/database/src/tools/dbdToHtml.pl +++ b/modules/database/src/tools/dbdToHtml.pl @@ -11,7 +11,6 @@ use strict; use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdToMenuH.pl b/modules/database/src/tools/dbdToMenuH.pl index ac4345b42..30418a351 100644 --- a/modules/database/src/tools/dbdToMenuH.pl +++ b/modules/database/src/tools/dbdToMenuH.pl @@ -9,7 +9,6 @@ use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use EPICS::Getopts; diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl index b1eb77d93..f1336a147 100644 --- a/modules/database/src/tools/dbdToRecordtypeH.pl +++ b/modules/database/src/tools/dbdToRecordtypeH.pl @@ -9,7 +9,6 @@ use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use EPICS::Getopts; diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 02bb9b772..671d24051 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -13,7 +13,6 @@ use strict; use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use databaseModuleDirs; no lib $Bin; use DBD; diff --git a/modules/libcom/src/env/Makefile b/modules/libcom/src/env/Makefile index 804426bc0..94322a228 100644 --- a/modules/libcom/src/env/Makefile +++ b/modules/libcom/src/env/Makefile @@ -12,7 +12,6 @@ SRC_DIRS += $(LIBCOM)/env vpath %.pl $(USR_VPATH) $(SRC_DIRS) PERL_SCRIPTS += bldEnvData.pl -PERL_SCRIPTS += libcomModuleDirs.pm INC += envDefs.h diff --git a/modules/libcom/src/env/RULES b/modules/libcom/src/env/RULES index 02df6aa7a..5ef766d57 100644 --- a/modules/libcom/src/env/RULES +++ b/modules/libcom/src/env/RULES @@ -8,7 +8,7 @@ # This is a Makefile fragment, see src/libCom/Makefile. envData.c: $(LIBCOM)/env/envDefs.h \ - $(INSTALL_HOST_BIN)/bldEnvData.pl $(INSTALL_HOST_BIN)/libcomModuleDirs.pm \ + $(INSTALL_HOST_BIN)/bldEnvData.pl \ $(CONFIG)/CONFIG_ENV $(CONFIG)/CONFIG_SITE_ENV \ $(wildcard $(CONFIG)/os/CONFIG_SITE_ENV.$(T_A)) $(PERL) $(INSTALL_HOST_BIN)/bldEnvData.pl $(QUIET_FLAG) -t $(T_A) \ diff --git a/modules/libcom/src/env/bldEnvData.pl b/modules/libcom/src/env/bldEnvData.pl index e3c21b772..f638c841f 100644 --- a/modules/libcom/src/env/bldEnvData.pl +++ b/modules/libcom/src/env/bldEnvData.pl @@ -15,7 +15,6 @@ use strict; use FindBin qw($Bin); use lib ($Bin, "$Bin/../../lib/perl"); -use libcomModuleDirs; no lib $Bin; use Getopt::Std; From d38fcd52473a5c9d43cee891f7d47a526fbe1a99 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 31 Dec 2018 10:31:48 -0800 Subject: [PATCH 019/281] no need to search for perl modules under bin/ --- modules/ca/src/perl/capr.pl | 2 +- modules/ca/src/template/top/caPerlApp/caget.pl | 2 +- modules/ca/src/template/top/caPerlApp/cainfo.pl | 2 +- modules/ca/src/template/top/caPerlApp/camonitor.pl | 2 +- modules/ca/src/template/top/caPerlApp/caput.pl | 2 +- modules/database/src/tools/dbExpand.pl | 2 +- modules/database/src/tools/dbdExpand.pl | 2 +- modules/database/src/tools/dbdReport.pl | 2 +- modules/database/src/tools/dbdToHtml.pl | 2 +- modules/database/src/tools/dbdToMenuH.pl | 2 +- modules/database/src/tools/dbdToRecordtypeH.pl | 2 +- modules/database/src/tools/registerRecordDeviceDriver.pl | 2 +- modules/libcom/src/env/bldEnvData.pl | 2 +- src/template/base/makeBaseApp.pl | 2 +- src/tools/convertRelease.pl | 2 +- src/tools/expandVars.pl | 2 +- src/tools/fullPathName.pl | 2 +- 17 files changed, 17 insertions(+), 17 deletions(-) diff --git a/modules/ca/src/perl/capr.pl b/modules/ca/src/perl/capr.pl index ba5998a14..17a6dd04b 100644 --- a/modules/ca/src/perl/capr.pl +++ b/modules/ca/src/perl/capr.pl @@ -10,7 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use Getopt::Std; diff --git a/modules/ca/src/template/top/caPerlApp/caget.pl b/modules/ca/src/template/top/caPerlApp/caget.pl index 0d9af37a1..dae3a778a 100644 --- a/modules/ca/src/template/top/caPerlApp/caget.pl +++ b/modules/ca/src/template/top/caPerlApp/caget.pl @@ -4,7 +4,7 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; no lib $Bin; diff --git a/modules/ca/src/template/top/caPerlApp/cainfo.pl b/modules/ca/src/template/top/caPerlApp/cainfo.pl index 3e38e8baf..37c705e26 100644 --- a/modules/ca/src/template/top/caPerlApp/cainfo.pl +++ b/modules/ca/src/template/top/caPerlApp/cainfo.pl @@ -4,7 +4,7 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; no lib $Bin; diff --git a/modules/ca/src/template/top/caPerlApp/camonitor.pl b/modules/ca/src/template/top/caPerlApp/camonitor.pl index 564688d68..15c0212f0 100644 --- a/modules/ca/src/template/top/caPerlApp/camonitor.pl +++ b/modules/ca/src/template/top/caPerlApp/camonitor.pl @@ -4,7 +4,7 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; no lib $Bin; diff --git a/modules/ca/src/template/top/caPerlApp/caput.pl b/modules/ca/src/template/top/caPerlApp/caput.pl index 64ff9cbda..b08c9d200 100644 --- a/modules/ca/src/template/top/caPerlApp/caput.pl +++ b/modules/ca/src/template/top/caPerlApp/caput.pl @@ -4,7 +4,7 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; no lib $Bin; diff --git a/modules/database/src/tools/dbExpand.pl b/modules/database/src/tools/dbExpand.pl index 35d7750d9..e4088d007 100644 --- a/modules/database/src/tools/dbExpand.pl +++ b/modules/database/src/tools/dbExpand.pl @@ -12,7 +12,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdExpand.pl b/modules/database/src/tools/dbdExpand.pl index 5f12dc23e..7e9ba8b5a 100644 --- a/modules/database/src/tools/dbdExpand.pl +++ b/modules/database/src/tools/dbdExpand.pl @@ -10,7 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdReport.pl b/modules/database/src/tools/dbdReport.pl index adc268345..8a82d690b 100644 --- a/modules/database/src/tools/dbdReport.pl +++ b/modules/database/src/tools/dbdReport.pl @@ -8,7 +8,7 @@ #************************************************************************* use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdToHtml.pl b/modules/database/src/tools/dbdToHtml.pl index fa1cc99d7..87fc23230 100644 --- a/modules/database/src/tools/dbdToHtml.pl +++ b/modules/database/src/tools/dbdToHtml.pl @@ -10,7 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use DBD; diff --git a/modules/database/src/tools/dbdToMenuH.pl b/modules/database/src/tools/dbdToMenuH.pl index 30418a351..e80ae3340 100644 --- a/modules/database/src/tools/dbdToMenuH.pl +++ b/modules/database/src/tools/dbdToMenuH.pl @@ -8,7 +8,7 @@ #************************************************************************* use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use EPICS::Getopts; diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl index f1336a147..028309fc4 100644 --- a/modules/database/src/tools/dbdToRecordtypeH.pl +++ b/modules/database/src/tools/dbdToRecordtypeH.pl @@ -8,7 +8,7 @@ #************************************************************************* use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use EPICS::Getopts; diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 671d24051..507385e57 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -12,7 +12,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use DBD; diff --git a/modules/libcom/src/env/bldEnvData.pl b/modules/libcom/src/env/bldEnvData.pl index f638c841f..180d63870 100644 --- a/modules/libcom/src/env/bldEnvData.pl +++ b/modules/libcom/src/env/bldEnvData.pl @@ -14,7 +14,7 @@ use strict; use FindBin qw($Bin); -use lib ($Bin, "$Bin/../../lib/perl"); +use lib ("$Bin/../../lib/perl"); no lib $Bin; use Getopt::Std; diff --git a/src/template/base/makeBaseApp.pl b/src/template/base/makeBaseApp.pl index d6da8adf8..0421f004b 100644 --- a/src/template/base/makeBaseApp.pl +++ b/src/template/base/makeBaseApp.pl @@ -3,7 +3,7 @@ # Authors: Ralph Lange, Marty Kraimer, Andrew Johnson and Janet Anderson use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use Cwd; use Getopt::Std; diff --git a/src/tools/convertRelease.pl b/src/tools/convertRelease.pl index a5a1a77d8..253378422 100644 --- a/src/tools/convertRelease.pl +++ b/src/tools/convertRelease.pl @@ -19,7 +19,7 @@ use Getopt::Std; $Getopt::Std::STANDARD_HELP_VERSION = 1; use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use EPICS::Path; use EPICS::Release; diff --git a/src/tools/expandVars.pl b/src/tools/expandVars.pl index 01e65fb3a..855aca329 100644 --- a/src/tools/expandVars.pl +++ b/src/tools/expandVars.pl @@ -10,7 +10,7 @@ use strict; use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use EPICS::Getopts; use EPICS::Path; diff --git a/src/tools/fullPathName.pl b/src/tools/fullPathName.pl index c8ac49a12..20ef6d231 100644 --- a/src/tools/fullPathName.pl +++ b/src/tools/fullPathName.pl @@ -17,7 +17,7 @@ use Getopt::Std; $Getopt::Std::STANDARD_HELP_VERSION = 1; use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl", $Bin); +use lib ("$Bin/../../lib/perl"); use EPICS::Path; From 834e202671e4c47ac1428e4c4b71a67eb697d553 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 3 Jan 2019 20:44:50 -0800 Subject: [PATCH 020/281] missed a TOP --- modules/database/test/std/link/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/test/std/link/Makefile b/modules/database/test/std/link/Makefile index c72301bea..2563fd591 100644 --- a/modules/database/test/std/link/Makefile +++ b/modules/database/test/std/link/Makefile @@ -4,7 +4,7 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in the file LICENSE that is included with this distribution. #************************************************************************* -TOP=../../.. +TOP=../../../../.. include $(TOP)/configure/CONFIG From 3e8f3a1ee9b5b9f6a720b1476f97458023f14575 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 6 Mar 2019 16:14:55 -0800 Subject: [PATCH 021/281] configure: Don't hide any perl scripts being run --- configure/RULES_BUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 2dc9dd501..864d2d9bf 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -190,7 +190,7 @@ endif checkRelease: +$(CONVERTRELEASE) checkRelease warnRelease: - -$(CONVERTRELEASE) checkRelease + $(CONVERTRELEASE) checkRelease noCheckRelease: ifeq ($(EPICS_HOST_ARCH),$(T_A)) $(info Warning: RELEASE file consistency checks have been disabled) @@ -346,7 +346,7 @@ $(MODNAME): %$(MODEXT): %$(EXE) runtests: $(TESTSCRIPTS) ifdef RUNTESTS_ENABLED - -$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^ + $(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^ endif testspec: $(TESTSCRIPTS) @@ -381,7 +381,7 @@ junitfiles: $(JUNITFILES) # A .tap file is the output from running the associated test script %.tap: %.t ifdef RUNTESTS_ENABLED - -$(PERL) $< -tap > $@ + $(PERL) $< -tap > $@ endif %.xml: %.tap From 0e2d0cde5fea48168faf3b4ce1f6d3fff18889ec Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 6 Mar 2019 16:50:47 -0800 Subject: [PATCH 022/281] skip RELEASE_TOPS --- configure/CONFIG | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure/CONFIG b/configure/CONFIG index e40d3f5f7..153e69e8c 100644 --- a/configure/CONFIG +++ b/configure/CONFIG @@ -58,8 +58,12 @@ include $(CONFIG)/CONFIG_BASE_VERSION include $(CONFIG)/os/CONFIG.$(EPICS_HOST_ARCH).Common -include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# Parse configure/RELEASE +# except when building Base itself, where this file is empty, +# and would error in src/tools/ anyway. +ifndef BASE_TOP RELEASE_TOPS := $(shell $(CONVERTRELEASE) -T $(TOP) releaseTops) - +endif ifdef T_A From 2e80a97da9dd6384ad6992f711569d3b72e298df Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 2 May 2019 09:25:19 -0700 Subject: [PATCH 023/281] iocsh catch exceptions --- modules/libcom/src/iocsh/iocsh.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 0de90c87a..23e363ad4 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -11,6 +11,8 @@ /* Heavily modified by Eric Norum Date: 03MAY2000 */ /* Adapted to C++ by Eric Norum Date: 18DEC2000 */ +#include + #include #include #include @@ -834,7 +836,14 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) for (int iarg = 0 ; ; ) { if (iarg == piocshFuncDef->nargs) { startRedirect(filename, lineno, redirects); - (*found->def.func)(argBuf); + /* execute */ + try { + (*found->def.func)(argBuf); + } catch(std::exception& e){ + fprintf(epicsGetStderr(), "c++ error: %s\n", e.what()); + } catch(...) { + fprintf(epicsGetStderr(), "c++ error unknown\n"); + } break; } if (iarg >= argBufCapacity) { From 89c269e2d5ba5f7775dd557ae919000ba199b9da Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 2 May 2019 10:38:47 -0700 Subject: [PATCH 024/281] iocsh control error behavior --- modules/libcom/src/iocsh/iocsh.cpp | 101 +++++++++++++++++++++++++---- 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 23e363ad4..57e8be671 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -58,7 +58,7 @@ static char iocshVarID[] = "iocshVar"; extern "C" { static void varCallFunc(const iocshArgBuf *); } static epicsMutexId iocshTableMutex; static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT; -static epicsThreadPrivateId iocshMacroHandleId; +static epicsThreadPrivateId iocshScopeId; /* * I/O redirection @@ -78,7 +78,7 @@ struct iocshRedirect { static void iocshOnce (void *) { iocshTableMutex = epicsMutexMustCreate (); - iocshMacroHandleId = epicsThreadPrivateCreate(); + iocshScopeId = epicsThreadPrivateCreate(); } static void iocshInit (void) @@ -498,6 +498,19 @@ static void helpCallFunc(const iocshArgBuf *args) } } +typedef enum { + Continue, + Break, + Halt +} OnError; + +typedef struct { + MAC_HANDLE *handle; + OnError onerr; + double timeout; + bool errored; +} Scope; + /* * The body of the command interpreter */ @@ -526,8 +539,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) void *readlineContext = NULL; int wasOkToBlock; static const char * pairs[] = {"", "environ", NULL, NULL}; + Scope *scope; MAC_HANDLE *handle; char ** defines = NULL; + int ret = 0; iocshInit(); @@ -588,17 +603,20 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) /* * Check for existing macro context or construct a new one. */ - handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); + scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); - if (handle == NULL) { - if (macCreateHandle(&handle, pairs)) { + if (!scope) { + scope = (Scope*)calloc(1, sizeof(*scope)); + if (!scope || macCreateHandle(&scope->handle, pairs)) { errlogMessage("iocsh: macCreateHandle failed."); free(redirects); + free(scope); return -1; } - epicsThreadPrivateSet(iocshMacroHandleId, (void *) handle); + epicsThreadPrivateSet(iocshScopeId, (void *) scope); } + handle = scope->handle; macPushScope(handle); macInstallMacros(handle, defines); @@ -837,12 +855,15 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (iarg == piocshFuncDef->nargs) { startRedirect(filename, lineno, redirects); /* execute */ + scope->errored = false; try { (*found->def.func)(argBuf); } catch(std::exception& e){ fprintf(epicsGetStderr(), "c++ error: %s\n", e.what()); + scope->errored = true; } catch(...) { fprintf(epicsGetStderr(), "c++ error unknown\n"); + scope->errored = true; } break; } @@ -877,15 +898,33 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } else { showError(filename, lineno, "Command %s not found.", argv[0]); + scope->errored = true; } } stopRedirect(filename, lineno, redirects); + if(!commandLine && !scope->errored) { + if(scope->onerr==Continue) { + } else if(scope->onerr==Break) { + ret = -1; + break; + } else if(scope->onerr==Halt) { + ret = -1; + if(scope->timeout<=0.0) { + epicsThreadSuspendSelf(); + } else { + fprintf(epicsGetStderr(), "Wait %f sec\n", scope->timeout); + epicsThreadSleep(scope->timeout); + } + break; + } + } } macPopScope(handle); if (handle->level == 0) { macDeleteHandle(handle); - epicsThreadPrivateSet(iocshMacroHandleId, NULL); + free(scope); + epicsThreadPrivateSet(iocshScopeId, NULL); } if (fp && (fp != stdin)) fclose (fp); @@ -900,7 +939,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (readlineContext) epicsReadlineEnd(readlineContext); epicsThreadSetOkToBlock(wasOkToBlock); - return 0; + return ret; } /* @@ -952,13 +991,13 @@ iocshRun(const char *cmd, const char *macros) void epicsShareAPI iocshEnvClear(const char *name) { - MAC_HANDLE *handle; + Scope *scope; - if (iocshMacroHandleId) { - handle = (MAC_HANDLE *) epicsThreadPrivateGet(iocshMacroHandleId); + if (iocshScopeId) { + scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); - if (handle != NULL) { - macPutValue(handle, name, NULL); + if (scope != NULL) { + macPutValue(scope->handle, name, NULL); } } } @@ -1063,6 +1102,41 @@ static void iocshRunCallFunc(const iocshArgBuf *args) iocshRun(args[0].sval, args[1].sval); } +/* on */ +static const iocshArg onArg0 = { "...", iocshArgArgv }; +static const iocshArg *onArgs[1] = {&onArg0}; +static const iocshFuncDef onFuncDef = {"on", 1, onArgs}; +static void onCallFunc(const iocshArgBuf *args) +{ + Scope *scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); + + if(!scope || args->aval.ac<=2) { + } else if(strcmp(args->aval.av[1], "error")==0) { + if(args->aval.ac==2) { + } else if(strcmp(args->aval.av[2], "continue")==0) { + scope->onerr = Continue; + return; + + } else if(strcmp(args->aval.av[2], "break")==0) { + scope->onerr = Break; + return; + + } else if(strcmp(args->aval.av[2], "halt")==0) { + scope->onerr = Halt; + scope->timeout = 0.0; + return; + + } else if(strcmp(args->aval.av[2], "wait")==0) { + scope->onerr = Halt; + if(args->aval.ac==3 || !epicsParseDouble(args->aval.av[3], &scope->timeout, NULL)) { + scope->timeout = 5.0; + } + return; + } + } + fprintf(epicsGetStderr(), "Invalid 'on'\n"); +} + /* * Dummy internal commands -- register and install in command table * so they show up in the help display @@ -1092,6 +1166,7 @@ static void localRegister (void) iocshRegister(&iocshCmdFuncDef,iocshCmdCallFunc); iocshRegister(&iocshLoadFuncDef,iocshLoadCallFunc); iocshRegister(&iocshRunFuncDef,iocshRunCallFunc); + iocshRegister(&onFuncDef, onCallFunc); } } /* extern "C" */ From eba8a13a2c1ba9fdfdea1380de636fc3c88824be Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 2 May 2019 20:18:12 -0700 Subject: [PATCH 025/281] iocsh allow setting of error code --- modules/libcom/src/iocsh/iocsh.cpp | 11 +++++++++++ modules/libcom/src/iocsh/iocsh.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 57e8be671..2e64e8b05 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -511,6 +511,17 @@ typedef struct { bool errored; } Scope; +int iocshSetError(int err) +{ + Scope *scope; + if (err && iocshScopeId) { + scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); + + if(scope) scope->errored = 1; + } + return err; +} + /* * The body of the command interpreter */ diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h index 84b38f224..2e8dc225e 100644 --- a/modules/libcom/src/iocsh/iocsh.h +++ b/modules/libcom/src/iocsh/iocsh.h @@ -89,6 +89,8 @@ epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd); epicsShareFunc int epicsShareAPI iocshLoad(const char *pathname, const char* macros); epicsShareFunc int epicsShareAPI iocshRun(const char *cmd, const char* macros); +epicsShareFunc int iocshSetError(int err); + /* Makes macros that shadow environment variables work correctly with epicsEnvSet */ epicsShareFunc void epicsShareAPI iocshEnvClear(const char *name); From 4d5a677239ecc2f0224c0dcc2bbbc92c5134f1a4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 2 May 2019 20:24:47 -0700 Subject: [PATCH 026/281] use iocshSetError() --- modules/database/src/ioc/as/asIocRegister.c | 2 +- modules/database/src/ioc/db/dbIocRegister.c | 4 ++-- .../database/src/ioc/dbtemplate/dbtoolsIocRegister.c | 2 +- modules/database/src/ioc/misc/miscIocRegister.c | 10 +++++----- .../database/src/tools/registerRecordDeviceDriver.pl | 2 +- modules/libcom/src/iocsh/libComRegister.c | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/database/src/ioc/as/asIocRegister.c b/modules/database/src/ioc/as/asIocRegister.c index 16cba90c6..d5926a551 100644 --- a/modules/database/src/ioc/as/asIocRegister.c +++ b/modules/database/src/ioc/as/asIocRegister.c @@ -39,7 +39,7 @@ static void asSetSubstitutionsCallFunc(const iocshArgBuf *args) static const iocshFuncDef asInitFuncDef = {"asInit",0}; static void asInitCallFunc(const iocshArgBuf *args) { - asInit(); + iocshSetError(asInit()); } /* asdbdump */ diff --git a/modules/database/src/ioc/db/dbIocRegister.c b/modules/database/src/ioc/db/dbIocRegister.c index c40af92c1..afb31151d 100644 --- a/modules/database/src/ioc/db/dbIocRegister.c +++ b/modules/database/src/ioc/db/dbIocRegister.c @@ -39,7 +39,7 @@ static const iocshFuncDef dbLoadDatabaseFuncDef = {"dbLoadDatabase",3,dbLoadDatabaseArgs}; static void dbLoadDatabaseCallFunc(const iocshArgBuf *args) { - dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval); + iocshSetError(dbLoadDatabase(args[0].sval,args[1].sval,args[2].sval)); } /* dbLoadRecords */ @@ -49,7 +49,7 @@ static const iocshArg * const dbLoadRecordsArgs[2] = {&dbLoadRecordsArg0,&dbLoad static const iocshFuncDef dbLoadRecordsFuncDef = {"dbLoadRecords",2,dbLoadRecordsArgs}; static void dbLoadRecordsCallFunc(const iocshArgBuf *args) { - dbLoadRecords(args[0].sval,args[1].sval); + iocshSetError(dbLoadRecords(args[0].sval,args[1].sval)); } /* dbb */ diff --git a/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c b/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c index 201a32398..879f67e19 100644 --- a/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c +++ b/modules/database/src/ioc/dbtemplate/dbtoolsIocRegister.c @@ -22,7 +22,7 @@ static const iocshFuncDef dbLoadTemplateFuncDef = {"dbLoadTemplate", 2, dbLoadTemplateArgs}; static void dbLoadTemplateCallFunc(const iocshArgBuf *args) { - dbLoadTemplate(args[0].sval, args[1].sval); + iocshSetError(dbLoadTemplate(args[0].sval, args[1].sval)); } diff --git a/modules/database/src/ioc/misc/miscIocRegister.c b/modules/database/src/ioc/misc/miscIocRegister.c index 6c08ef0c9..4dffdfca0 100644 --- a/modules/database/src/ioc/misc/miscIocRegister.c +++ b/modules/database/src/ioc/misc/miscIocRegister.c @@ -22,28 +22,28 @@ static const iocshFuncDef iocInitFuncDef = {"iocInit",0,NULL}; static void iocInitCallFunc(const iocshArgBuf *args) { - iocInit(); + iocshSetError(iocInit()); } /* iocBuild */ static const iocshFuncDef iocBuildFuncDef = {"iocBuild",0,NULL}; static void iocBuildCallFunc(const iocshArgBuf *args) { - iocBuild(); + iocshSetError(iocBuild()); } /* iocRun */ static const iocshFuncDef iocRunFuncDef = {"iocRun",0,NULL}; static void iocRunCallFunc(const iocshArgBuf *args) { - iocRun(); + iocshSetError(iocRun()); } /* iocPause */ static const iocshFuncDef iocPauseFuncDef = {"iocPause",0,NULL}; static void iocPauseCallFunc(const iocshArgBuf *args) { - iocPause(); + iocshSetError(iocPause()); } /* coreRelease */ @@ -77,7 +77,7 @@ static const iocshArg * const systemArgs[] = {&systemArg0}; static const iocshFuncDef systemFuncDef = {"system",1,systemArgs}; static void systemCallFunc(const iocshArgBuf *args) { - system(args[0].sval); + iocshSetError(system(args[0].sval)); } #endif diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 02bb9b772..10147db4b 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -277,7 +277,7 @@ static const iocshFuncDef rrddFuncDef = {"$subname", 1, rrddArgs}; static void rrddCallFunc(const iocshArgBuf *) { - $subname(*iocshPpdbbase); + iocshSetError($subname(*iocshPpdbbase)); } } // extern "C" diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index b105ea12f..11396e984 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -76,7 +76,7 @@ static const iocshFuncDef chdirFuncDef = {"cd",1,chdirArgs}; static void chdirCallFunc(const iocshArgBuf *args) { if (args[0].sval == NULL || - chdir(args[0].sval)) { + iocshSetError(chdir(args[0].sval))) { fprintf(stderr, "Invalid directory path, ignored\n"); } } From 73cdea5517d625243ba149abf4a1368fbae8fe81 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 May 2019 19:02:13 -0700 Subject: [PATCH 027/281] as-hostname address review comments --- documentation/RELEASE_NOTES.html | 22 ++++++++++++++++++++ modules/database/src/ioc/rsrv/camessage.c | 4 ++-- modules/database/src/ioc/rsrv/caservertask.c | 2 +- modules/libcom/src/as/asLib.h | 2 +- modules/libcom/src/as/asLibRoutines.c | 4 ++-- modules/libcom/src/iocsh/libComRegister.c | 6 +++--- modules/libcom/test/aslibtest.c | 8 +++---- 7 files changed, 35 insertions(+), 13 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 63f8880a7..25f0eac62 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -26,6 +26,28 @@ release.

--> +

ACF Hostname from DNS

+ +

ACF hostname has so far been a string provided by a CA client, +which may or may not agree with DNS. An option is now available +to cause IOCs to resolve hostnames, and compare against the actual +client IP address.

+

This resolution is done at ACF file load time, +which has two consequences.

+ +
    +
  • Slow/unavailable DNS will cause problems during ACF file +loading. eg. during IOC start.
  • +
  • Changes in host -> IP mapping will not be picked up until/unless +the ACF file is reloaded.
  • +
+ +

This may be enabled with:

+ +
+var("asCheckClientIP",1)
+
+

Launchpad Bugs

The list of tracked bugs fixed in this release can be found on the diff --git a/modules/database/src/ioc/rsrv/camessage.c b/modules/database/src/ioc/rsrv/camessage.c index 40448d018..f54bb4888 100644 --- a/modules/database/src/ioc/rsrv/camessage.c +++ b/modules/database/src/ioc/rsrv/camessage.c @@ -862,9 +862,9 @@ static int host_name_action ( caHdrLargeArray *mp, void *pPayload, } /* after all validation */ - if(asUseIP) { + if(asCheckClientIP) { - DLOG (2, ( "CAS: host_name_action for \"%s\" ignores clist provided host name\n", + DLOG (2, ( "CAS: host_name_action for \"%s\" ignores client provided host name\n", client->pHostName ) ); return RSRV_OK; } diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index 048487b20..7a9ae63b3 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -1421,7 +1421,7 @@ struct client *create_tcp_client (SOCKET sock , const osiSockAddr *peerAddr) } client->addr = peerAddr->ia; - if(asUseIP) { + if(asCheckClientIP) { epicsUInt32 ip = ntohl(client->addr.sin_addr.s_addr); client->pHostName = malloc(24); if(!client->pHostName) { diff --git a/modules/libcom/src/as/asLib.h b/modules/libcom/src/as/asLib.h index b4e5139ce..a29cf3b65 100644 --- a/modules/libcom/src/as/asLib.h +++ b/modules/libcom/src/as/asLib.h @@ -24,7 +24,7 @@ extern "C" { /* 0 - Use (unverified) client provided host name string. * 1 - Use actual client IP address. HAG() are resolved to IPs at ACF load time. */ -epicsShareExtern int asUseIP; +epicsShareExtern int asCheckClientIP; typedef struct asgMember *ASMEMBERPVT; typedef struct asgClient *ASCLIENTPVT; diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index ceade030e..e3105facd 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -29,7 +29,7 @@ #include "postfix.h" #include "asLib.h" -int asUseIP; +int asCheckClientIP; static epicsMutexId asLock; #define LOCK epicsMutexMustLock(asLock) @@ -1210,7 +1210,7 @@ static long asHagAddHost(HAG *phag,const char *host) int len, i; if (!phag) return 0; - if(!asUseIP) { + if(!asCheckClientIP) { len = strlen(host); phagname = asCalloc(1, sizeof(HAGNAME) + len + 1); phagname->host = (char *)(phagname + 1); diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index 2bbb09f3e..c842dce27 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -393,7 +393,7 @@ static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) installLastResortEventProvider(); } -static iocshVarDef asUseIPDef = {"asUseIP", iocshArgInt, 0}; +static iocshVarDef asCheckClientIPDef = {"asCheckClientIP", iocshArgInt, 0}; void epicsShareAPI libComRegister(void) { @@ -428,6 +428,6 @@ void epicsShareAPI libComRegister(void) iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc); iocshRegister(&installLastResortEventProviderFuncDef, installLastResortEventProviderCallFunc); - asUseIPDef.pval = &asUseIP; - iocshRegisterVariable(&asUseIPDef); + asCheckClientIPDef.pval = &asCheckClientIP; + iocshRegisterVariable(&asCheckClientIPDef); } diff --git a/modules/libcom/test/aslibtest.c b/modules/libcom/test/aslibtest.c index 367a12426..4237fafb1 100644 --- a/modules/libcom/test/aslibtest.c +++ b/modules/libcom/test/aslibtest.c @@ -82,7 +82,7 @@ static const char hostname_config[] = "" static void testHostNames(void) { testDiag("testHostNames()"); - asUseIP = 0; + asCheckClientIP = 0; testOk1(asInitMem(hostname_config, NULL)==0); @@ -102,7 +102,7 @@ static void testHostNames(void) testAccess("ro", 0); testAccess("rw", 0); - setHost("nosuchhost"); + setHost("guaranteed.invalid."); testAccess("invalid", 0); testAccess("DEFAULT", 0); @@ -113,7 +113,7 @@ static void testHostNames(void) static void testUseIP(void) { testDiag("testUseIP()"); - asUseIP = 1; + asCheckClientIP = 1; /* still host names in .acf */ testOk1(asInitMem(hostname_config, NULL)==0); @@ -135,7 +135,7 @@ static void testUseIP(void) testAccess("ro", 1); testAccess("rw", 3); - setHost("nosuchhost"); + setHost("guaranteed.invalid."); testAccess("invalid", 0); testAccess("DEFAULT", 0); From 251304e280c023ed72031d25981d6db4bd0b73d4 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 13 May 2019 09:43:44 +0200 Subject: [PATCH 028/281] use dynamic binding of vxWorks BSP functions because some BSPs don't provide them --- .../libcom/src/osi/os/vxWorks/devLibVMEOSD.c | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c b/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c index 82bec603d..93d30fc38 100644 --- a/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c +++ b/modules/libcom/src/osi/os/vxWorks/devLibVMEOSD.c @@ -110,7 +110,21 @@ static long vxDevWriteProbe (unsigned wordSize, volatile void *ptr, const void * static void *devA24Malloc(size_t size); static void devA24Free(void *pBlock); -static long devInit(void) { return 0;} + +/* We don't know which functions are implemented in the BSP */ +static int (*sysIntEnableFunc)(int) = NULL; +static int (*sysIntDisableFunc)(int) = NULL; +static int (*sysIntEnablePICFunc)(int) = NULL; +static int (*sysIntDisablePICFunc)(int) = NULL; + +static long devInit(void) +{ + sysIntEnableFunc = epicsFindSymbol ("sysIntEnable"); + sysIntDisableFunc = epicsFindSymbol ("sysIntDisable"); + sysIntDisablePICFunc = epicsFindSymbol ("sysIntDisablePIC"); + sysIntEnablePICFunc = epicsFindSymbol ("sysIntEnablePIC"); + return 0; +} static long vxDevConnectInterruptVME ( unsigned vectorNumber, @@ -214,16 +228,16 @@ static long vxDevDisconnectInterruptVME ( */ static long vxDevEnableInterruptLevelVME (unsigned level) { -# if CPU_FAMILY != I80X86 + if (sysIntEnableFunc) { int s; - s = sysIntEnable (level); + s = sysIntEnableFunc (level); if (s!=OK) { return S_dev_intEnFail; } return 0; -# else + } else { return S_dev_intEnFail; -# endif + } } /* @@ -231,16 +245,16 @@ static long vxDevEnableInterruptLevelVME (unsigned level) */ long devEnableInterruptLevelISA (unsigned level) { -# if CPU_FAMILY == I80X86 + if (sysIntEnablePICFunc) { int s; - s = sysIntEnablePIC (level); + s = sysIntEnablePICFunc (level); if (s!=OK) { return S_dev_intEnFail; } return 0; -# else + } else { return S_dev_intEnFail; -# endif + } } /* @@ -248,15 +262,15 @@ long devEnableInterruptLevelISA (unsigned level) */ long devDisableInterruptLevelISA (unsigned level) { -# if CPU_FAMILY == I80X86 + if (sysIntDisablePICFunc) { int s; - s = sysIntDisablePIC (level); + s = sysIntDisablePICFunc (level); if (s!=OK) { return S_dev_intEnFail; } -# else + } else { return S_dev_intEnFail; -# endif + } return 0; } @@ -266,16 +280,16 @@ long devDisableInterruptLevelISA (unsigned level) */ static long vxDevDisableInterruptLevelVME (unsigned level) { -# if CPU_FAMILY != I80X86 + if (sysIntDisableFunc) { int s; - s = sysIntDisable (level); + s = sysIntDisableFunc (level); if (s!=OK) { return S_dev_intDissFail; } return 0; -# else + } else { return S_dev_intEnFail; -# endif + } } /* From 6eb6cc0d805e3ccab87963895b9a94f1c4485035 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 13 May 2019 14:52:10 -0500 Subject: [PATCH 029/281] Expand Release Note entry for as-hostname changes. --- documentation/RELEASE_NOTES.html | 46 ++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 25f0eac62..376279fc9 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -26,28 +26,46 @@ release.

--> -

ACF Hostname from DNS

+

Channel Access Security: Check Hostname Against DNS

-

ACF hostname has so far been a string provided by a CA client, -which may or may not agree with DNS. An option is now available -to cause IOCs to resolve hostnames, and compare against the actual -client IP address.

-

This resolution is done at ACF file load time, -which has two consequences.

+

Host names given in a HAG entry of an IOC's Access Security +Configuration File (ACF) have to date been compared against the hostname +provided by the CA client at connection time, which may or may not be the actual +name of that client. This allows rogue clients to pretend to be a different +host, and the IOC would believe them.

-
    -
  • Slow/unavailable DNS will cause problems during ACF file -loading. eg. during IOC start.
  • -
  • Changes in host -> IP mapping will not be picked up until/unless -the ACF file is reloaded.
  • -
+

An option is now available to cause an IOC to ask its operating system to +look up the IP address of any hostnames listed in its ACF (which will normally +be done using the DNS or the /etc/hosts file). The IOC will then +compare the resulting IP address against the client's actual IP address when +checking access permissions at connection time. This name resolution gets done +at ACF file load time, which has a few consequences:

-

This may be enabled with:

+
    + +
  1. If the DNS is slow when the names are resolved this will delay the process +of loading the ACF file.
  2. + +
  3. If a host name cannot be resolved the IOC will treat the ACF as invalid, +which prevents any CA clients from connecting.
  4. + +
  5. Any changes in the hostname to IP address mapping will not be picked up by +the IOC unless and until the ACF file gets reloaded.
  6. + +
+ +

This feature can be enabled before iocInit with

 var("asCheckClientIP",1)
 
+

or with the VxWorks target shell use

+ +
+asCheckClientIP = 1
+
+

Launchpad Bugs

The list of tracked bugs fixed in this release can be found on the From 76506991da5ba163f26de43bff367ae336f2fe2b Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Fri, 24 May 2019 14:15:40 -0700 Subject: [PATCH 030/281] Fixed logic errors and added some prompts. --- modules/libcom/src/iocsh/iocsh.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 2e64e8b05..6fea9c4c4 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -913,20 +913,22 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } } stopRedirect(filename, lineno, redirects); - if(!commandLine && !scope->errored) { + if(!commandLine && scope->errored) { if(scope->onerr==Continue) { } else if(scope->onerr==Break) { + fprintf(epicsGetStderr(), "iocsh Error: Break\n" ); ret = -1; break; } else if(scope->onerr==Halt) { ret = -1; if(scope->timeout<=0.0) { + fprintf(epicsGetStderr(), "iocsh Error: Halt\n" ); epicsThreadSuspendSelf(); + break; } else { - fprintf(epicsGetStderr(), "Wait %f sec\n", scope->timeout); + fprintf(epicsGetStderr(), "iocsh Error: Waiting %f sec ...\n", scope->timeout); epicsThreadSleep(scope->timeout); } - break; } } } @@ -1114,7 +1116,7 @@ static void iocshRunCallFunc(const iocshArgBuf *args) } /* on */ -static const iocshArg onArg0 = { "...", iocshArgArgv }; +static const iocshArg onArg0 = { "'error' 'continue' | 'break' | 'wait' [value] | 'halt'", iocshArgArgv }; static const iocshArg *onArgs[1] = {&onArg0}; static const iocshFuncDef onFuncDef = {"on", 1, onArgs}; static void onCallFunc(const iocshArgBuf *args) @@ -1133,15 +1135,15 @@ static void onCallFunc(const iocshArgBuf *args) return; } else if(strcmp(args->aval.av[2], "halt")==0) { - scope->onerr = Halt; scope->timeout = 0.0; + scope->onerr = Halt; return; } else if(strcmp(args->aval.av[2], "wait")==0) { - scope->onerr = Halt; - if(args->aval.ac==3 || !epicsParseDouble(args->aval.av[3], &scope->timeout, NULL)) { + if(args->aval.ac<=3 || epicsParseDouble(args->aval.av[3], &scope->timeout, NULL)) { scope->timeout = 5.0; } + scope->onerr = Halt; return; } } From 52b9c8b947a817ea31de767da3c9c413a5fd6945 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 27 May 2019 21:24:18 -0700 Subject: [PATCH 031/281] iocsh further on error Split Scope into iocshContext and iocshScope to separate per-thread and per-call state. Error handling is per-call. --- modules/libcom/src/iocsh/iocsh.cpp | 149 +++++++++++++++++------------ 1 file changed, 87 insertions(+), 62 deletions(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 6fea9c4c4..26ecb5b01 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -20,6 +20,7 @@ #include #define epicsExportSharedSymbols +#include "epicsMath.h" #include "errlog.h" #include "macLib.h" #include "epicsStdio.h" @@ -58,7 +59,7 @@ static char iocshVarID[] = "iocshVar"; extern "C" { static void varCallFunc(const iocshArgBuf *); } static epicsMutexId iocshTableMutex; static epicsThreadOnceId iocshOnceId = EPICS_THREAD_ONCE_INIT; -static epicsThreadPrivateId iocshScopeId; +static epicsThreadPrivateId iocshContextId; /* * I/O redirection @@ -78,7 +79,7 @@ struct iocshRedirect { static void iocshOnce (void *) { iocshTableMutex = epicsMutexMustCreate (); - iocshScopeId = epicsThreadPrivateCreate(); + iocshContextId = epicsThreadPrivateCreate(); } static void iocshInit (void) @@ -504,20 +505,29 @@ typedef enum { Halt } OnError; -typedef struct { - MAC_HANDLE *handle; +// per call to iocshBody() +struct iocshScope { + iocshScope *outer; OnError onerr; double timeout; bool errored; -} Scope; + bool interactive; + iocshScope() :outer(0), onerr(Continue), timeout(0.0), errored(false), interactive(false) {} +}; + +// per thread executing iocshBody() +struct iocshContext { + MAC_HANDLE *handle; + iocshScope *scope; +}; int iocshSetError(int err) { - Scope *scope; - if (err && iocshScopeId) { - scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); + iocshContext *ctxt; + if (err && iocshContextId) { + ctxt = (iocshContext *) epicsThreadPrivateGet(iocshContextId); - if(scope) scope->errored = 1; + if(ctxt && ctxt->scope) ctxt->scope->errored = 1; } return err; } @@ -550,8 +560,8 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) void *readlineContext = NULL; int wasOkToBlock; static const char * pairs[] = {"", "environ", NULL, NULL}; - Scope *scope; - MAC_HANDLE *handle; + iocshScope scope; + iocshContext *context; char ** defines = NULL; int ret = 0; @@ -562,8 +572,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) */ if (commandLine == NULL) { if ((pathname == NULL) || (strcmp (pathname, "") == 0)) { - if ((prompt = envGetConfigParamPtr(&IOCSH_PS1)) == NULL) + if ((prompt = envGetConfigParamPtr(&IOCSH_PS1)) == NULL) { prompt = "epics> "; + } + scope.interactive = true; } else { fp = fopen (pathname, "r"); @@ -614,21 +626,24 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) /* * Check for existing macro context or construct a new one. */ - scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); - - if (!scope) { - scope = (Scope*)calloc(1, sizeof(*scope)); - if (!scope || macCreateHandle(&scope->handle, pairs)) { + context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); + + if (!context) { + context = (iocshContext*)calloc(1, sizeof(*context)); + if (!context || macCreateHandle(&context->handle, pairs)) { errlogMessage("iocsh: macCreateHandle failed."); free(redirects); - free(scope); + free(context); return -1; } - epicsThreadPrivateSet(iocshScopeId, (void *) scope); + epicsThreadPrivateSet(iocshContextId, (void *) context); } - handle = scope->handle; - + MAC_HANDLE *handle = context->handle; + + scope.outer = context->scope; + context->scope = &scope; + macPushScope(handle); macInstallMacros(handle, defines); @@ -866,15 +881,15 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (iarg == piocshFuncDef->nargs) { startRedirect(filename, lineno, redirects); /* execute */ - scope->errored = false; + scope.errored = false; try { (*found->def.func)(argBuf); } catch(std::exception& e){ fprintf(epicsGetStderr(), "c++ error: %s\n", e.what()); - scope->errored = true; + scope.errored = true; } catch(...) { fprintf(epicsGetStderr(), "c++ error unknown\n"); - scope->errored = true; + scope.errored = true; } break; } @@ -909,35 +924,42 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } else { showError(filename, lineno, "Command %s not found.", argv[0]); - scope->errored = true; + scope.errored = true; } } stopRedirect(filename, lineno, redirects); - if(!commandLine && scope->errored) { - if(scope->onerr==Continue) { - } else if(scope->onerr==Break) { + + if(!scope.interactive && scope.errored) { + if(scope.onerr==Continue) { + /* do nothing */ + + } else if(scope.onerr==Break) { + ret = -1; fprintf(epicsGetStderr(), "iocsh Error: Break\n" ); - ret = -1; break; - } else if(scope->onerr==Halt) { + + } else if(scope.onerr==Halt) { ret = -1; - if(scope->timeout<=0.0) { + if(scope.timeout<=0.0 || isinf(scope.timeout)) { fprintf(epicsGetStderr(), "iocsh Error: Halt\n" ); epicsThreadSuspendSelf(); break; + } else { - fprintf(epicsGetStderr(), "iocsh Error: Waiting %f sec ...\n", scope->timeout); - epicsThreadSleep(scope->timeout); + fprintf(epicsGetStderr(), "iocsh Error: Waiting %f sec ...\n", scope.timeout); + epicsThreadSleep(scope.timeout); } } } } macPopScope(handle); - if (handle->level == 0) { + if (!scope.outer) { macDeleteHandle(handle); - free(scope); - epicsThreadPrivateSet(iocshScopeId, NULL); + free(context); + epicsThreadPrivateSet(iocshContextId, NULL); + } else { + context->scope = scope.outer; } if (fp && (fp != stdin)) fclose (fp); @@ -1004,13 +1026,13 @@ iocshRun(const char *cmd, const char *macros) void epicsShareAPI iocshEnvClear(const char *name) { - Scope *scope; + iocshContext *context; - if (iocshScopeId) { - scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); + if (iocshContextId) { + context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); - if (scope != NULL) { - macPutValue(scope->handle, name, NULL); + if (context != NULL) { + macPutValue(context->handle, name, NULL); } } } @@ -1121,33 +1143,36 @@ static const iocshArg *onArgs[1] = {&onArg0}; static const iocshFuncDef onFuncDef = {"on", 1, onArgs}; static void onCallFunc(const iocshArgBuf *args) { - Scope *scope = (Scope *) epicsThreadPrivateGet(iocshScopeId); + iocshContext *context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); - if(!scope || args->aval.ac<=2) { - } else if(strcmp(args->aval.av[1], "error")==0) { - if(args->aval.ac==2) { - } else if(strcmp(args->aval.av[2], "continue")==0) { - scope->onerr = Continue; - return; + if(!context || !context->scope) { + // we are not called through iocshBody()... - } else if(strcmp(args->aval.av[2], "break")==0) { - scope->onerr = Break; - return; + } else if(args->aval.ac<3 || strcmp(args->aval.av[1], "error")!=0) { + fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n"); - } else if(strcmp(args->aval.av[2], "halt")==0) { - scope->timeout = 0.0; - scope->onerr = Halt; - return; + } else if(context->scope->interactive) { + fprintf(epicsGetStderr(), "Interactive shell ignores on error ...\n"); - } else if(strcmp(args->aval.av[2], "wait")==0) { - if(args->aval.ac<=3 || epicsParseDouble(args->aval.av[3], &scope->timeout, NULL)) { - scope->timeout = 5.0; - } - scope->onerr = Halt; - return; + } else if(strcmp(args->aval.av[2], "continue")==0) { + context->scope->onerr = Continue; + + } else if(strcmp(args->aval.av[2], "break")==0) { + context->scope->onerr = Break; + + } else if(strcmp(args->aval.av[2], "halt")==0) { + context->scope->onerr = Halt; + context->scope->timeout = 0.0; + + } else if(strcmp(args->aval.av[2], "wait")==0) { + context->scope->onerr = Halt; + if(args->aval.ac==3 || epicsParseDouble(args->aval.av[3], &context->scope->timeout, NULL)) { + context->scope->timeout = 5.0; } + + } else { + fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n"); } - fprintf(epicsGetStderr(), "Invalid 'on'\n"); } /* From 72985505ef4c375dbf07e2fbb58bdb6168c7167b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Jun 2019 10:27:55 +0200 Subject: [PATCH 032/281] further no need to search for perl modules under bin --- modules/ca/src/perl/capr.pl | 1 - modules/ca/src/template/top/caPerlApp/caget.pl | 1 - modules/ca/src/template/top/caPerlApp/cainfo.pl | 1 - modules/ca/src/template/top/caPerlApp/camonitor.pl | 1 - modules/ca/src/template/top/caPerlApp/caput.pl | 1 - modules/database/src/tools/dbExpand.pl | 1 - modules/database/src/tools/dbdExpand.pl | 1 - modules/database/src/tools/dbdReport.pl | 1 - modules/database/src/tools/dbdToHtml.pl | 1 - modules/database/src/tools/dbdToMenuH.pl | 1 - modules/database/src/tools/dbdToRecordtypeH.pl | 1 - modules/database/src/tools/registerRecordDeviceDriver.pl | 1 - modules/libcom/src/env/bldEnvData.pl | 1 - 13 files changed, 13 deletions(-) diff --git a/modules/ca/src/perl/capr.pl b/modules/ca/src/perl/capr.pl index 17a6dd04b..21e56ecd9 100644 --- a/modules/ca/src/perl/capr.pl +++ b/modules/ca/src/perl/capr.pl @@ -11,7 +11,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use Getopt::Std; use EPICS::Path; diff --git a/modules/ca/src/template/top/caPerlApp/caget.pl b/modules/ca/src/template/top/caPerlApp/caget.pl index dae3a778a..d206d8a36 100644 --- a/modules/ca/src/template/top/caPerlApp/caget.pl +++ b/modules/ca/src/template/top/caPerlApp/caget.pl @@ -6,7 +6,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; -no lib $Bin; use Getopt::Std; use Scalar::Util qw(looks_like_number); diff --git a/modules/ca/src/template/top/caPerlApp/cainfo.pl b/modules/ca/src/template/top/caPerlApp/cainfo.pl index 37c705e26..4d4a1ffbe 100644 --- a/modules/ca/src/template/top/caPerlApp/cainfo.pl +++ b/modules/ca/src/template/top/caPerlApp/cainfo.pl @@ -6,7 +6,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; -no lib $Bin; use Getopt::Std; use CA; diff --git a/modules/ca/src/template/top/caPerlApp/camonitor.pl b/modules/ca/src/template/top/caPerlApp/camonitor.pl index 15c0212f0..c426fa536 100644 --- a/modules/ca/src/template/top/caPerlApp/camonitor.pl +++ b/modules/ca/src/template/top/caPerlApp/camonitor.pl @@ -6,7 +6,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; -no lib $Bin; use Getopt::Std; use Scalar::Util qw(looks_like_number); diff --git a/modules/ca/src/template/top/caPerlApp/caput.pl b/modules/ca/src/template/top/caPerlApp/caput.pl index b08c9d200..03842d397 100644 --- a/modules/ca/src/template/top/caPerlApp/caput.pl +++ b/modules/ca/src/template/top/caPerlApp/caput.pl @@ -6,7 +6,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; -no lib $Bin; use Getopt::Std; use CA; diff --git a/modules/database/src/tools/dbExpand.pl b/modules/database/src/tools/dbExpand.pl index e4088d007..6596e4361 100644 --- a/modules/database/src/tools/dbExpand.pl +++ b/modules/database/src/tools/dbExpand.pl @@ -13,7 +13,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdExpand.pl b/modules/database/src/tools/dbdExpand.pl index 7e9ba8b5a..74e81eb76 100644 --- a/modules/database/src/tools/dbdExpand.pl +++ b/modules/database/src/tools/dbdExpand.pl @@ -11,7 +11,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdReport.pl b/modules/database/src/tools/dbdReport.pl index 8a82d690b..3f2269d8b 100644 --- a/modules/database/src/tools/dbdReport.pl +++ b/modules/database/src/tools/dbdReport.pl @@ -9,7 +9,6 @@ use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdToHtml.pl b/modules/database/src/tools/dbdToHtml.pl index 87fc23230..66d46f949 100644 --- a/modules/database/src/tools/dbdToHtml.pl +++ b/modules/database/src/tools/dbdToHtml.pl @@ -11,7 +11,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use DBD; use DBD::Parser; diff --git a/modules/database/src/tools/dbdToMenuH.pl b/modules/database/src/tools/dbdToMenuH.pl index e80ae3340..76aff7dac 100644 --- a/modules/database/src/tools/dbdToMenuH.pl +++ b/modules/database/src/tools/dbdToMenuH.pl @@ -9,7 +9,6 @@ use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use EPICS::Getopts; use File::Basename; diff --git a/modules/database/src/tools/dbdToRecordtypeH.pl b/modules/database/src/tools/dbdToRecordtypeH.pl index 028309fc4..891b5b5c5 100644 --- a/modules/database/src/tools/dbdToRecordtypeH.pl +++ b/modules/database/src/tools/dbdToRecordtypeH.pl @@ -9,7 +9,6 @@ use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use EPICS::Getopts; use File::Basename; diff --git a/modules/database/src/tools/registerRecordDeviceDriver.pl b/modules/database/src/tools/registerRecordDeviceDriver.pl index 507385e57..acbcc517c 100644 --- a/modules/database/src/tools/registerRecordDeviceDriver.pl +++ b/modules/database/src/tools/registerRecordDeviceDriver.pl @@ -13,7 +13,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use DBD; use DBD::Parser; diff --git a/modules/libcom/src/env/bldEnvData.pl b/modules/libcom/src/env/bldEnvData.pl index 180d63870..693be65da 100644 --- a/modules/libcom/src/env/bldEnvData.pl +++ b/modules/libcom/src/env/bldEnvData.pl @@ -15,7 +15,6 @@ use strict; use FindBin qw($Bin); use lib ("$Bin/../../lib/perl"); -no lib $Bin; use Getopt::Std; use File::Basename; From ac87fbac852bc8f1ec22dd7ffb0661dd8648f71f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Jun 2019 11:18:58 +0200 Subject: [PATCH 033/281] simplify e_flex/antelope path compute --- configure/CONFIG_LIBCOM_MODULE | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/configure/CONFIG_LIBCOM_MODULE b/configure/CONFIG_LIBCOM_MODULE index 175606cdb..32bb937c2 100644 --- a/configure/CONFIG_LIBCOM_MODULE +++ b/configure/CONFIG_LIBCOM_MODULE @@ -5,18 +5,10 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -# Set EPICS_LIBCOM if necessary -ifndef EPICS_LIBCOM - EPICS_LIBCOM = $(if $(BUILDING_LIBCOM),$(INSTALL_LOCATION),$(EPICS_BASE)) - - # Paths to tools built here - EPICS_LIBCOM_HOST_BIN ?= $(EPICS_LIBCOM)/bin/$(EPICS_HOST_ARCH) -endif - # Set location of locally generated tools -YACC = $(abspath $(EPICS_LIBCOM_HOST_BIN))/antelope$(HOSTEXE) -LEX = $(abspath $(EPICS_LIBCOM_HOST_BIN))/e_flex$(HOSTEXE) \ - -S$(EPICS_LIBCOM)/include/flex.skel.static +YACC = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/antelope$(HOSTEXE) +LEX = $(abspath $(EPICS_BASE)/bin/$(EPICS_HOST_ARCH))/e_flex$(HOSTEXE) \ + -S$(EPICS_BASE)/include/flex.skel.static # Default stack size for osiThread OSITHREAD_USE_DEFAULT_STACK = NO From 932e9f3b21375e03641f9c1316b123e041ee2fe7 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Jun 2019 14:36:42 +0200 Subject: [PATCH 034/281] asLib: asUseIP name lookup soft-fail --- modules/libcom/src/as/asLibRoutines.c | 34 +++++++++++++++++---------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index e3105facd..c29fff674 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -1207,32 +1207,40 @@ static HAG *asHagAdd(const char *hagName) static long asHagAddHost(HAG *phag,const char *host) { HAGNAME *phagname; - int len, i; if (!phag) return 0; if(!asCheckClientIP) { - len = strlen(host); + size_t i, len = strlen(host); phagname = asCalloc(1, sizeof(HAGNAME) + len + 1); phagname->host = (char *)(phagname + 1); for (i = 0; i < len; i++) { phagname->host[i] = (char)tolower((int)host[i]); } + } else { struct sockaddr_in addr; epicsUInt32 ip; + if(aToIPAddr(host, 0, &addr)) { - errlogPrintf("Unable to resolve host '%s'\n", host); - return S_asLib_noHag; + static const char unresolved[] = "unresolved:"; + + errlogPrintf("ACF: Unable to resolve host '%s'\n", host); + + phagname = asCalloc(1, sizeof(HAGNAME) + sizeof(unresolved)-1+strlen(host)); + strcpy(phagname->host, unresolved); + strcat(phagname->host, host); + + } else { + ip = ntohl(addr.sin_addr.s_addr); + phagname = asCalloc(1, sizeof(HAGNAME) + 24); + phagname->host = (char *)(phagname + 1); + epicsSnprintf(phagname->host, 24, + "%u.%u.%u.%u", + (ip>>24)&0xff, + (ip>>16)&0xff, + (ip>>8)&0xff, + (ip>>0)&0xff); } - ip = ntohl(addr.sin_addr.s_addr); - phagname = asCalloc(1, sizeof(HAGNAME) + 24); - phagname->host = (char *)(phagname + 1); - epicsSnprintf(phagname->host, 24, - "%u.%u.%u.%u", - (ip>>24)&0xff, - (ip>>16)&0xff, - (ip>>8)&0xff, - (ip>>0)&0xff); } ellAdd(&phag->list, &phagname->node); return 0; From a83a85af7c730164e8e3b1c1260bd41187e81f99 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 4 Jun 2019 16:05:54 +0200 Subject: [PATCH 035/281] asLib one short --- modules/libcom/src/as/asLibRoutines.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index c29fff674..4ca1916bd 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -1226,7 +1226,7 @@ static long asHagAddHost(HAG *phag,const char *host) errlogPrintf("ACF: Unable to resolve host '%s'\n", host); - phagname = asCalloc(1, sizeof(HAGNAME) + sizeof(unresolved)-1+strlen(host)); + phagname = asCalloc(1, sizeof(HAGNAME) + sizeof(unresolved)+strlen(host)); strcpy(phagname->host, unresolved); strcat(phagname->host, host); From deb9dbcd7756edeac608948e8cd0568228d4329b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 4 Jun 2019 12:23:13 -0500 Subject: [PATCH 036/281] Added decimation filter, documentation and tests --- documentation/RELEASE_NOTES.html | 17 ++ src/std/filters/Makefile | 1 + src/std/filters/decimate.c | 115 +++++++++ src/std/filters/filters.dbd.pod | 40 +++ src/std/filters/test/Makefile | 6 + src/std/filters/test/decTest.c | 273 +++++++++++++++++++++ src/std/filters/test/epicsRunFilterTests.c | 2 + 7 files changed, 454 insertions(+) create mode 100644 src/std/filters/decimate.c create mode 100644 src/std/filters/test/decTest.c diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 8ed4e04bf..c7fbc02b2 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -16,6 +16,23 @@ +

Added new decimation channel filter

+ +

A new server-side filter has been added to the IOC for reducing the number +and frequency of monitor updates from a channel by a client-specified factor. +The filter's behaviour is quite simplistic, it passes the first monitor event it +sees to the client and then drops the next N-1 events before passing another +event. For example to sample a 60Hz channel at 1Hz, a 10Hz channel every 6 +seconds, or a 1Hz channel once every minute:

+ +
    Hal$ camonitor 'test:channel.{"dec":{"n":60}}'
+    ...
+ +

More information is included in the +filters +documentation +file.

+

Cleaning up with Multiple CA contexts in a Process

Bruno Martins reported a problem with the CA client library at shutdown in a diff --git a/src/std/filters/Makefile b/src/std/filters/Makefile index d4539898f..3a27361f6 100644 --- a/src/std/filters/Makefile +++ b/src/std/filters/Makefile @@ -15,6 +15,7 @@ dbRecStd_SRCS += ts.c dbRecStd_SRCS += dbnd.c dbRecStd_SRCS += arr.c dbRecStd_SRCS += sync.c +dbRecStd_SRCS += decimate.c HTMLS += filters.html diff --git a/src/std/filters/decimate.c b/src/std/filters/decimate.c new file mode 100644 index 000000000..d34884ebe --- /dev/null +++ b/src/std/filters/decimate.c @@ -0,0 +1,115 @@ +/*************************************************************************\ +* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2010 Brookhaven National Laboratory. +* Copyright (c) 2010 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Authors: Ralph Lange , + * Andrew Johnson + */ + +#include + +#include "freeList.h" +#include "db_field_log.h" +#include "chfPlugin.h" +#include "epicsExport.h" + +typedef struct myStruct { + epicsInt32 n, i; +} myStruct; + +static void *myStructFreeList; + +static const +chfPluginArgDef opts[] = { + chfInt32(myStruct, n, "n", 1, 0), + chfPluginArgEnd +}; + +static void * allocPvt(void) +{ + myStruct *my = (myStruct*) freeListCalloc(myStructFreeList); + return (void *) my; +} + +static void freePvt(void *pvt) +{ + freeListFree(myStructFreeList, pvt); +} + +static int parse_ok(void *pvt) +{ + myStruct *my = (myStruct*) pvt; + + if (my->n < 1) + return -1; + + return 0; +} + +static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { + db_field_log *passfl = NULL; + myStruct *my = (myStruct*) pvt; + epicsInt32 i = my->i; + + if (pfl->ctx == dbfl_context_read) + return pfl; + + if (i++ == 0) + passfl = pfl; + + if (i >= my->n) + i = 0; + + my->i = i; + return passfl; +} + +static void channelRegisterPre(dbChannel *chan, void *pvt, + chPostEventFunc **cb_out, void **arg_out, db_field_log *probe) +{ + *cb_out = filter; + *arg_out = pvt; +} + +static void channel_report(dbChannel *chan, void *pvt, int level, const unsigned short indent) +{ + myStruct *my = (myStruct*) pvt; + printf("%*sDecimate (dec): n=%d, i=%d\n", indent, "", + my->n, my->i); +} + +static chfPluginIf pif = { + allocPvt, + freePvt, + + NULL, /* parse_error, */ + parse_ok, + + NULL, /* channel_open, */ + channelRegisterPre, + NULL, /* channelRegisterPost, */ + channel_report, + NULL /* channel_close */ +}; + +static void decInitialize(void) +{ + static int firstTime = 1; + + if (!firstTime) return; + firstTime = 0; + + if (!myStructFreeList) + freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64); + + chfPluginRegister("dec", &pif, opts); +} + +epicsExportRegistrar(decInitialize); diff --git a/src/std/filters/filters.dbd.pod b/src/std/filters/filters.dbd.pod index f1a848469..d352d0e5c 100644 --- a/src/std/filters/filters.dbd.pod +++ b/src/std/filters/filters.dbd.pod @@ -14,6 +14,8 @@ The following filters are available in this release: =item * L +=item * L + =back =head2 Using Filters @@ -245,3 +247,41 @@ periods only when "blue" is true by using ... =cut + +registrar(decInitialize) + +=head3 Decimation Filter C<"dec"> + +This filter is used to reduce the number or rate of monitor updates from a +channel by an integer factor C that is provided as a filter argument, +discarding the other updates. A true decimation following the original meaning +of the word would be achieved by giving C as 10, to only allow every tenth +update through. + +=head4 Parameters + +=over + +=item Number C<"n"> + +The decimation factor, a positive integer. Giving n=1 is equivalent to a no-op +that allows all updates to be passed to the client. + +=back + +This filter is intentionally very simplistic. It passes on the first monitor +event that it sees after the channel connects, then discards the next N-1 events +before sending the next event. If several clients connect to a channel using the +same filter settings they may see completely different data streams since each +client gets its own instance of the filter whose event counter starts when that +client connects. + +=head4 Example + +To sample a 60Hz channel at 1Hz, a 10Hz channel every 6 seconds or a 1Hz channel +once every minute: + + Hal$ camonitor 'test:channel' 'test:channel.{"dec":{"n":60}}' + ... + +=cut diff --git a/src/std/filters/test/Makefile b/src/std/filters/test/Makefile index 6e6ad79c6..ad77c5d11 100644 --- a/src/std/filters/test/Makefile +++ b/src/std/filters/test/Makefile @@ -56,6 +56,12 @@ syncTest_SRCS += filterTest_registerRecordDeviceDriver.cpp testHarness_SRCS += syncTest.c TESTS += syncTest +TESTPROD_HOST += decTest +decTest_SRCS += decTest.c +decTest_SRCS += filterTest_registerRecordDeviceDriver.cpp +testHarness_SRCS += decTest.c +TESTS += decTest + # epicsRunFilterTests runs all the test programs in a known working order. testHarness_SRCS += epicsRunFilterTests.c diff --git a/src/std/filters/test/decTest.c b/src/std/filters/test/decTest.c new file mode 100644 index 000000000..cc9317eb4 --- /dev/null +++ b/src/std/filters/test/decTest.c @@ -0,0 +1,273 @@ +/*************************************************************************\ +* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* Copyright (c) 2010 Brookhaven National Laboratory. +* Copyright (c) 2010 Helmholtz-Zentrum Berlin +* fuer Materialien und Energie GmbH. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* + * Authors: Ralph Lange , + * Andrew Johnson + */ + +#include + +#include "dbStaticLib.h" +#include "dbAccessDefs.h" +#include "db_field_log.h" +#include "dbCommon.h" +#include "dbChannel.h" +#include "registry.h" +#include "chfPlugin.h" +#include "errlog.h" +#include "dbmf.h" +#include "epicsUnitTest.h" +#include "dbUnitTest.h" +#include "epicsTime.h" +#include "testMain.h" +#include "osiFileName.h" + +void filterTest_registerRecordDeviceDriver(struct dbBase *); + +static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { + return !(memcmp(pfl1, pfl2, sizeof(db_field_log))); +} + +static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) { + struct dbCommon *prec = dbChannelRecord(chan); + + pfl->ctx = dbfl_context_event; + pfl->type = dbfl_type_val; + pfl->stat = prec->stat; + pfl->sevr = prec->sevr; + pfl->time = prec->time; + pfl->field_type = DBF_LONG; + pfl->no_elements = 1; + /* + * use memcpy to avoid a bus error on + * union copy of char in the db at an odd + * address + */ + memcpy(&pfl->u.v.field, + dbChannelField(chan), + dbChannelFieldSize(chan)); + pfl->u.v.field.dbf_long = val; +} + +static void testHead (char* title) { + testDiag("--------------------------------------------------------"); + testDiag("%s", title); + testDiag("--------------------------------------------------------"); +} + +static void mustDrop(dbChannel *pch, db_field_log *pfl, char* m) { + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + + testOk(NULL == pfl2, "filter drops field_log (%s)", m); +} + +static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + + testOk(pfl == pfl2, "filter passes field_log (%s)", m); +} + +static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) { + ELLNODE *node; + chFilter *filter; + chPostEventFunc *cb_out = NULL; + void *arg_out = NULL; + db_field_log fl, fl1; + + testDiag("Test filter structure and open channel"); + + testOk((ellCount(&pch->filters) == 1), "channel has one plugin"); + + fl_setup(pch, &fl, 1); + fl1 = fl; + node = ellFirst(&pch->filters); + filter = CONTAINER(node, chFilter, list_node); + plug->fif->channel_register_pre(filter, &cb_out, &arg_out, &fl1); + testOk(cb_out && arg_out, + "register_pre registers one filter with argument"); + testOk(fl_equal(&fl1, &fl), + "register_pre does not change field_log data type"); + + testOk(!(dbChannelOpen(pch)), "dbChannel with plugin dec opened"); + node = ellFirst(&pch->pre_chain); + filter = CONTAINER(node, chFilter, pre_node); + testOk((ellCount(&pch->pre_chain) == 1 && filter->pre_arg != NULL), + "dec has one filter with argument in pre chain"); + testOk((ellCount(&pch->post_chain) == 0), + "sync has no filter in post chain"); +} + +MAIN(decTest) +{ + dbChannel *pch; + const chFilterPlugin *plug; + char myname[] = "dec"; + db_field_log *pfl[10]; + int i; + dbEventCtx evtctx; + + testPlan(68); + + testdbPrepare(); + + testdbReadDatabase("filterTest.dbd", NULL, NULL); + + filterTest_registerRecordDeviceDriver(pdbbase); + + testdbReadDatabase("xRecord.db", NULL, NULL); + + eltc(0); + testIocInitOk(); + eltc(1); + + evtctx = db_init_events(); + + testOk(!!(plug = dbFindFilter(myname, strlen(myname))), + "plugin '%s' registered correctly", myname); + + /* N < 1 */ + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":-1}}")), + "dbChannel with dec (n=-1) failed"); + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":0}}")), + "dbChannel with dec (n=0) failed"); + /* Bad parms */ + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{}}")), + "dbChannel with dec (no parm) failed"); + testOk(!(pch = dbChannelCreate("x.VAL{\"dec\":{\"x\":true}}")), + "dbChannel with dec (x=true) failed"); + + /* No Decimation (N=1) */ + + testHead("No Decimation (n=1)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":1}}")), + "dbChannel with plugin dec (n=1) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 5; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 10 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustPass(pch, pfl[1], "i=1"); + mustPass(pch, pfl[2], "i=2"); + mustPass(pch, pfl[3], "i=3"); + mustPass(pch, pfl[4], "i=4"); + + for (i = 0; i < 5; i++) + db_delete_field_log(pfl[i]); + + dbChannelDelete(pch); + + /* Decimation (N=2) */ + + testHead("Decimation (n=2)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":2}}")), + "dbChannel with plugin dec (n=2) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 10; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 20 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustDrop(pch, pfl[1], "i=1"); + mustPass(pch, pfl[2], "i=2"); + mustDrop(pch, pfl[3], "i=3"); + mustPass(pch, pfl[4], "i=4"); + mustDrop(pch, pfl[5], "i=5"); + mustPass(pch, pfl[6], "i=6"); + mustDrop(pch, pfl[7], "i=7"); + mustPass(pch, pfl[8], "i=8"); + mustDrop(pch, pfl[9], "i=9"); + + for (i = 0; i < 10; i++) + db_delete_field_log(pfl[i]); + + dbChannelDelete(pch); + + /* Decimation (N=3) */ + + testHead("Decimation (n=3)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":3}}")), + "dbChannel with plugin dec (n=3) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 10; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 30 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustDrop(pch, pfl[1], "i=1"); + mustDrop(pch, pfl[2], "i=2"); + mustPass(pch, pfl[3], "i=3"); + mustDrop(pch, pfl[4], "i=4"); + mustDrop(pch, pfl[5], "i=5"); + mustPass(pch, pfl[6], "i=6"); + mustDrop(pch, pfl[7], "i=7"); + mustDrop(pch, pfl[8], "i=8"); + mustPass(pch, pfl[9], "i=9"); + + for (i = 0; i < 10; i++) + db_delete_field_log(pfl[i]); + + dbChannelDelete(pch); + + /* Decimation (N=4) */ + + testHead("Decimation (n=4)"); + testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":4}}")), + "dbChannel with plugin dec (n=4) created"); + + checkAndOpenChannel(pch, plug); + + for (i = 0; i < 10; i++) { + pfl[i] = db_create_read_log(pch); + fl_setup(pch, pfl[i], 40 + i); + } + + testDiag("Test event stream"); + + mustPass(pch, pfl[0], "i=0"); + mustDrop(pch, pfl[1], "i=1"); + mustDrop(pch, pfl[2], "i=2"); + mustDrop(pch, pfl[3], "i=3"); + mustPass(pch, pfl[4], "i=4"); + mustDrop(pch, pfl[5], "i=5"); + mustDrop(pch, pfl[6], "i=6"); + mustDrop(pch, pfl[7], "i=7"); + mustPass(pch, pfl[8], "i=8"); + mustDrop(pch, pfl[9], "i=9"); + + for (i = 0; i < 10; i++) + db_delete_field_log(pfl[i]); + + dbChannelDelete(pch); + + db_close_events(evtctx); + + testIocShutdownOk(); + + testdbCleanup(); + + return testDone(); +} diff --git a/src/std/filters/test/epicsRunFilterTests.c b/src/std/filters/test/epicsRunFilterTests.c index 236364391..5737d77dc 100644 --- a/src/std/filters/test/epicsRunFilterTests.c +++ b/src/std/filters/test/epicsRunFilterTests.c @@ -17,6 +17,7 @@ int tsTest(void); int dbndTest(void); int syncTest(void); int arrTest(void); +int decTest(void); void epicsRunFilterTests(void) { @@ -26,6 +27,7 @@ void epicsRunFilterTests(void) runTest(dbndTest); runTest(syncTest); runTest(arrTest); + runTest(decTest); dbmfFreeChunks(); From 048975ccc708987afdda43712485ff9dc24b0b29 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 5 Jun 2019 11:40:50 +0200 Subject: [PATCH 037/281] asLib more string size... --- modules/libcom/src/as/asLib.h | 4 ++-- modules/libcom/src/as/asLibRoutines.c | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/libcom/src/as/asLib.h b/modules/libcom/src/as/asLib.h index a29cf3b65..528ce6ed9 100644 --- a/modules/libcom/src/as/asLib.h +++ b/modules/libcom/src/as/asLib.h @@ -170,8 +170,8 @@ typedef struct uag{ } UAG; /*Defs for Host Access Groups*/ typedef struct{ - ELLNODE node; - char *host; + ELLNODE node; + char host[1]; } HAGNAME; typedef struct hag{ ELLNODE node; diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index 4ca1916bd..ab0bf5071 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -1211,8 +1211,7 @@ static long asHagAddHost(HAG *phag,const char *host) if (!phag) return 0; if(!asCheckClientIP) { size_t i, len = strlen(host); - phagname = asCalloc(1, sizeof(HAGNAME) + len + 1); - phagname->host = (char *)(phagname + 1); + phagname = asCalloc(1, sizeof(HAGNAME) + len); for (i = 0; i < len; i++) { phagname->host[i] = (char)tolower((int)host[i]); } @@ -1226,14 +1225,13 @@ static long asHagAddHost(HAG *phag,const char *host) errlogPrintf("ACF: Unable to resolve host '%s'\n", host); - phagname = asCalloc(1, sizeof(HAGNAME) + sizeof(unresolved)+strlen(host)); + phagname = asCalloc(1, sizeof(HAGNAME) + sizeof(unresolved)-1+strlen(host)); strcpy(phagname->host, unresolved); strcat(phagname->host, host); } else { ip = ntohl(addr.sin_addr.s_addr); phagname = asCalloc(1, sizeof(HAGNAME) + 24); - phagname->host = (char *)(phagname + 1); epicsSnprintf(phagname->host, 24, "%u.%u.%u.%u", (ip>>24)&0xff, From 5cfff383b265ab99448ce44d39b0e865bf9bdd4d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 Jun 2019 13:16:42 -0500 Subject: [PATCH 038/281] Synchronization hook support for osiClockTime --- src/libCom/osi/osiClockTime.c | 7 +++++++ src/libCom/osi/osiClockTime.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/src/libCom/osi/osiClockTime.c b/src/libCom/osi/osiClockTime.c index fb9d1532f..8ae43aed8 100644 --- a/src/libCom/osi/osiClockTime.c +++ b/src/libCom/osi/osiClockTime.c @@ -148,6 +148,8 @@ void ClockTime_GetProgramStart(epicsTimeStamp *pDest) /* Synchronization thread */ #if defined(vxWorks) || defined(__rtems__) +CLOCKTIME_SYNCHOOK ClockTime_syncHook = NULL; + static void ClockTimeSync(void *dummy) { taskwdInsert(0, NULL, NULL); @@ -179,11 +181,16 @@ static void ClockTimeSync(void *dummy) ClockTimePvt.syncTime = timeNow; epicsMutexUnlock(ClockTimePvt.lock); + if (ClockTime_syncHook) + ClockTime_syncHook(1); + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_value; } } ClockTimePvt.synchronized = 0; + if (ClockTime_syncHook) + ClockTime_syncHook(0); taskwdRemove(0); } #endif diff --git a/src/libCom/osi/osiClockTime.h b/src/libCom/osi/osiClockTime.h index 17eacab3e..23598886d 100644 --- a/src/libCom/osi/osiClockTime.h +++ b/src/libCom/osi/osiClockTime.h @@ -19,6 +19,12 @@ void ClockTime_Init(int synchronize); void ClockTime_Shutdown(void *dummy); int ClockTime_Report(int level); +#if defined(vxWorks) || defined(__rtems__) +typedef void (* CLOCKTIME_SYNCHOOK)(int synchronized); + +extern CLOCKTIME_SYNCHOOK ClockTime_syncHook; +#endif + #ifdef __cplusplus } #endif From 30812c23f017cc20daf15ed72364648af04c2ce9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 Jun 2019 13:17:35 -0500 Subject: [PATCH 039/281] Internal cleanup in osiClockTime.c --- src/libCom/osi/osiClockTime.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libCom/osi/osiClockTime.c b/src/libCom/osi/osiClockTime.c index 8ae43aed8..01958b20e 100644 --- a/src/libCom/osi/osiClockTime.c +++ b/src/libCom/osi/osiClockTime.c @@ -23,7 +23,8 @@ #include "taskwd.h" #define NSEC_PER_SEC 1000000000 -#define ClockTimeSyncInterval_value 60.0 +#define ClockTimeSyncInterval_initial 1.0 +#define ClockTimeSyncInterval_normal 60.0 static struct { @@ -79,7 +80,7 @@ static void ClockTime_InitOnce(void *pfirst) ClockTimePvt.loopEvent = epicsEventMustCreate(epicsEventEmpty); ClockTimePvt.lock = epicsMutexCreate(); - ClockTimePvt.ClockTimeSyncInterval = 1.0; /* First sync */ + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_initial; epicsAtExit(ClockTime_Shutdown, NULL); @@ -184,7 +185,7 @@ static void ClockTimeSync(void *dummy) if (ClockTime_syncHook) ClockTime_syncHook(1); - ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_value; + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_normal; } } From b0db6568ea26ab41c4610d21b9bf1a901707f834 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 Jun 2019 13:24:39 -0500 Subject: [PATCH 040/281] Replace EPICS_TIMEZONE envParam with EPICS_TZ Adjust rtems_init() to use it. --- configure/CONFIG_SITE_ENV | 69 ++++++++++++++++++----------------- src/libCom/RTEMS/rtems_init.c | 24 +++--------- src/libCom/env/envDefs.h | 2 +- 3 files changed, 41 insertions(+), 54 deletions(-) diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV index 49331f9a4..008467933 100644 --- a/configure/CONFIG_SITE_ENV +++ b/configure/CONFIG_SITE_ENV @@ -24,40 +24,41 @@ # Site-specific environment settings -# Time service: -# EPICS_TIMEZONE -# Local timezone info for vxWorks and RTEMS. The format is -# :::: -# where is only used by strftime() for %Z conversions, -# and and are mmddhh - that is month,day,hour -# e.g. for ANL in 2018: EPICS_TIMEZONE=CUS::360:031102:110402 -# The future dates below assume the rules don't get changed; -# see http://www.timeanddate.com/time/dst/2018.html to check. -# -# DST for 2018 US: Mar 11 - Nov 04 -# EU: Mar 25 - Oct 28 -EPICS_TIMEZONE = CUS::360:031102:110402 -#EPICS_TIMEZONE = MET::-60:032502:102803 -# -# DST for 2019 US: Mar 10 - Nov 03 -# EU: Mar 31 - Oct 27 -#EPICS_TIMEZONE = CUS::360:031002:110302 -#EPICS_TIMEZONE = MET::-60:033102:102703 -# -# DST for 2020 US: Mar 08 - Nov 01 -# EU: Mar 29 - Oct 25 -#EPICS_TIMEZONE = CUS::360:030802:110102 -#EPICS_TIMEZONE = MET::-60:032902:102503 -# -# DST for 2021 US: Mar 14 - Nov 07 -# EU: Mar 28 - Oct 31 -#EPICS_TIMEZONE = CUS::360:031402:110702 -#EPICS_TIMEZONE = MET::-60:032802:103103 -# -# DST for 2022 US: Mar 13 - Nov 06 -# EU: Mar 27 - Oct 30 -#EPICS_TIMEZONE = CUS::360:031302:110602 -#EPICS_TIMEZONE = MET::-60:032702:103003 +## Time service: +# EPICS_TZ +# Local timezone rules for vxWorks and RTEMS. The value follows the Posix +# TZ environment variable's Mm.n.d/h format (see the IBM link below for +# details). If TZ hasn't already been set when the osdTime timeRegister() +# C++ static constructor runs, this parameter will be copied into the TZ +# environment variable. Once the OS clock has been synchronized to NTP the +# routine tz2timezone() will be run to convert TZ into the TIMEZONE +# variable format that VxWorks needs. +# https://developer.ibm.com/articles/au-aix-posix/ + +# Japan Standard Time, no DST: +#EPICS_TZ = "JST-9" + +# Central European (Summer) Time: +#EPICS_TZ = "CET-1CEST,M3.5.0/2,M10.5.0/3" + +# Greenwich Mean/British Summer Time: +#EPICS_TZ = "GMT0BST,M3.5.0/1,M10.5.0/2" + +# US Eastern Standard/Daylight Time: +#EPICS_TZ = "EST5EDT,M3.2.0/2,M11.1.0/2" + +# US Central Standard/Daylight Time: +EPICS_TZ = "CST6CDT,M3.2.0/2,M11.1.0/2" + +# US Mountain Standard/Daylight Time: +#EPICS_TZ = "MST7MDT,M3.2.0/2,M11.1.0/2" + +# US Pacific Standard/Daylight Time: +#EPICS_TZ = "PST8PDT,M3.2.0/2,M11.1.0/2" + +# US Hawaiian Standard Time, no DST: +#EPICS_TZ = "HST10" + # EPICS_TS_NTP_INET # NTP time server ip address for VxWorks and RTEMS. diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c index 2b909ab3b..dcb6daaf7 100644 --- a/src/libCom/RTEMS/rtems_init.c +++ b/src/libCom/RTEMS/rtems_init.c @@ -581,25 +581,11 @@ Init (rtems_task_argument ignored) printf ("***** Can't set time: %s\n", rtems_status_text (sc)); } if (getenv("TZ") == NULL) { - const char *tzp = envGetConfigParamPtr(&EPICS_TIMEZONE); - if (tzp == NULL) { - printf("Warning -- no timezone information available -- times will be displayed as GMT.\n"); - } - else { - char tz[10]; - int minWest, toDst = 0, fromDst = 0; - if(sscanf(tzp, "%9[^:]::%d:%d:%d", tz, &minWest, &toDst, &fromDst) < 2) { - printf("Warning: EPICS_TIMEZONE (%s) unrecognizable -- times will be displayed as GMT.\n", tzp); - } - else { - char posixTzBuf[40]; - char *p = posixTzBuf; - p += sprintf(p, "%cST%d:%.2d", tz[0], minWest/60, minWest%60); - if (toDst != fromDst) - p += sprintf(p, "%cDT", tz[0]); - epicsEnvSet("TZ", posixTzBuf); - } - } + const char *tzp = envGetConfigParamPtr(&EPICS_TZ); + if (!tzp || *tzp) + printf("Warning: No timezone information, times will be displayed in UTC.\n"); + else + epicsEnvSet("TZ", tzp); } tzset(); osdTimeRegister(); diff --git a/src/libCom/env/envDefs.h b/src/libCom/env/envDefs.h index 20f0eb2ad..588cecdad 100644 --- a/src/libCom/env/envDefs.h +++ b/src/libCom/env/envDefs.h @@ -61,7 +61,7 @@ epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PORT; epicsShareExtern const ENV_PARAM EPICS_BUILD_COMPILER_CLASS; epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS; epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH; -epicsShareExtern const ENV_PARAM EPICS_TIMEZONE; +epicsShareExtern const ENV_PARAM EPICS_TZ; epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_INET; From b57f02ece202c71c03d94c9b53990c29ab1a416c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 Jun 2019 13:26:24 -0500 Subject: [PATCH 041/281] epicsTimeTo[GM]TM(): Allow pNSecDest==NULL --- src/libCom/osi/epicsTime.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp index af4fae25d..9f544274f 100644 --- a/src/libCom/osi/epicsTime.cpp +++ b/src/libCom/osi/epicsTime.cpp @@ -955,7 +955,8 @@ extern "C" { try { local_tm_nano_sec tmns = epicsTime (*pSrc); *pDest = tmns.ansi_tm; - *pNSecDest = tmns.nSec; + if (pNSecDest) + *pNSecDest = tmns.nSec; } catch (...) { return epicsTimeERROR; @@ -967,7 +968,8 @@ extern "C" { try { gm_tm_nano_sec gmtmns = epicsTime (*pSrc); *pDest = gmtmns.ansi_tm; - *pNSecDest = gmtmns.nSec; + if (pNSecDest) + *pNSecDest = gmtmns.nSec; } catch (...) { return epicsTimeERROR; From 96998f55e01f6472fa41f9db448db768628002bb Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 Jun 2019 14:55:26 -0500 Subject: [PATCH 042/281] Have VxWorks call tz2timezone() once clock is sync'd --- src/libCom/osi/Makefile | 2 +- src/libCom/osi/os/vxWorks/osdTime.cpp | 32 ++- src/libCom/osi/os/vxWorks/tz2timezone.c | 278 ++++++++++++++++++++++++ 3 files changed, 303 insertions(+), 9 deletions(-) create mode 100644 src/libCom/osi/os/vxWorks/tz2timezone.c diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile index c06a862ed..e05aec37d 100644 --- a/src/libCom/osi/Makefile +++ b/src/libCom/osi/Makefile @@ -77,7 +77,7 @@ Com_SRCS += epicsGeneralTime.c # Time providers Com_SRCS += osiClockTime.c -Com_SRCS_vxWorks += osiNTPTime.c +Com_SRCS_vxWorks += osiNTPTime.c tz2timezone.c Com_SRCS_RTEMS += osiNTPTime.c ifeq ($(OS_CLASS),vxWorks) diff --git a/src/libCom/osi/os/vxWorks/osdTime.cpp b/src/libCom/osi/os/vxWorks/osdTime.cpp index 4db375fbb..eb144c1b6 100644 --- a/src/libCom/osi/os/vxWorks/osdTime.cpp +++ b/src/libCom/osi/os/vxWorks/osdTime.cpp @@ -24,22 +24,38 @@ #define NTP_REQUEST_TIMEOUT 4 /* seconds */ +extern "C" { + int tz2timezone(void); +} + static char sntp_sync_task[] = "ipsntps"; static char ntp_daemon[] = "ipntpd"; static const char *pserverAddr = NULL; +static CLOCKTIME_SYNCHOOK prevHook; + extern char* sysBootLine; +static void timeSync(int synchronized) { + if (!tz2timezone()) + ClockTime_syncHook = prevHook; /* Don't call me again */ +} + static int timeRegister(void) { - /* If TIMEZONE not defined, set it from EPICS_TIMEZONE */ - if (getenv("TIMEZONE") == NULL) { - const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE); - if (timezone == NULL) { - printf("timeRegister: No Time Zone Information\n"); - } else { - epicsEnvSet("TIMEZONE", timezone); + /* If TZ not defined, set it from EPICS_TZ */ + if (getenv("TZ") == NULL) { + const char *tz = envGetConfigParamPtr(&EPICS_TZ); + + if (tz && *tz) { + epicsEnvSet("TZ", tz); + + /* Call tz2timezone() once we know what year it is */ + prevHook = ClockTime_syncHook; + ClockTime_syncHook = timeSync; } + else if (getenv("TIMEZONE") == NULL) + printf("timeRegister: No Time Zone Information available\n"); } // Define EPICS_TS_FORCE_NTPTIME to force use of NTPTime provider @@ -57,7 +73,7 @@ static int timeRegister(void) } if (useNTP) { - // Start NTP first so it can be used to sync SysTime + // Start NTP first so it can be used to sync ClockTime NTPTime_Init(100); ClockTime_Init(CLOCKTIME_SYNC); } else { diff --git a/src/libCom/osi/os/vxWorks/tz2timezone.c b/src/libCom/osi/os/vxWorks/tz2timezone.c new file mode 100644 index 000000000..df8db8514 --- /dev/null +++ b/src/libCom/osi/os/vxWorks/tz2timezone.c @@ -0,0 +1,278 @@ +/*************************************************************************\ +* Copyright (c) 2009 Brookhaven Science Associates, as Operator of +* Brookhaven National Laboratory. +* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne +* National Laboratory. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* + * Authors: Larry Hoff, Andrew Johnson + */ + +/* + * This file exports a single function "int tz2timezone(void)" which reads + * the TZ environment variable (defined by POSIX) and converts it to the + * TIMEZONE environment variable defined by ANSI. The latter is used by + * VxWorks "time" functions, is largely deprecated in other computing + * environments, has limitations, and is difficult to maintain. This holds + * out the possibility of "pretending" that VxWorks supports "TZ" - until + * such time as it actually does. + * + * For simplicity, only the "POSIX standard form" of TZ will be supported. + * Even that is complicated enough (see following spec). Furthermore, + * only the "M" form of DST start and stop dates are supported. + * + * TZ = zone[-]offset[dst[offset],start[/time],end[/time]] + * + * zone + * A three or more letter name for the timezone in normal (winter) time. + * + * [-]offset + * A signed time giving the offset of the time zone westwards from + * Greenwich. The time has the form hh[:mm[:ss]] with a one of two + * digit hour, and optional two digit minutes and seconds. + * + * dst + * The name of the time zone when daylight saving is in effect. It may + * be followed by an offset giving how big the adjustment is, required + * if different than the default of 1 hour. + * + * start/time,end/time + * Specify the start and end of the daylight saving period. The start + * and end fields indicate on what day the changeover occurs, and must + * be in this format: + * + * Mm.n.d + * This indicates month m, the n-th occurrence of day d, where + * 1 <= m <= 12, 1 <= n <= 5, 0 <= d <= 6, 0=Sunday + * The 5th occurrence means the last occurrence of that day in a + * month. So M4.1.0 is the first Sunday in April, M9.5.0 is the + * last Sunday in September. + * + * The time field indicates what hour the changeover occurs on the given + * day (TIMEZONE only supports switching on the hour). + * + */ + +#include +#include /* getenv() */ +#include /* printf() */ +#include /* strchr() */ +#include /* isalpha() */ + +#include + +/* for reference: TZ syntax, example, and TIMEZONE example + * std offset dst [offset],start[/time],end[/time] + * CST6CDT5,M3.2.0,M11.1.0 + * EST+5EDT,M4.1.0/2,M10.5.0/2 + * + * std offset start stop + * TIMEZONE=EST::300:030802:110102 + */ + +static int extractDate(const char *tz, struct tm *current, char *s) +{ + static const int startdays[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 + }; + static const int molengths[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + }; + + int month, week, weekday, hour=2; /* default=2AM */ + int jan1wday, wday, mday; + + /* Require 'M' format */ + if (*++tz != 'M') { + printf("tz2timezone: Unsupported date type, need 'M' format\n"); + return ERROR; + } + tz++; + + if (sscanf(tz, "%d.%d.%d/%d", &month, &week, &weekday, &hour) < 3) + return ERROR; /* something important missing */ + + if (month == 0 || month>12 || + week < 1 || week > 5 || + weekday < 0 || weekday > 6 || + hour < 0 || hour > 23) + return ERROR; + + /* Now for some brute-force calendar calculations... */ + /* start month is in "month", and the day is "weekday", but + we need to know when that weekday first occurs in that month */ + /* Let's start with weekday on Jan. 1 */ + jan1wday = (7 + current->tm_wday - (current->tm_yday % 7)) % 7; + + /* We need to know if it is a leap year (and if it matters) */ + /* Let's assume that we're working with a date between 1901 and 2099, + that way we don't have to think about the "century exception". + If this code is still running (unchanged) in 2100, I'll be stunned + (and 139 years old) */ + wday = (jan1wday + startdays[month-1] + + ((month > 2 && (current->tm_year % 4 == 0)) ? 1 : 0)) % 7; + + /* Let's see on what day-of-the-month the first target weekday occurs + (counting from 1). The result is a number between 1 and 7, inclusive. */ + mday = 1 + ((7 + weekday - wday) % 7); + + /* Next, we add the week offset. If we overflow the month, we subtract + one week */ + mday += 7 * (week - 1); + if (mday > molengths[month-1]) + mday -= 7; + + /* Should I handle Feb 29? I'm willing to gamble that no one in their right + mind would schedule a time change to occur on Feb. 29. If so, we'll be a + week early */ + sprintf(s, "%02d%02d%02d", month, mday, hour); + + return OK; +} + + +static const char *getTime(const char *s, int *time) +{ + /* Time format is [+/-]hh[:mm][:ss] followed by the next zone name */ + + *time = 0; + + if (!isdigit((int) s[0])) + return s; /* no number here... */ + + if (!isdigit((int) s[1])) { /* single digit form */ + *time = s[0] - '0'; + return s + 1; + } + + if (isdigit((int) s[1])) { /* two digit form */ + *time = 10 * (s[0] - '0') + (s[1] - '0'); + return s + 2; + } + + return s; /* does not follow supported form */ +} + +int tz2timezone(void) +{ + const char *tz = getenv("TZ"); + /* Spec. says that zone names must be at least 3 chars. + * I've never seen a longer zone name, but I'll allocate + * 40 chars. If you live in a zone with a longer name, + * you may want to think about the benefits of relocation. + */ + char zone[40]; + char start[10], stop[10]; /* only really need 7 bytes now */ + int hours = 0, minutes = 0, sign = 1; + /* This is more than enough, even with a 40-char zone + * name, and 4-char offset. + */ + char timezone[100]; + int i = 0; /* You *always need an "i" :-) */ + epicsTimeStamp now; + struct tm current; + + /* First let's get the current time. We need the year to + * compute the start/stop dates for DST. + */ + if (epicsTimeGetCurrent(&now) || + epicsTimeToTM(¤t, NULL, &now)) + return ERROR; + + /* Make sure TZ exists. + * Spec. says that ZONE must be at least 3 chars. + */ + if ((!tz) || (strlen(tz) < 3)) + return ERROR; + + /* OK, now a bunch of brute-force parsing. My brain hurts if + * I try to think of an elegant regular expression for the + * string. + */ + + /* Start extracting zone name, must be alpha */ + while ((i < sizeof(zone) - 1) && isalpha((int) *tz)) { + zone[i++] = *tz++; + } + if (i < 3) + return ERROR; /* Too short, not a real zone name? */ + + zone[i] = 0; /* Nil-terminate (for now) */ + + /* Now extract offset time. The format is [+/-]hh[:mm[:ss]] + * Recall that TIMEZONE doesn't support seconds.... + */ + if (*tz == '-') { + sign = -1; + tz++; + } + else if (*tz == '+') { + tz++; + } + + /* Need a digit now */ + if (!isdigit((int) *tz)) + return ERROR; + + /* First get the hours */ + tz = getTime(tz, &hours); + if (hours > 24) + return ERROR; + + if (*tz == ':') { /* There is a minutes part */ + /* Need another digit now */ + if (!isdigit((int) *++tz)) + return ERROR; + + /* Extract the minutes */ + tz = getTime(tz, &minutes); + if (minutes > 60) + return ERROR; + + /* Skip any seconds part */ + if (*tz == ':') { + int seconds; + tz = getTime(tz + 1, &seconds); + } + } + + /* Extract any DST zone name, must be alpha */ + if (isalpha((int) *tz)) { + zone[i++] = '/'; /* Separate the names */ + + while ((i < sizeof(zone) - 1) && isalpha((int) *tz)) { + zone[i++] = *tz++; + } + zone[i] = 0; /* Nil-terminate */ + } + + minutes += hours * 60; + minutes *= sign; + + /* Look for start/stop dates - require neither or both */ + tz = strchr(tz, ','); + if (!tz) { /* No daylight savings time here */ + /* Format the env. variable */ + sprintf(timezone, "TIMEZONE=%s::%d", zone, minutes); + } + else { + if (extractDate(tz, ¤t, start) != OK) + return ERROR; + + tz = strchr(tz + 1, ','); + if (!tz) + return ERROR; + if (extractDate(tz, ¤t, stop) != OK) + return ERROR; + + /* Format the env. variable */ + sprintf(timezone, "TIMEZONE=%s::%d:%s:%s", zone, minutes, start, stop); + } + + /* Make it live! */ + putenv(timezone); + + return OK; +} From d3a8a49552ca7930aa9a5ab34ceb1de9cd25ccf4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 7 Jun 2019 15:37:46 -0500 Subject: [PATCH 043/281] Release Notes --- documentation/RELEASE_NOTES.html | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 8ed4e04bf..f6daa49d4 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -16,6 +16,38 @@ +

Replace EPICS_TIMEZONE with EPICS_TZ

+ +

The EPICS_TIMEZONE environment parameter provided time-zone +information for the IOC's locale in the old ANSI format expected by VxWorks for +its TIMEZONE environment variable, and can also used by RTEMS to set +its TZ environment variable. However the TIMEZONE value has to +be updated every year since it contains the exact dates of the daylight-savings +time changes. The Posix TZ format that RTEMS uses contains rules that for +calculating those dates, thus its value would only need updating if the rules +(or the locale) are changed.

+ +

This release contains changes that replace the EPICS_TIMEZONE +environment parameter with one called EPICS_TZ and a routine for +VxWorks that calculates the TIMEZONE environment variable from the +current TZ value. This routine will be run once at start-up, when the +EPICS clock has synchronized to its NTP server. The calculations it contains +were worked out and donated to EPICS by Larry Hoff in 2009; it is unforunate +that it has taken 10 years for them to be integrated into Base.

+ +

The default value for the EPICS_TZ environment parameter is set in +the Base configure/CONFIG_SITE_ENV file, which contains example settings for +most EPICS sites that use VxWorks, and a link to a page describing the Posix TZ +format for any locations that I missed.

+ +

If a VxWorks IOC runs continuously without being rebooted from December 31st +to the start of daylight savings time the following year, its TIMEZONE +value will be wrong as it was calculated for the previous year. This only +affects times that are converted to a string on the IOC however and is easily +fixed; just run the command tz2timezone() on the VxWorks shell and the +calculation will be redone for the current year. IOCs that get rebooted at least +once before the start of summer time will not need this to be done.

+

Cleaning up with Multiple CA contexts in a Process

Bruno Martins reported a problem with the CA client library at shutdown in a From e8db975e7f764c9d6e446de01e307ed27d9313aa Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 17 Jun 2019 14:33:28 -0500 Subject: [PATCH 044/281] Initial implementation for VxWorks 6.9 and later This almost seems too simple... --- modules/libcom/src/osi/os/vxWorks/osdThread.c | 9 ++++++++- modules/libcom/src/osi/os/vxWorks/osdThread.h | 10 ++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 7a0fe7b9f..8a24add1c 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -223,7 +223,14 @@ epicsThreadCreateOpt ( return((epicsThreadId)tid); } -void epicsThreadJoin(epicsThreadId id) {} +void epicsThreadJoin(epicsThreadId id) { +#if EPICS_THREAD_CAN_JOIN + int tid = (int)id; + + if (tid) + taskWait(tid, WAIT_FOREVER); +#endif +} void epicsThreadSuspendSelf() { diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.h b/modules/libcom/src/osi/os/vxWorks/osdThread.h index 09704b667..8fa454ce3 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.h +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.h @@ -10,7 +10,13 @@ #ifndef osdThreadh #define osdThreadh -/* This target does not support joining threads */ -#define EPICS_THREAD_CAN_JOIN (0) +/* VxWorks 6.9 and later can support joining threads */ + +#if (_WRS_VXWORKS_MAJOR > 6) || \ + (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 9) +# define EPICS_THREAD_CAN_JOIN (1) +#else +# define EPICS_THREAD_CAN_JOIN (0) +#endif #endif /* osdThreadh */ From 5efce9ecc056e5de24c7c8a8cbc2fba7d7f4ef67 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 07:30:48 -0700 Subject: [PATCH 045/281] epicsThreadJoin() -> epicsThreadMustJoin() --- modules/libcom/src/osi/epicsThread.cpp | 4 ++-- modules/libcom/src/osi/epicsThread.h | 2 +- modules/libcom/src/osi/os/RTEMS/osdThread.c | 4 ++-- modules/libcom/src/osi/os/WIN32/osdThread.c | 2 +- modules/libcom/src/osi/os/posix/osdThread.c | 4 ++-- modules/libcom/src/osi/os/vxWorks/osdThread.c | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 7092900b1..9a049133f 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -158,7 +158,7 @@ bool epicsThread::exitWait ( const double delay ) throw () epicsGuard < epicsMutex > guard ( this->mutex ); joined = true; } - epicsThreadJoin(this->id); + epicsThreadMustJoin(this->id); } return true; } @@ -177,7 +177,7 @@ bool epicsThread::exitWait ( const double delay ) throw () joined = true; epicsGuardRelease < epicsMutex > unguard ( guard ); - epicsThreadJoin(this->id); + epicsThreadMustJoin(this->id); } } catch ( std :: exception & except ) { diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index c43d7fb01..61ab323b1 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -89,7 +89,7 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ); -epicsShareFunc void epicsThreadJoin(epicsThreadId id); +epicsShareFunc void epicsThreadMustJoin(epicsThreadId id); epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void); epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id); epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority( diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index a22e2f87f..cae1b0449 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -363,7 +363,7 @@ threadMustCreate (const char *name, return tid; } -void epicsThreadJoin(epicsThreadId id) +void epicsThreadMustJoin(epicsThreadId id) { rtems_id target_tid = (rtems_id)id, self_tid; struct taskVar *v; @@ -389,7 +389,7 @@ void epicsThreadJoin(epicsThreadId id) cantProceed("oopsj %s\n", rtems_status_text(sc)); if(sc != RTEMS_SUCCESSFUL) { - errlogPrintf("epicsThreadJoin('%s') -> %s\n", v->name, rtems_status_text(sc)); + errlogPrintf("epicsThreadMustJoin('%s') -> %s\n", v->name, rtems_status_text(sc)); } } diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index eba41645f..bc41037cf 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -662,7 +662,7 @@ epicsThreadId epicsThreadCreateOpt ( return ( epicsThreadId ) pParmWIN32; } -void epicsThreadJoin(epicsThreadId id) +void epicsThreadMustJoin(epicsThreadId id) { win32ThreadParam * pParmWIN32 = id; diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index d34edf694..e2f5f556b 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -557,7 +557,7 @@ epicsThreadCreateOpt ( status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL); checkStatusOnce(status,"pthread_sigmask"); if(pthreadInfo->joinable) { - /* extra ref for epicsThreadJoin() */ + /* extra ref for epicsThreadMustJoin() */ epicsAtomicIncrIntT(&pthreadInfo->refcnt); } return(pthreadInfo); @@ -600,7 +600,7 @@ static epicsThreadOSD *createImplicit(void) return pthreadInfo; } -void epicsThreadJoin(epicsThreadId id) +void epicsThreadMustJoin(epicsThreadId id) { void *ret = NULL; int status; diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 8a24add1c..6847e9769 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -223,7 +223,7 @@ epicsThreadCreateOpt ( return((epicsThreadId)tid); } -void epicsThreadJoin(epicsThreadId id) { +void epicsThreadMustJoin(epicsThreadId id) { #if EPICS_THREAD_CAN_JOIN int tid = (int)id; From 9e5c63fb9158f0262abfc9e6be282dcb542a914c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 07:53:23 -0700 Subject: [PATCH 046/281] epicsThreadMustJoin() clear joinable flag Clear so that repeated calls will error correctly. Only well defined for self join. --- modules/libcom/src/osi/os/RTEMS/osdThread.c | 4 +++- modules/libcom/src/osi/os/WIN32/osdThread.c | 5 ++++- modules/libcom/src/osi/os/posix/osdThread.c | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index cae1b0449..b30cb4156 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -380,7 +380,8 @@ void epicsThreadMustJoin(epicsThreadId id) /* try to error nicely, however in all likelyhood rtems_task_get_note failed, * or gave us the wrong thread as we are racing thread exit. */ - cantProceed("%s join not enabled for thread.\n", v->name); + cantProceed("%s thread not joinable.\n", v->name); + return; } else if(target_tid!=self_tid) { /* wait for target to complete */ @@ -393,6 +394,7 @@ void epicsThreadMustJoin(epicsThreadId id) } } + v->joinable = 0; taskUnref(v); /* target task may be deleted. * self task is not deleted, even for self join. diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index bc41037cf..8c3973703 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -673,7 +673,8 @@ void epicsThreadMustJoin(epicsThreadId id) * 'pParmWIN32' has already crashed us as we are racing thread exit, * which free's 'pParmWIN32'. */ - cantProceed("%s join not enabled for thread.\n", pParmWIN32->pName); + cantProceed("%s thread not joinable.\n", pParmWIN32->pName); + return; } else if(epicsThreadGetIdSelf() != id) { DWORD status = WaitForSingleObject(pParmWIN32->handle, INFINITE); @@ -681,9 +682,11 @@ void epicsThreadMustJoin(epicsThreadId id) /* TODO: signal error? */ } + pParmWIN32->joinable = 0; epicsParmCleanupWIN32(pParmWIN32); } else { /* join self silently does nothing */ + pParmWIN32->joinable = 0; epicsParmCleanupWIN32(pParmWIN32); } } diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index e2f5f556b..ed3785205 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -612,7 +612,8 @@ void epicsThreadMustJoin(epicsThreadId id) * 'id' has already caused SIGSEGV as we are racing thread exit, * which free's 'id'. */ - cantProceed("%s join not enabled for thread.\n", id->name); + cantProceed("%s thread not joinable.\n", id->name); + return; } status = pthread_join(id->tid, &ret); @@ -623,6 +624,7 @@ void epicsThreadMustJoin(epicsThreadId id) status = pthread_detach(id->tid); checkStatusOnce(status, "pthread_detach"); } else checkStatusOnce(status, "pthread_join"); + id->joinable = 0; free_threadInfo(id); } From 86a942872aea66e06cc8aa5478da74f8f5d3fb77 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 08:01:59 -0700 Subject: [PATCH 047/281] epicsThreadTest check explicit join Also remove all the sleeps to improve chances of catching some kind of race. --- modules/libcom/test/epicsThreadTest.cpp | 29 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index eb26cc8bf..c50d8c5bd 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -52,7 +52,7 @@ void myThread::run() startEvt.signal(); int *pset = argvalue; privateKey.set(argvalue); - epicsThreadSleep(2.0); + int *pget = privateKey.get(); testOk1(pget == pset); @@ -63,6 +63,7 @@ void myThread::run() typedef struct info { int isOkToBlock; + int didSomething; } info; extern "C" { @@ -71,19 +72,19 @@ static void thread(void *arg) info *pinfo = (info *)arg; epicsThreadSetOkToBlock(pinfo->isOkToBlock); - epicsThreadSleep(1.0); testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock, "%s epicsThreadIsOkToBlock() = %d", epicsThreadGetNameSelf(), pinfo->isOkToBlock); - epicsThreadSleep(0.1); + + pinfo->didSomething = 1; } } MAIN(epicsThreadTest) { - testPlan(9); + testPlan(11); unsigned int ncpus = epicsThreadGetCPUs(); testDiag("System has %u CPUs", ncpus); @@ -108,15 +109,23 @@ MAIN(epicsThreadTest) delete myThreads[i]; } - unsigned int stackSize = epicsThreadGetStackSize(epicsThreadStackSmall); + epicsThreadOpts opts; + epicsThreadOptsDefaults(&opts); + opts.priority = 50; + opts.joinable = 1; - info infoA = {0}; - epicsThreadCreate("threadA", 50, stackSize, thread, &infoA); + info infoA = {0, 0}; + epicsThreadId threadA = epicsThreadCreateOpt("threadA", thread, &infoA, &opts); - info infoB = {1}; - epicsThreadCreate("threadB", 50, stackSize, thread, &infoB); + info infoB = {1, 0}; + epicsThreadId threadB = epicsThreadCreateOpt("threadB", thread, &infoB, &opts); - epicsThreadSleep(2.0); + // join B first to better our chance of detecting if it never runs. + epicsThreadMustJoin(threadB); + testOk1(infoB.didSomething); + + epicsThreadMustJoin(threadA); + testOk1(infoA.didSomething); return testDone(); } From 4dcd6f37c697b1517b5e36ae1b9d130abfcd7699 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 16:18:43 -0700 Subject: [PATCH 048/281] update release notes --- documentation/RELEASE_NOTES.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 376279fc9..1d93d2b3b 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -38,7 +38,7 @@ host, and the IOC would believe them.

look up the IP address of any hostnames listed in its ACF (which will normally be done using the DNS or the /etc/hosts file). The IOC will then compare the resulting IP address against the client's actual IP address when -checking access permissions at connection time. This name resolution gets done +checking access permissions at connection time. This name resolution is performed at ACF file load time, which has a few consequences:

    @@ -46,14 +46,17 @@ at ACF file load time, which has a few consequences:

  1. If the DNS is slow when the names are resolved this will delay the process of loading the ACF file.
  2. -
  3. If a host name cannot be resolved the IOC will treat the ACF as invalid, -which prevents any CA clients from connecting.
  4. +
  5. If a host name cannot be resolved the IOC will proceed, but this host name +will never be matched.
  6. Any changes in the hostname to IP address mapping will not be picked up by the IOC unless and until the ACF file gets reloaded.
+

Optionally, IP addresses may be added instead of, or in addition to, host names +in the ACF file.

+

This feature can be enabled before iocInit with


From 32b3eddb94cf4f47494ff2cc58d6f5e0f3f71d21 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver 
Date: Sun, 23 Jun 2019 08:56:32 -0700
Subject: [PATCH 049/281] epicsThreadMustJoin() warn only on double self-join

---
 modules/libcom/src/osi/os/RTEMS/osdThread.c |  14 ++-
 modules/libcom/src/osi/os/WIN32/osdThread.c |  15 ++-
 modules/libcom/src/osi/os/posix/osdThread.c |  15 ++-
 modules/libcom/test/epicsThreadTest.cpp     | 106 ++++++++++++++------
 4 files changed, 108 insertions(+), 42 deletions(-)

diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c
index b30cb4156..b23f66b8f 100644
--- a/modules/libcom/src/osi/os/RTEMS/osdThread.c
+++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c
@@ -377,10 +377,16 @@ void epicsThreadMustJoin(epicsThreadId id)
     }
 
     if(!v->joinable) {
-        /* try to error nicely, however in all likelyhood rtems_task_get_note failed,
-         * or gave us the wrong thread as we are racing thread exit.
-         */
-        cantProceed("%s thread not joinable.\n", v->name);
+        if(epicsThreadGetIdSelf()==id) {
+            errlogPrintf("Warning: %s thread self-join of unjoinable\n", v->name);
+
+        } else {
+            /* try to error nicely, however in all likelyhood de-ref of
+             * 'id' has already caused SIGSEGV as we are racing thread exit,
+             * which free's 'id'.
+             */
+            cantProceed("Error: %s thread not joinable.\n", v->name);
+        }
         return;
 
     } else if(target_tid!=self_tid) {
diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c
index 8c3973703..6d43e769f 100644
--- a/modules/libcom/src/osi/os/WIN32/osdThread.c
+++ b/modules/libcom/src/osi/os/WIN32/osdThread.c
@@ -669,11 +669,16 @@ void epicsThreadMustJoin(epicsThreadId id)
     if(!id) {
         /* no-op */
     } else if(!pParmWIN32->joinable) {
-        /* try to error nicely, however in all likelyhood de-ref of
-         * 'pParmWIN32' has already crashed us as we are racing thread exit,
-         * which free's 'pParmWIN32'.
-         */
-        cantProceed("%s thread not joinable.\n", pParmWIN32->pName);
+        if(epicsThreadGetIdSelf()==id) {
+            fprintf(stderr, "Warning: %s thread self-join of unjoinable\n", pParmWIN32->pName);
+
+        } else {
+            /* try to error nicely, however in all likelyhood de-ref of
+             * 'id' has already caused SIGSEGV as we are racing thread exit,
+             * which free's 'id'.
+             */
+            cantProceed("Error: %s thread not joinable.\n", pParmWIN32->pName);
+        }
         return;
 
     } else if(epicsThreadGetIdSelf() != id) {
diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c
index ed3785205..5ed2cbc56 100644
--- a/modules/libcom/src/osi/os/posix/osdThread.c
+++ b/modules/libcom/src/osi/os/posix/osdThread.c
@@ -608,11 +608,16 @@ void epicsThreadMustJoin(epicsThreadId id)
     if(!id) {
         return;
     } else if(!id->joinable) {
-        /* try to error nicely, however in all likelyhood de-ref of
-         * 'id' has already caused SIGSEGV as we are racing thread exit,
-         * which free's 'id'.
-         */
-        cantProceed("%s thread not joinable.\n", id->name);
+        if(epicsThreadGetIdSelf()==id) {
+            errlogPrintf("Warning: %s thread self-join of unjoinable\n", id->name);
+
+        } else {
+            /* try to error nicely, however in all likelyhood de-ref of
+             * 'id' has already caused SIGSEGV as we are racing thread exit,
+             * which free's 'id'.
+             */
+            cantProceed("Error: %s thread not joinable.\n", id->name);
+        }
         return;
     }
 
diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp
index c50d8c5bd..08d7529fa 100644
--- a/modules/libcom/test/epicsThreadTest.cpp
+++ b/modules/libcom/test/epicsThreadTest.cpp
@@ -18,11 +18,14 @@
 #include 
 
 #include "epicsThread.h"
+#include "epicsEvent.h"
 #include "epicsTime.h"
 #include "errlog.h"
 #include "epicsUnitTest.h"
 #include "testMain.h"
 
+namespace {
+
 static epicsThreadPrivate privateKey;
 
 class myThread: public epicsThreadRunable {
@@ -60,35 +63,8 @@ void myThread::run()
     testOk1(thread.getPriority() == epicsThreadGetPriority(self));
 }
 
-
-typedef struct info {
-    int  isOkToBlock;
-    int  didSomething;
-} info;
-
-extern "C" {
-static void thread(void *arg)
+void testMyThread()
 {
-    info *pinfo = (info *)arg;
-
-    epicsThreadSetOkToBlock(pinfo->isOkToBlock);
-
-    testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock,
-        "%s epicsThreadIsOkToBlock() = %d",
-        epicsThreadGetNameSelf(), pinfo->isOkToBlock);
-
-    pinfo->didSomething = 1;
-}
-}
-
-
-MAIN(epicsThreadTest)
-{
-    testPlan(11);
-
-    unsigned int ncpus = epicsThreadGetCPUs();
-    testDiag("System has %u CPUs", ncpus);
-    testOk1(ncpus > 0);
 
     const int ntasks = 3;
     myThread *myThreads[ntasks];
@@ -108,6 +84,65 @@ MAIN(epicsThreadTest)
         myThreads[i]->thread.exitWait();
         delete myThreads[i];
     }
+}
+
+struct selfJoiner {
+    epicsEvent finished;
+};
+
+void joiner(void *arg) {
+    epicsEvent *finished = (epicsEvent*)arg;
+
+    // This is a no-op
+    epicsThreadMustJoin(epicsThreadGetIdSelf());
+
+    // This is a no-op as well, except for a warning.
+    eltc(0);
+    epicsThreadMustJoin(epicsThreadGetIdSelf());
+    eltc(1);
+
+    testPass("Check double self-join");
+    finished->signal();
+}
+
+typedef struct info {
+    int  isOkToBlock;
+    int  didSomething;
+} info;
+
+void testSelfJoin()
+{
+    epicsEvent finished;
+    epicsThreadOpts opts;
+    epicsThreadOptsDefaults(&opts);
+    opts.priority = 50;
+    opts.joinable = 1;
+
+    (void)epicsThreadCreateOpt("selfjoin", &joiner, &finished, &opts);
+
+    // as this thread "joins" itself, we can't.
+    finished.wait();
+}
+
+} // namespace
+
+extern "C" {
+static void thread(void *arg)
+{
+    info *pinfo = (info *)arg;
+
+    epicsThreadSetOkToBlock(pinfo->isOkToBlock);
+
+    testOk(epicsThreadIsOkToBlock() == pinfo->isOkToBlock,
+        "%s epicsThreadIsOkToBlock() = %d",
+        epicsThreadGetNameSelf(), pinfo->isOkToBlock);
+
+    pinfo->didSomething = 1;
+}
+}
+
+static void testOkToBlock()
+{
 
     epicsThreadOpts opts;
     epicsThreadOptsDefaults(&opts);
@@ -127,5 +162,20 @@ MAIN(epicsThreadTest)
     epicsThreadMustJoin(threadA);
     testOk1(infoA.didSomething);
 
+}
+
+
+MAIN(epicsThreadTest)
+{
+    testPlan(12);
+
+    unsigned int ncpus = epicsThreadGetCPUs();
+    testDiag("System has %u CPUs", ncpus);
+    testOk1(ncpus > 0);
+
+    testMyThread();
+    testSelfJoin();
+    testOkToBlock();
+
     return testDone();
 }

From afc31f2f064974e97ef61a9dc6cc58692a1b0a5f Mon Sep 17 00:00:00 2001
From: Michael Davidsaver 
Date: Sun, 23 Jun 2019 09:29:04 -0700
Subject: [PATCH 050/281] asCaStop() join worker thread

---
 modules/database/src/ioc/as/asCa.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/modules/database/src/ioc/as/asCa.c b/modules/database/src/ioc/as/asCa.c
index d0180448b..e8c5403d9 100644
--- a/modules/database/src/ioc/as/asCa.c
+++ b/modules/database/src/ioc/as/asCa.c
@@ -229,20 +229,23 @@ static void asCaTask(void)
     
 void asCaStart(void)
 {
+    epicsThreadOpts opts;
+    epicsThreadOptsDefaults(&opts);
+    opts.stackSize = epicsThreadGetStackSize(epicsThreadStackBig);
+    opts.priority = epicsThreadPriorityScanLow - 3;
+    opts.joinable = 1;
+
     if(asCaDebug) printf("asCaStart called\n");
     if(firstTime) {
-	firstTime = FALSE;
+        firstTime = FALSE;
         asCaTaskLock=epicsMutexMustCreate();
         asCaTaskWait=epicsEventMustCreate(epicsEventEmpty);
         asCaTaskAddChannels=epicsEventMustCreate(epicsEventEmpty);
         asCaTaskClearChannels=epicsEventMustCreate(epicsEventEmpty);
-        threadid = epicsThreadCreate("asCaTask",
-            (epicsThreadPriorityScanLow - 3),
-            epicsThreadGetStackSize(epicsThreadStackBig),
-            (EPICSTHREADFUNC)asCaTask,0);
-	if(threadid==0) {
-	    errMessage(0,"asCaStart: taskSpawn Failure\n");
-	}
+        threadid = epicsThreadCreateOpt("asCaTask", (EPICSTHREADFUNC)asCaTask, 0, &opts);
+        if(threadid==0) {
+            errMessage(0,"asCaStart: taskSpawn Failure\n");
+        }
     }
     epicsMutexMustLock(asCaTaskLock);
     epicsEventSignal(asCaTaskAddChannels);
@@ -260,6 +263,8 @@ void asCaStop(void)
     epicsEventMustWait(asCaTaskWait);
     if(asCaDebug) printf("asCaStop done\n");
     epicsMutexUnlock(asCaTaskLock);
+    epicsThreadMustJoin(threadid);
+    threadid = 0;
 }
 
 int ascar(int level) { return ascarFP(stdout,level);}

From 01fa58f37b4ab74e355fb1bc74b1b1fcaaa96d1a Mon Sep 17 00:00:00 2001
From: Michael Davidsaver 
Date: Sun, 23 Jun 2019 09:33:08 -0700
Subject: [PATCH 051/281] dbCa join worker

---
 modules/database/src/ioc/db/dbCa.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c
index 65a8327cf..935c397d4 100644
--- a/modules/database/src/ioc/db/dbCa.c
+++ b/modules/database/src/ioc/db/dbCa.c
@@ -68,6 +68,7 @@ static volatile enum dbCaCtl_t {
     ctlInit, ctlRun, ctlPause, ctlExit
 } dbCaCtl;
 static epicsEventId startStopEvent;
+static epicsThreadId dbCaWorker;
 
 struct ca_client_context * dbCaClientContext;
 
@@ -258,10 +259,18 @@ void dbCaShutdown(void)
     dbCaCtl = ctlExit;
     epicsEventSignal(workListEvent);
     epicsEventMustWait(startStopEvent);
+    if(dbCaWorker)
+        epicsThreadMustJoin(dbCaWorker);
 }
 
 static void dbCaLinkInitImpl(int isolate)
 {
+    epicsThreadOpts opts;
+    epicsThreadOptsDefaults(&opts);
+    opts.stackSize = epicsThreadGetStackSize(epicsThreadStackBig);
+    opts.priority = epicsThreadPriorityMedium;
+    opts.joinable = 1;
+
     dbServiceIsolate = isolate;
     dbServiceIOInit();
 
@@ -274,9 +283,8 @@ static void dbCaLinkInitImpl(int isolate)
         startStopEvent = epicsEventMustCreate(epicsEventEmpty);
     dbCaCtl = ctlPause;
 
-    epicsThreadCreate("dbCaLink", epicsThreadPriorityMedium,
-        epicsThreadGetStackSize(epicsThreadStackBig),
-        dbCaTask, NULL);
+    dbCaWorker = epicsThreadCreateOpt("dbCaLink", dbCaTask, NULL, &opts);
+    /* wait for worker to startup and initialize dbCaClientContext */
     epicsEventMustWait(startStopEvent);
 }
 

From 37a76b433a9e7d5a8d26a13fd21ad62f20a0c1c1 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver 
Date: Sun, 23 Jun 2019 10:36:52 -0700
Subject: [PATCH 052/281] dbEvent simplify db_close_events() with join

---
 modules/database/src/ioc/db/dbEvent.c | 71 ++++++++-------------------
 1 file changed, 20 insertions(+), 51 deletions(-)

diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c
index 9304f99b2..48dc9012b 100644
--- a/modules/database/src/ioc/db/dbEvent.c
+++ b/modules/database/src/ioc/db/dbEvent.c
@@ -78,7 +78,6 @@ struct event_user {
     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 */
     void                *extralabor_arg;/* parameter to above */
@@ -117,8 +116,6 @@ static char *EVENT_PEND_NAME = "eventTask";
 
 static struct evSubscrip canceledEvent;
 
-static epicsMutexId stopSync;
-
 static unsigned short ringSpace ( const struct event_que *pevq )
 {
     if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
@@ -260,10 +257,6 @@ dbEventCtx db_init_events (void)
 {
     struct event_user * evUser;
 
-    if (!stopSync) {
-        stopSync = epicsMutexMustCreate();
-    }
-
     if (!dbevEventUserFreeList) {
         freeListInitPvt(&dbevEventUserFreeList,
             sizeof(struct event_user),8);
@@ -287,9 +280,6 @@ dbEventCtx db_init_events (void)
         return NULL;
     }
 
-    /* Flag will be cleared when event task starts */
-    evUser->pendexit = TRUE;
-
     evUser->firstque.evUser = evUser;
     evUser->firstque.writelock = epicsMutexCreate();
     if (!evUser->firstque.writelock)
@@ -304,9 +294,6 @@ dbEventCtx db_init_events (void)
     evUser->lock = epicsMutexCreate();
     if (!evUser->lock)
         goto fail;
-    evUser->pexitsem = epicsEventCreate(epicsEventEmpty);
-    if (!evUser->pexitsem)
-        goto fail;
 
     evUser->flowCtrlMode = FALSE;
     evUser->extraLaborBusy = FALSE;
@@ -321,8 +308,6 @@ fail:
         epicsEventDestroy (evUser->ppendsem);
     if(evUser->pflush_sem)
         epicsEventDestroy (evUser->pflush_sem);
-    if(evUser->pexitsem)
-        epicsEventDestroy (evUser->pexitsem);
     freeListFree(dbevEventUserFreeList,evUser);
     return NULL;
 }
@@ -343,7 +328,6 @@ epicsShareFunc void db_cleanup_events(void)
     dbevFieldLogFreeList = NULL;
 }
 
-    /* intentionally leak stopSync to avoid possible shutdown races */
 /*
  *  DB_CLOSE_EVENTS()
  *
@@ -365,30 +349,15 @@ void db_close_events (dbEventCtx ctx)
      * hazardous to the system's health.
      */
     epicsMutexMustLock ( evUser->lock );
-    if(!evUser->pendexit) { /* event task running */
-        evUser->pendexit = TRUE;
-        epicsMutexUnlock ( evUser->lock );
-
-        /* notify the waiting task */
-        epicsEventSignal(evUser->ppendsem);
-        /* wait for task to exit */
-        epicsEventMustWait(evUser->pexitsem);
-
-        epicsMutexMustLock ( evUser->lock );
-    }
-
+    evUser->pendexit = TRUE;
     epicsMutexUnlock ( evUser->lock );
 
-    epicsMutexMustLock (stopSync);
+    /* notify the waiting task */
+    epicsEventSignal(evUser->ppendsem);
 
-    epicsEventDestroy(evUser->pexitsem);
-    epicsEventDestroy(evUser->ppendsem);
-    epicsEventDestroy(evUser->pflush_sem);
-    epicsMutexDestroy(evUser->lock);
-
-    epicsMutexUnlock (stopSync);
-
-    freeListFree(dbevEventUserFreeList, evUser);
+    if(evUser->taskid)
+        epicsThreadMustJoin(evUser->taskid);
+    /* evUser has been deleted by the worker */
 }
 
 /*
@@ -1068,17 +1037,14 @@ static void event_task (void *pParm)
         }
     }
 
+    epicsEventDestroy(evUser->ppendsem);
+    epicsEventDestroy(evUser->pflush_sem);
+    epicsMutexDestroy(evUser->lock);
+
+    freeListFree(dbevEventUserFreeList, evUser);
+
     taskwdRemove(epicsThreadGetIdSelf());
 
-    /* use stopSync to ensure pexitsem is not destroy'd
-     * until epicsEventSignal() has returned.
-     */
-    epicsMutexMustLock (stopSync);
-
-    epicsEventSignal(evUser->pexitsem);
-
-    epicsMutexUnlock(stopSync);
-
     return;
 }
 
@@ -1090,6 +1056,12 @@ int db_start_events (
     void *init_func_arg, unsigned osiPriority )
 {
      struct event_user * const evUser = (struct event_user *) ctx;
+     epicsThreadOpts opts;
+
+     epicsThreadOptsDefaults(&opts);
+     opts.stackSize = epicsThreadGetStackSize(epicsThreadStackMedium);
+     opts.priority = osiPriority;
+     opts.joinable = 1;
 
      epicsMutexMustLock ( evUser->lock );
 
@@ -1107,15 +1079,12 @@ int db_start_events (
      if (!taskname) {
          taskname = EVENT_PEND_NAME;
      }
-     evUser->taskid = epicsThreadCreate (
-         taskname, osiPriority, 
-         epicsThreadGetStackSize(epicsThreadStackMedium),
-         event_task, (void *)evUser);
+     evUser->taskid = epicsThreadCreateOpt (
+         taskname, event_task, (void *)evUser, &opts);
      if (!evUser->taskid) {
          epicsMutexUnlock ( evUser->lock );
          return DB_EVENT_ERROR;
      }
-     evUser->pendexit = FALSE;
      epicsMutexUnlock ( evUser->lock );
      return DB_EVENT_OK;
 }

From 38999a971f78ebacdd2bad69d3886d9ee4c16ec7 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver 
Date: Sun, 23 Jun 2019 15:21:56 -0700
Subject: [PATCH 053/281] document epicsThread.h

---
 modules/libcom/src/osi/epicsThread.h | 128 ++++++++++++++++++++++++++-
 1 file changed, 124 insertions(+), 4 deletions(-)

diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h
index 61ab323b1..694ac94c7 100644
--- a/modules/libcom/src/osi/epicsThread.h
+++ b/modules/libcom/src/osi/epicsThread.h
@@ -45,6 +45,7 @@ typedef enum {
     epicsThreadBooleanStatusFail, epicsThreadBooleanStatusSuccess
 } epicsThreadBooleanStatus;
 
+/** Lookup target specific default stack size */
 epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize(
     epicsThreadStackSizeClass size);
 
@@ -54,6 +55,20 @@ typedef struct epicsThreadOSD *epicsThreadId;
 typedef epicsThreadId epicsThreadOnceId;
 #define EPICS_THREAD_ONCE_INIT 0
 
+/** Perform one-time initialization.
+ *
+ * Run the provided function if it has not run, and is not running.
+ *
+ * @post The provided function has been run.
+ *
+ * @code
+ * static epicsThreadOnceId onceId = EPICS_THREAD_ONCE_INIT;
+ * static void myInitFunc(void *arg) { ... }
+ * static void some Function(void) {
+ *     epicsThreadOnce(&onceId, &myInitFunc, NULL);
+ * }
+ * @endcode
+ */
 epicsShareFunc void epicsShareAPI epicsThreadOnce(
     epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg);
 
@@ -65,6 +80,7 @@ epicsShareFunc void epicsThreadRealtimeLock(void);
 
 epicsShareFunc void epicsShareAPI epicsThreadExitMain(void);
 
+/** For use with epicsThreadCreateOpt() */
 typedef struct epicsThreadOpts {
     /** Thread priority in OSI range (cf. epicsThreadPriority*) */
     unsigned int priority;
@@ -73,57 +89,123 @@ typedef struct epicsThreadOpts {
      * @warning Do not pass enum epicsThreadStackSizeClass directly!
      */
     unsigned int stackSize;
-    /** Should thread be joinable? (default (0) is not joinable). */
+    /** Should thread be joinable? (default (0) is not joinable).
+     * If joinable=1, then epicsThreadMustJoin() must be called for cleanup thread resources.
+     */
     unsigned int joinable;
 } epicsThreadOpts;
 
+/** Fill in target specific default values. */
 epicsShareFunc void epicsThreadOptsDefaults(epicsThreadOpts *opts);
 
+/** @brief Allocate and start a new OS thread.
+ * @param name A name describing this thread.  Appears in various log and error message.
+ * @param funptr The thread main function.
+ * @param parm Passed to thread main function.
+ * @param opts Modifiers for the new thread, or NULL to use target specific defaults.
+ * @return NULL on error
+ */
 epicsShareFunc epicsThreadId epicsThreadCreateOpt (
     const char * name,
     EPICSTHREADFUNC funptr, void * parm,
     const epicsThreadOpts *opts );
+/** Short-hand for epicsThreadCreateOpt() to create an un-joinable thread. */
 epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate (
     const char * name, unsigned int priority, unsigned int stackSize,
     EPICSTHREADFUNC funptr,void * parm );
+/** Short-hand for epicsThreadCreateOpt() to create an un-joinable thread.
+ * On error calls cantProceed()
+ */
 epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate (
     const char * name, unsigned int priority, unsigned int stackSize,
     EPICSTHREADFUNC funptr,void * parm );
+/** Wait for a joinable thread to exit (return from its main function */
 epicsShareFunc void epicsThreadMustJoin(epicsThreadId id);
+/** Block the current thread until epicsThreadResume(). */
 epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void);
+/** Resume a thread suspended with epicsThreadSuspendSelf() */
 epicsShareFunc void epicsShareAPI epicsThreadResume(epicsThreadId id);
+/** Return thread OSI priority */
 epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPriority(
     epicsThreadId id);
+/** Return thread OSI priority */
 epicsShareFunc unsigned int epicsShareAPI epicsThreadGetPrioritySelf(void);
+/** Change OSI priority of target thread. */
 epicsShareFunc void epicsShareAPI epicsThreadSetPriority(
     epicsThreadId id,unsigned int priority);
+/** Lookup the next usage OSI priority such that priority > *pPriorityJustBelow
+ *  if this is possible with the current target configuration and privlages.
+ */
 epicsShareFunc epicsThreadBooleanStatus epicsShareAPI
     epicsThreadHighestPriorityLevelBelow (
         unsigned int priority, unsigned *pPriorityJustBelow);
+/** Lookup the next usage OSI priority such that priority < *pPriorityJustBelow
+ *  if this is possible with the current target configuration and privlages.
+ */
 epicsShareFunc epicsThreadBooleanStatus epicsShareAPI
     epicsThreadLowestPriorityLevelAbove (
         unsigned int priority, unsigned *pPriorityJustAbove);
+/** Test if two thread IDs actually refer to the same OS thread */
 epicsShareFunc int epicsShareAPI epicsThreadIsEqual(
     epicsThreadId id1, epicsThreadId id2);
+/** Test if thread has been suspended with epicsThreadSuspendSelf() */
 epicsShareFunc int epicsShareAPI epicsThreadIsSuspended(epicsThreadId id);
+/** @brief Block the calling thread for at least the specified time.
+ * @param seconds Time to wait in seconds.  Values <=0 blocks for the shortest possible time.
+ */
 epicsShareFunc void epicsShareAPI epicsThreadSleep(double seconds);
+/** @brief Query a value approximating the OS timer/scheduler resolution.
+ * @return A value in seconds >=0
+ *
+ * @warning On targets other than vxWorks and RTEMS, the quantum value often isn't
+ *          meaningful.  Use of this function is discouraged in portable code.
+ */
 epicsShareFunc double epicsShareAPI epicsThreadSleepQuantum(void);
+/** Find an epicsThreadId associated with the current thread.
+ * For non-EPICS threads, a new epicsThreadId may be allocated.
+ */
 epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetIdSelf(void);
+/** Attempt to find the first instance of a thread by name.
+ * @return An epicsThreadId, or NULL if no such thread is currently running.
+ *         Note that a non-NULL ID may still be invalid if this call races
+ *         with thread exit.
+ *
+ * @warning Safe use of this function requires external knowledge that this
+ *          thread will not return.
+ */
 epicsShareFunc epicsThreadId epicsShareAPI epicsThreadGetId(const char *name);
+/** Return a value approximating the number of threads which this target
+ *  can run in parallel.  This value is advisory.
+ * @return >=1
+ */
 epicsShareFunc int epicsThreadGetCPUs(void);
 
+/** Return the name of the current thread.
+ *
+ * @return Never NULL.  Storage lifetime tied to epicsThreadId.
+ *
+ * This is either a copy of the string passed to epicsThread*Create*(),
+ * or an arbitrary unique string for non-EPICS threads.
+ */
 epicsShareFunc const char * epicsShareAPI epicsThreadGetNameSelf(void);
 
-/* For epicsThreadGetName name is guaranteed to be null terminated */
-/* size is size of buffer to hold name (including terminator) */
-/* Failure results in an empty string stored in name */
+/** Copy out the thread name into the provided buffer.
+ *
+ * Guaranteed to be null terminated.
+ * size is number of bytes in buffer to hold name (including terminator).
+ * Failure results in an empty string stored in name.
+ */
 epicsShareFunc void epicsShareAPI epicsThreadGetName(
     epicsThreadId id, char *name, size_t size);
 
 epicsShareFunc int epicsShareAPI epicsThreadIsOkToBlock(void);
 epicsShareFunc void epicsShareAPI epicsThreadSetOkToBlock(int isOkToBlock);
 
+/** Print to stdout information about all running EPICS threads.
+ * @param level 0 prints minimal output.  Higher values print more details.
+ */
 epicsShareFunc void epicsShareAPI epicsThreadShowAll(unsigned int level);
+/** Print info about a single EPICS thread. */
 epicsShareFunc void epicsShareAPI epicsThreadShow(
     epicsThreadId id,unsigned int level);
 
@@ -134,10 +216,17 @@ epicsShareFunc int epicsThreadHookDelete(EPICS_THREAD_HOOK_ROUTINE hook);
 epicsShareFunc void epicsThreadHooksShow(void);
 epicsShareFunc void epicsThreadMap(EPICS_THREAD_HOOK_ROUTINE func);
 
+/** Thread local storage */
 typedef struct epicsThreadPrivateOSD * epicsThreadPrivateId;
+/** Allocate a new thread local variable.
+ * This variable will initially hold NULL for each thread.
+ */
 epicsShareFunc epicsThreadPrivateId epicsShareAPI epicsThreadPrivateCreate(void);
+/** Free a thread local variable */
 epicsShareFunc void epicsShareAPI epicsThreadPrivateDelete(epicsThreadPrivateId id);
+/** Update thread local variable */
 epicsShareFunc void epicsShareAPI epicsThreadPrivateSet(epicsThreadPrivateId,void *);
+/** Fetch the current value of a thread local variable */
 epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId);
 
 #ifdef __cplusplus
@@ -149,33 +238,64 @@ epicsShareFunc void * epicsShareAPI epicsThreadPrivateGet(epicsThreadPrivateId);
 #include "epicsEvent.h"
 #include "epicsMutex.h"
 
+//! Interface used with class epicsThread
 class epicsShareClass epicsThreadRunable {
 public:
     virtual ~epicsThreadRunable () = 0;
+    //! Thread main function.
+    //! C++ exceptions which propagate from this method will be caught and a warning printed.
+    //! No other action is taken.
     virtual void run () = 0;
+    //! Optional.  Called via epicsThread::show()
     virtual void show ( unsigned int level ) const;
 };
 
 extern "C" void epicsThreadCallEntryPoint ( void * );
 
+/** @brief An OS thread
+ *
+ * A wrapper around the epicsThread* C API.
+ *
+ * @note Threads must be start() ed.
+ */
 class epicsShareClass epicsThread {
 public:
+    /** Create a new thread with the provided information.
+     *
+     * cf. epicsThreadOpts
+     * @note Threads must be start() ed.
+     * @throws epicsThread::unableToCreateThread on error.
+     */
     epicsThread ( epicsThreadRunable &,const char *name, unsigned int stackSize,
         unsigned int priority=epicsThreadPriorityLow );
     ~epicsThread () throw ();
+    //! Actually start the thread.
     void start () throw ();
+    //! Wait for the thread epicsRunnable::run() to return.
     void exitWait () throw ();
+    //! Wait for the thread epicsRunnable::run() to return.
+    //! @param delay Wait up to this many seconds.
+    //! @returns true if run() returned.  false on timeout.
     bool exitWait ( const double delay ) throw (); 
+    //! @throws A special exitException which will be caught and ignored.
+    //! @note This exitException doesn't not derive from std::exception
     static void exit ();
+    //! cf. epicsThreadResume()
     void resume () throw ();
+    //! cf. epicsThreadGetName();
     void getName ( char * name, size_t size ) const throw ();
+    //! cf. epicsThreadGetIdSelf()()
     epicsThreadId getId () const throw ();
+    //! cf. epicsThreadGetPriority()
     unsigned int getPriority () const throw ();
+    //! cf. epicsThreadSetPriority()
     void setPriority ( unsigned int ) throw ();
     bool priorityIsEqual ( const epicsThread & ) const throw ();
     bool isSuspended () const throw ();
+    //! @return true if call through this thread's epicsRunnable::run()
     bool isCurrentThread () const throw ();
     bool operator == ( const epicsThread & ) const throw ();
+    //! Say something interesting about this thread to stdout.
     void show ( unsigned level ) const throw ();
 
     /* these operate on the current thread */

From 57d2b143e9ab2a547da14b74fbb4c85ec347da15 Mon Sep 17 00:00:00 2001
From: Michael Davidsaver 
Date: Sun, 23 Jun 2019 15:31:35 -0700
Subject: [PATCH 054/281] update release notes

---
 documentation/RELEASE_NOTES.html | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
index 63f8880a7..fa9727aff 100644
--- a/documentation/RELEASE_NOTES.html
+++ b/documentation/RELEASE_NOTES.html
@@ -26,6 +26,28 @@ release.

--> +

Add epicsThreadCreateOpt() and epicsThreadMustJoin()

+ +

epicsThreadCreateOpt() is an alternative to epicsThreadCreate() which +passes some arguments via a structure (struct epicsThreadOpts). +This epicsThreadOpts* may be NULL to use target specific +defaults. Caller wishing to provide thread options should first call +epicsThreadOptsDefaults() to fill in the defaults.

+ +
+void startitup(void) {
+    epicsThreadOpts opts;
+    epicsThreadOptsDefaults(&opts);
+    opts.priority = epicsThreadPriorityMedium;
+
+    ... = epicsThreadCreateOpt("my thread", &threadMain, NULL, &opts);
+}
+
+ +

If the new epicsThreadOpts::joinable option flag is set (not the default), +then epicsThreadMustJoin() needs to be called to free up thread resources. +This function will block until the thread main function has returned.

+

Launchpad Bugs

The list of tracked bugs fixed in this release can be found on the From 93a96e33c09e6377e112bc3f124d06476f75bde9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 16:49:41 -0700 Subject: [PATCH 055/281] dbChArrTest use dbUnitTest.h --- modules/database/test/ioc/db/dbChArrTest.cpp | 41 ++++++-------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/modules/database/test/ioc/db/dbChArrTest.cpp b/modules/database/test/ioc/db/dbChArrTest.cpp index 8a788bed6..8255fdc39 100644 --- a/modules/database/test/ioc/db/dbChArrTest.cpp +++ b/modules/database/test/ioc/db/dbChArrTest.cpp @@ -36,7 +36,7 @@ #include "iocInit.h" #include "iocsh.h" #include "dbChannel.h" -#include "epicsUnitTest.h" +#include "dbUnitTest.h" #include "testMain.h" #include "osiFileName.h" @@ -197,50 +197,33 @@ static void check(short dbr_type) { dbChannelDelete(pch); } -static dbEventCtx evtctx; - -extern "C" { -static void dbChArrTestCleanup(void* junk) -{ - dbFreeBase(pdbbase); - registryFree(); - pdbbase=0; - - db_close_events(evtctx); - - dbmfFreeChunks(); -} -} - MAIN(dbChArrTest) { testPlan(102); /* Prepare the IOC */ + testdbPrepare(); epicsEnvSet("EPICS_CA_SERVER_PORT", server_port); - if (dbReadDatabase(&pdbbase, "dbChArrTest.dbd", - "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR - "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL)) - testAbort("Database description not loaded"); + testdbReadDatabase("dbChArrTest.dbd", + "." OSI_PATH_LIST_SEPARATOR ".." OSI_PATH_LIST_SEPARATOR + "../O.Common" OSI_PATH_LIST_SEPARATOR "O.Common", NULL); dbChArrTest_registerRecordDeviceDriver(pdbbase); - if (dbReadDatabase(&pdbbase, "dbChArrTest.db", - "." OSI_PATH_LIST_SEPARATOR "..", NULL)) - testAbort("Test database not loaded"); + testdbReadDatabase("dbChArrTest.db", + "." OSI_PATH_LIST_SEPARATOR "..", NULL); - epicsAtExit(&dbChArrTestCleanup,NULL); - - /* Start the IOC */ - - iocInit(); - evtctx = db_init_events(); + testIocInitOk(); check(DBR_LONG); check(DBR_DOUBLE); check(DBR_STRING); + testIocShutdownOk(); + + testdbCleanup(); + return testDone(); } From 14440b2d9d30a25addac00c4e3d227b63def6ecb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 19:28:03 -0700 Subject: [PATCH 056/281] more RTEMS join --- modules/libcom/src/osi/os/RTEMS/osdThread.c | 7 ++++--- modules/libcom/test/epicsThreadTest.cpp | 7 +++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index b23f66b8f..fdc31759f 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -366,7 +366,7 @@ threadMustCreate (const char *name, void epicsThreadMustJoin(epicsThreadId id) { rtems_id target_tid = (rtems_id)id, self_tid; - struct taskVar *v; + struct taskVar *v = 0; rtems_task_ident (RTEMS_SELF, 0, &self_tid); @@ -375,10 +375,11 @@ void epicsThreadMustJoin(epicsThreadId id) rtems_task_get_note (target_tid, RTEMS_NOTEPAD_TASKVAR, ¬e); v = (void *)note; } + /* 'v' may be NULL if 'id' represents a non-EPICS thread other than _main_. */ - if(!v->joinable) { + if(!v || !v->joinable) { if(epicsThreadGetIdSelf()==id) { - errlogPrintf("Warning: %s thread self-join of unjoinable\n", v->name); + errlogPrintf("Warning: %s thread self-join of unjoinable\n", v ? v->name : "non-EPICS thread"); } else { /* try to error nicely, however in all likelyhood de-ref of diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index 08d7529fa..edaada914 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -172,10 +172,17 @@ MAIN(epicsThreadTest) unsigned int ncpus = epicsThreadGetCPUs(); testDiag("System has %u CPUs", ncpus); testOk1(ncpus > 0); + testDiag("main() thread %p", epicsThreadGetIdSelf()); testMyThread(); testSelfJoin(); testOkToBlock(); + // attempt to self-join from a non-EPICS thread + // to make sure it does nothing as expected + eltc(0); + epicsThreadMustJoin(epicsThreadGetIdSelf()); + eltc(1); + return testDone(); } From a81e261e23ac744c297a6ebc882b473a5e46cdf0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 19:43:34 -0700 Subject: [PATCH 057/281] iocsh trap arg. parsing errors --- modules/libcom/src/iocsh/iocsh.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 26ecb5b01..7392bca42 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -868,6 +868,9 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Set up redirection */ if ((openRedirect(filename, lineno, redirects) == 0) && (argc > 0)) { + // error unless a function is actually called. + // handles command not-found and arg parsing errors. + scope.errored = true; /* * Look up command */ @@ -924,7 +927,6 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } else { showError(filename, lineno, "Command %s not found.", argv[0]); - scope.errored = true; } } stopRedirect(filename, lineno, redirects); From 87d5ca1619ec99055c5fdd0ecfcf7c8fc9edca57 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 24 Jun 2019 10:35:25 -0700 Subject: [PATCH 058/281] rpath $ORIGIN doc --- configure/CONFIG_SITE | 2 +- src/tools/makeRPath.py | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index 49f82c7a8..a39911783 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -172,7 +172,7 @@ GCC_PIPE = NO # Must be either YES, NO, or ORIGIN. If you set this to NO you must also provide a # way for Base executables to find their shared libraries when they are # run at build-time, e.g. set the LD_LIBRARY_PATH environment variable. -# ORIGIN is Linux specific. +# ORIGIN is a feature of the ELF executable format used by Linux, freebsd, and solaris. LINKER_USE_RPATH = YES # Only used when LINKER_USE_RPATH=ORIGIN diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py index 5d151a41a..eeda8ab55 100644 --- a/src/tools/makeRPath.py +++ b/src/tools/makeRPath.py @@ -10,9 +10,17 @@ from argparse import ArgumentParser if os.environ.get('EPICS_DEBUG_RPATH','')=='YES': sys.stderr.write('%s'%sys.argv) -P = ArgumentParser() +P = ArgumentParser(description='''Compute and output -rpath entries for each of the given paths. + Paths under --root will be computed as relative to --final .''', +epilog=''' +eg. A library to be placed in /build/lib and linked against libraries in +'/build/lib', '/build/module/lib', and '/other/lib' would pass: + + "makeRPath.py -F /build/lib -R /build /build/lib /build/module/lib /other/lib" +which prints "-Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib" +''') P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file') -P.add_argument('-R','--root',default='/') +P.add_argument('-R','--root',default='/', help='Root of relocatable tree.') P.add_argument('-O', '--origin', default='$ORIGIN') P.add_argument('path', nargs='*') args = P.parse_args() From ea1b208c33295f0b81f369bcb638a73c5a83c439 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 24 Jun 2019 13:23:28 -0700 Subject: [PATCH 059/281] redo softIoc to be more c++y --- modules/database/src/std/softIoc/softMain.cpp | 419 ++++++++---------- 1 file changed, 197 insertions(+), 222 deletions(-) diff --git a/modules/database/src/std/softIoc/softMain.cpp b/modules/database/src/std/softIoc/softMain.cpp index 01ef19b2f..bc945c80e 100644 --- a/modules/database/src/std/softIoc/softMain.cpp +++ b/modules/database/src/std/softIoc/softMain.cpp @@ -9,55 +9,12 @@ /* Author: Andrew Johnson Date: 2003-04-08 */ -/* Usage: - * softIoc [-D softIoc.dbd] [-h] [-S] [-s] [-a ascf] - * [-m macro=value,macro2=value2] [-d file.db] - * [-x prefix] [st.cmd] - * - * If used the -D option must come first, and specify the - * path to the softIoc.dbd file. The compile-time install - * location is saved in the binary as a default. - * - * Usage information will be printed if -h is given, then - * the program will exit normally. - * - * The -S option prevents an interactive shell being started - * after all arguments have been processed. - * - * Previous versions accepted a -s option to cause a shell - * to be started; this option is still accepted but ignored - * since a command shell is now started by default. - * - * Access Security can be enabled with the -a option giving - * the name of the configuration file; if any macros were - * set with -m before the -a option was given, they will be - * used as access security substitution macros. - * - * Any number of -m and -d arguments can be interspersed; - * the macros are applied to the following .db files. Each - * later -m option causes earlier macros to be discarded. - * - * The -x option loads the softIocExit.db with the macro - * IOC set to the string provided. This database contains - * a subroutine record named $(IOC):exit which has its field - * SNAM set to "exit". When this record is processed, the - * subroutine that runs will call epicsExit() with the value - * of the field A determining whether the exit status is - * EXIT_SUCCESS if (A == 0.0) or EXIT_FAILURE (A != 0.0). - * - * A st.cmd file is optional. If any databases were loaded - * the st.cmd file will be run *after* iocInit. To perform - * iocsh commands before iocInit, all database loading must - * be performed by the script itself, or by the user from - * the interactive IOC shell. - */ - -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "registryFunction.h" #include "epicsThread.h" #include "epicsExit.h" @@ -74,6 +31,12 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); +#ifndef EPICS_BASE +// so IDEs knows EPICS_BASE is a string constant +# define EPICS_BASE "/" +# error -DEPICS_BASE required +#endif + #define DBD_BASE "dbd/softIoc.dbd" #define EXIT_BASE "db/softIocExit.db" #define DBD_FILE_REL "../../" DBD_BASE @@ -81,190 +44,202 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); #define DBD_FILE EPICS_BASE "/" DBD_BASE #define EXIT_FILE EPICS_BASE "/" EXIT_BASE -const char *arg0; -const char *base_dbd = DBD_FILE; -const char *exit_db = EXIT_FILE; - -static void preparePath(void) -{ - FILE *fp; - char *prefix = epicsGetExecDir(); - char *dbd, *exit; - if(!prefix) return; - - dbd = (char*)malloc(strlen(prefix) + strlen(DBD_FILE_REL) + 1); - if(dbd) { - dbd[0] = '\0'; - strcat(dbd, prefix); - strcat(dbd, DBD_FILE_REL); - printf("Testing '%s'\n", dbd); - if((fp = fopen(dbd, "rb"))!=NULL) { - fclose(fp); - base_dbd = dbd; - } - } - - exit = (char*)malloc(strlen(prefix) + strlen(EXIT_FILE_REL) + 1); - if(exit) { - exit[0] = '\0'; - strcat(exit, prefix); - strcat(exit, EXIT_FILE_REL); - if((fp = fopen(exit, "rb"))!=NULL) { - fclose(fp); - exit_db = exit; - } - } -} +namespace { static void exitSubroutine(subRecord *precord) { epicsExitLater((precord->a == 0.0) ? EXIT_SUCCESS : EXIT_FAILURE); } -static void usage(int status) { - printf("Usage: %s [-D softIoc.dbd] [-h] [-S] [-a ascf]\n", arg0); - puts("\t[-m macro=value,macro2=value2] [-d file.db]"); - puts("\t[-x prefix] [st.cmd]"); - puts("Compiled-in path to softIoc.dbd is:"); - printf("\t%s\n", base_dbd); - epicsExit(status); +void usage(const char *arg0, const std::string& base_dbd) { + std::cout<<"Usage: "< If used, must come first. Specify the path to the softIoc.dbdfile." + " The compile-time install location is saved in the binary as a default.\n" + "\n" + " -h Print this mesage and exit.\n" + "\n" + " -S Prevents an interactive shell being started.\n" + "\n" + " -s Previously caused a shell to be started. Now accepted and ignored.\n" + "\n" + " -a Access Security configuration file. Macro substitution is\n" + " performed.\n" + "\n" + " -m =,... Set/replace macro definitions used by subsequent -d and\n" + " -a.\n" + "\n" + " -d Load records from file (dbLoadRecords). Macro substitution is\n" + " performed.\n" + "\n" + " -x Load softIocExit.db. Provides a record \":exit\".\n" + " Put 0 to exit with success, or non-zero to exit with an error.\n" + "\n" + "Any number of -m and -d arguments can be interspersed; the macros are applied\n" + "to the following .db files. Each later -m option causes earlier macros to be\n" + "discarded.\n" + "\n" + "A st.cmd file is optional. If any databases were loaded the st.cmd file will\n" + "be run *after* iocInit. To perform iocsh commands before iocInit, all database\n" + "loading must be performed by the script itself, or by the user from the\n" + "interactive IOC shell.\n" + "\n" + "Compiled-in path to softIoc.dbd is:\n" + "\t"<(base_dbd); - char *macros = NULL; - char xmacro[PVNAME_STRINGSZ + 4]; - int startIocsh = 1; /* default = start shell */ - int loadedDb = 0; - - arg0 = strrchr(*argv, '/'); - if (!arg0) { - arg0 = *argv; - } else { - ++arg0; /* skip the '/' */ - } - - --argc, ++argv; - - /* Do this here in case the dbd file not available */ - if (argc>0 && **argv=='-' && (*argv)[1]=='h') { - usage(EXIT_SUCCESS); - } - - if (argc>1 && **argv=='-' && (*argv)[1]=='D') { - dbd_file = *++argv; - argc -= 2; - ++argv; - } - - if (dbLoadDatabase(dbd_file, NULL, NULL)) { - epicsExit(EXIT_FAILURE); - } - - softIoc_registerRecordDeviceDriver(pdbbase); - registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine); + try { + std::string dbd_file(DBD_FILE), + exit_file(EXIT_FILE), + macros, // scratch space for macros (may be given more than once) + xmacro; + bool interactive = true; + bool loadedDb = false; - while (argc>1 && **argv == '-') { - switch ((*argv)[1]) { - case 'a': - if (macros) asSetSubstitutions(macros); - asSetFilename(*++argv); - --argc; - break; - - case 'd': - if (dbLoadRecords(*++argv, macros)) { - epicsExit(EXIT_FAILURE); - } - loadedDb = 1; - --argc; - break; - - case 'h': - usage(EXIT_SUCCESS); - - case 'm': - macros = *++argv; - --argc; - break; - - case 'S': - startIocsh = 0; - break; - - case 's': - break; - - case 'x': - epicsSnprintf(xmacro, sizeof xmacro, "IOC=%s", *++argv); - if (dbLoadRecords(exit_db, xmacro)) { - epicsExit(EXIT_FAILURE); - } - loadedDb = 1; - --argc; - break; - - default: - printf("%s: option '%s' not recognized\n", arg0, *argv); - usage(EXIT_FAILURE); - } - --argc; - ++argv; + // attempt to compute relative paths + { + std::string prefix; + char *cprefix = epicsGetExecDir(); + if(cprefix) { + try { + prefix = cprefix; + free(cprefix); + } catch(...) { + free(cprefix); + throw; + } + } + + dbd_file = prefix + DBD_FILE_REL; + exit_file = prefix + EXIT_FILE_REL; + } + + int opt; + + while ((opt = getopt(argc, argv, "ha:d:m:Ssx:")) != -1) { + switch (opt) { + case 'h': /* Print usage */ + usage(argv[0], dbd_file); + epicsExit(0); + return 0; + default: + usage(argv[0], dbd_file); + std::cerr<<"Unknown argument: -"<0 && **argv=='-') { - switch((*argv)[1]) { - case 'a': - case 'd': - case 'm': - case 'x': - printf("%s: missing argument to option '%s'\n", arg0, *argv); - usage(EXIT_FAILURE); - - case 'h': - usage(EXIT_SUCCESS); - - case 'S': - startIocsh = 0; - break; - - case 's': - break; - - default: - printf("%s: option '%s' not recognized\n", arg0, *argv); - usage(EXIT_FAILURE); - } - --argc; - ++argv; - } - - if (loadedDb) { - iocInit(); - epicsThreadSleep(0.2); - } - - /* run user's startup script */ - if (argc>0) { - if (iocsh(*argv)) epicsExit(EXIT_FAILURE); - epicsThreadSleep(0.2); - loadedDb = 1; /* Give it the benefit of the doubt... */ - } - - /* start an interactive shell if it was requested */ - if (startIocsh) { - iocsh(NULL); - } else { - if (loadedDb) { - epicsThreadExitMain(); - } else { - printf("%s: Nothing to do!\n", arg0); - usage(EXIT_FAILURE); - } - } - epicsExit(EXIT_SUCCESS); - /*Note that the following statement will never be executed*/ - return 0; } From 784d619bdee4653f8412f664b7338fe42f67e047 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 24 Jun 2019 15:41:48 -0700 Subject: [PATCH 060/281] makeRPath allow multiple root directories Allows handling of complex situations like a package build where some libraries are in a staging area, but will be copied to the same final location. eg. LINKER_ORIGIN_ROOT=/usr/lib/epics:/build/mymodule Where build TOP is /build/mymodule --- configure/CONFIG_SITE | 5 ++-- src/tools/makeRPath.py | 59 +++++++++++++++++++++++++++++++++--------- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/configure/CONFIG_SITE b/configure/CONFIG_SITE index a39911783..c46703f84 100644 --- a/configure/CONFIG_SITE +++ b/configure/CONFIG_SITE @@ -176,9 +176,10 @@ GCC_PIPE = NO LINKER_USE_RPATH = YES # Only used when LINKER_USE_RPATH=ORIGIN -# The build time root of the relocatable tree. -# Linking to libraries under this root directory will be relative. +# The build time root(s) of the relocatable tree (separate multiple w/ ':'). +# Linking to libraries under any root directory will be relative. # Linking to libraries outside of this root will be absolute. +# All root directories are considered to be the same. LINKER_ORIGIN_ROOT = $(INSTALL_LOCATION) # Overrides for the settings above may appear in a CONFIG_SITE.local file diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py index eeda8ab55..000b8b450 100644 --- a/src/tools/makeRPath.py +++ b/src/tools/makeRPath.py @@ -4,6 +4,7 @@ from __future__ import print_function import sys import os +from collections import OrderedDict # used as OrderedSet from argparse import ArgumentParser @@ -20,26 +21,60 @@ eg. A library to be placed in /build/lib and linked against libraries in which prints "-Wl,-rpath,$ORIGIN/. -Wl,-rpath,$ORIGIN/../module/lib -Wl,-rpath,/other/lib" ''') P.add_argument('-F','--final',default=os.getcwd(), help='Final install location for ELF file') -P.add_argument('-R','--root',default='/', help='Root of relocatable tree.') +P.add_argument('-R','--root',default='', help='Root(s) of relocatable tree. Separate with :') P.add_argument('-O', '--origin', default='$ORIGIN') P.add_argument('path', nargs='*') args = P.parse_args() -fdir = os.path.abspath(args.final) +# eg. +# target to be installed as: /build/bin/blah +# +# post-install will copy as: /install/bin/blah +# +# Need to link against: +# /install/lib/libA.so +# /build/lib/libB.so +# /other/lib/libC.so +# +# Want final result to be: +# -rpath $ORIGIN/../lib -rpath /other/lib \ +# -rpath-link /build/lib -rpath-link /install/lib -output = [] +fdir = os.path.abspath(args.final) +roots = [os.path.abspath(root) for root in args.root.split(':') if len(root)] + +# find the root which contains the final location +froot = None +for root in roots: + frel = os.path.relpath(fdir, root) + if not frel.startswith('..'): + # final dir is under this root + froot = root + break + +if froot is None: + sys.stderr.write("makeRPath: Final location %s\nNot under any of: %s\n"%(fdir, roots)) + sys.exit(1) + +output = OrderedDict() for path in args.path: path = os.path.abspath(path) - if args.root and os.path.relpath(path, args.root).startswith('../'): - pass # absolute rpath - else: - # some older binutils don't seem to handle $ORIGIN correctly - # when locating dependencies of libraries. So also provide - # the absolute path for internal use by 'ld' only. - output.append('-Wl,-rpath-link,'+path) - path = os.path.relpath(path, fdir) + for root in roots: + rrel = os.path.relpath(path, root) + if not rrel.startswith('..'): + # path is under this root - output.append('-Wl,-rpath,'+os.path.join(args.origin, path)) + # some older binutils don't seem to handle $ORIGIN correctly + # when locating dependencies of libraries. So also provide + # the absolute path for internal use by 'ld' only. + output['-Wl,-rpath-link,'+path] = True + + # frel is final location relative to enclosing root + # rrel is target location relative to enclosing root + path = os.path.relpath(rrel, frel) + break + + output['-Wl,-rpath,'+os.path.join(args.origin, path)] = True print(' '.join(output)) From 398fdee33ebf2f20bef733653839cbf2118d22fe Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 26 Jun 2019 23:28:51 -0500 Subject: [PATCH 061/281] Added db_available_logs() for filter test code to use Returns the number of items available on the db_field_log free-list. --- src/ioc/db/dbEvent.c | 5 +++++ src/ioc/db/dbEvent.h | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/dbEvent.c b/src/ioc/db/dbEvent.c index fb1f3a168..d1f954834 100644 --- a/src/ioc/db/dbEvent.c +++ b/src/ioc/db/dbEvent.c @@ -1165,3 +1165,8 @@ void db_delete_field_log (db_field_log *pfl) freeListFree(dbevFieldLogFreeList, pfl); } } + +int db_available_logs(void) +{ + return (int) freeListItemsAvail(dbevFieldLogFreeList); +} diff --git a/src/ioc/db/dbEvent.h b/src/ioc/db/dbEvent.h index fe0e52f90..2e496a726 100644 --- a/src/ioc/db/dbEvent.h +++ b/src/ioc/db/dbEvent.h @@ -78,6 +78,7 @@ epicsShareFunc void db_event_disable (dbEventSubscription es); epicsShareFunc struct db_field_log* db_create_event_log (struct evSubscrip *pevent); epicsShareFunc struct db_field_log* db_create_read_log (struct dbChannel *chan); epicsShareFunc void db_delete_field_log (struct db_field_log *pfl); +epicsShareFunc int db_available_logs(void); #define DB_EVENT_OK 0 #define DB_EVENT_ERROR (-1) @@ -87,4 +88,3 @@ epicsShareFunc void db_delete_field_log (struct db_field_log *pfl); #endif #endif /*INCLdbEventh*/ - From e03c7edfe5ac87f8573d0ad420167eec8d26a7bd Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 26 Jun 2019 23:32:52 -0500 Subject: [PATCH 062/281] Check free-list size to ensure field-logs freed properly Moves where the field-logs get freed into the mustPass/mustDrop routines, where it only happens if the filter didn't free them itself. Filters that save field-logs can't use this code as-is. --- src/std/filters/test/decTest.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/std/filters/test/decTest.c b/src/std/filters/test/decTest.c index cc9317eb4..b6b2276c6 100644 --- a/src/std/filters/test/decTest.c +++ b/src/std/filters/test/decTest.c @@ -64,15 +64,29 @@ static void testHead (char* title) { } static void mustDrop(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); testOk(NULL == pfl2, "filter drops field_log (%s)", m); + testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", + oldFree, newFree); + + if (newFree == oldFree) + db_delete_field_log(pfl); } static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); testOk(pfl == pfl2, "filter passes field_log (%s)", m); + testOk(newFree == oldFree, "field_log was not freed - %d => %d", + oldFree, newFree); + + if (newFree == oldFree) + db_delete_field_log(pfl); } static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) { @@ -114,7 +128,7 @@ MAIN(decTest) int i; dbEventCtx evtctx; - testPlan(68); + testPlan(103); testdbPrepare(); @@ -165,9 +179,6 @@ MAIN(decTest) mustPass(pch, pfl[3], "i=3"); mustPass(pch, pfl[4], "i=4"); - for (i = 0; i < 5; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); /* Decimation (N=2) */ @@ -196,9 +207,6 @@ MAIN(decTest) mustPass(pch, pfl[8], "i=8"); mustDrop(pch, pfl[9], "i=9"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); /* Decimation (N=3) */ @@ -227,9 +235,6 @@ MAIN(decTest) mustDrop(pch, pfl[8], "i=8"); mustPass(pch, pfl[9], "i=9"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); /* Decimation (N=4) */ @@ -258,9 +263,6 @@ MAIN(decTest) mustPass(pch, pfl[8], "i=8"); mustDrop(pch, pfl[9], "i=9"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); db_close_events(evtctx); From f79c69f0a0ed7b323af8c16751afe9e25e4914fc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 26 Jun 2019 23:33:35 -0500 Subject: [PATCH 063/281] Fix the decimate filter, free field-logs when dropping them --- src/std/filters/decimate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/std/filters/decimate.c b/src/std/filters/decimate.c index d34884ebe..502422f55 100644 --- a/src/std/filters/decimate.c +++ b/src/std/filters/decimate.c @@ -63,6 +63,8 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { if (i++ == 0) passfl = pfl; + else + db_delete_field_log(pfl); if (i >= my->n) i = 0; From ff1462fcc78a326548198afff43d3dff9acebb20 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 28 Jun 2019 12:28:41 -0500 Subject: [PATCH 064/281] Working VxWorks implementation of epicsThreadMustJoin() --- modules/libcom/src/osi/os/vxWorks/osdThread.c | 153 +++++++++++++++--- 1 file changed, 133 insertions(+), 20 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 6847e9769..43770eab3 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -34,6 +34,22 @@ #include "vxLib.h" #include "epicsExit.h" +#if EPICS_THREAD_CAN_JOIN + /* The implementation of epicsThreadMustJoin() here uses 2 features + * of VxWorks that were first introduced in VxWorks 6.9: taskWait(), + * and the taskSpareFieldGet/Set routines in taskUtilLib. + */ + #include + + #define JOIN_WARNING_TIMEOUT (60 * sysClkRateGet()) + + static SPARE_NUM joinField; + #define ALLOT_JOIN(tid) taskSpareNumAllot(tid, &joinField) +#else + #define ALLOT_JOIN(tid) +#endif + + epicsShareFunc void osdThreadHooksRun(epicsThreadId id); #if CPU_FAMILY == MC680X0 @@ -109,6 +125,7 @@ static void epicsThreadInit(void) assert(taskIdList); taskIdListSize = ID_LIST_CHUNK; atRebootRegister(); + ALLOT_JOIN(0); done = 1; } lock = 0; @@ -177,19 +194,58 @@ void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg) } semGive(epicsThreadOnceMutex); } - + +#if EPICS_THREAD_CAN_JOIN + +/* This routine is not static so it appears in the back-trace + * of a thread that is waiting to be joined. + */ +void epicsThreadAwaitingJoin(int tid) +{ + SEM_ID joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField); + STATUS status; + + if (!joinSem || (int) joinSem == ERROR) + return; + + /* Wait for our supervisor */ + status = semTake(joinSem, JOIN_WARNING_TIMEOUT); + if (status && errno == S_objLib_OBJ_TIMEOUT) { + errlogPrintf("Warning: epicsThread '%s' still awaiting join\n", + epicsThreadGetNameSelf()); + status = semTake(joinSem, WAIT_FOREVER); + } + if (status) + perror("epicsThreadAwaitingJoin"); + + semDelete(joinSem); + taskSpareFieldSet(tid, joinField, 0); +} + #define PREPARE_JOIN(tid, joinable) \ + taskSpareFieldSet(tid, joinField, \ + joinable ? (int) semBCreate(SEM_Q_FIFO, SEM_EMPTY) : 0) + #define AWAIT_JOIN(tid) epicsThreadAwaitingJoin(tid) +#else + #define PREPARE_JOIN(tid, joinable) + #define AWAIT_JOIN(tid) +#endif + static void createFunction(EPICSTHREADFUNC func, void *parm) { int tid = taskIdSelf(); taskVarAdd(tid,(int *)(char *)&papTSD); - /*Make sure that papTSD is still 0 after that call to taskVarAdd*/ - papTSD = 0; + papTSD = NULL; /* Initialize for this thread */ + osdThreadHooksRun((epicsThreadId)tid); + (*func)(parm); + epicsExitCallAtThreadExits (); free(papTSD); taskVarDelete(tid,(int *)(char *)&papTSD); + + AWAIT_JOIN(tid); } #ifdef ALTIVEC @@ -197,38 +253,95 @@ static void createFunction(EPICSTHREADFUNC func, void *parm) #else #define TASK_FLAGS (VX_FP_TASK) #endif -epicsThreadId -epicsThreadCreateOpt ( - const char * name, +epicsThreadId epicsThreadCreateOpt(const char * name, EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { int tid; - if(!opts) opts = &opts_default; + if (!opts) + opts = &opts_default; epicsThreadInit(); - if(opts->stackSize<100) { - errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n",name,opts->stackSize); - return(0); + if (opts->stackSize < 100) { + errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n", + name, opts->stackSize); + return 0; } - tid = taskSpawn((char *)name,getOssPriorityValue(opts->priority), + + tid = taskCreate((char *)name,getOssPriorityValue(opts->priority), TASK_FLAGS, opts->stackSize, - (FUNCPTR)createFunction,(int)funptr,(int)parm, + (FUNCPTR)createFunction, (int)funptr, (int)parm, 0,0,0,0,0,0,0,0); - if(tid==ERROR) { + if (tid == ERROR) { errlogPrintf("epicsThreadCreate %s failure %s\n", - name,strerror(errno)); - return(0); + name, strerror(errno)); + return 0; } - return((epicsThreadId)tid); + + PREPARE_JOIN(tid, opts->joinable); + taskActivate(tid); + + return (epicsThreadId)tid; } -void epicsThreadMustJoin(epicsThreadId id) { +void epicsThreadMustJoin(epicsThreadId id) +{ + const char *fn = "epicsThreadMustJoin"; #if EPICS_THREAD_CAN_JOIN - int tid = (int)id; + int tid = (int) id; + SEM_ID joinSem; + STATUS status; - if (tid) - taskWait(tid, WAIT_FOREVER); + if (!tid) + return; + + joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField); + if ((int) joinSem == ERROR) { + errlogPrintf("%s: Thread '%s' no longer exists.\n", + fn, taskName(tid)); + return; + } + + if (tid == taskIdSelf()) { + if (joinSem) { + semDelete(joinSem); + taskSpareFieldSet(tid, joinField, 0); + } + else { + errlogPrintf("%s: Self-join of unjoinable thread '%s'\n", + fn, taskName(tid)); + } + return; + } + + if (!joinSem) { + cantProceed("%s: Thread '%s' is not joinable.\n", + fn, taskName(tid)); + return; + } + + semGive(joinSem); /* Rendezvous with thread */ + + status = taskWait(tid, JOIN_WARNING_TIMEOUT); + if (status && errno == S_objLib_OBJ_TIMEOUT) { + errlogPrintf("Warning: %s still waiting for thread '%s'\n", + fn, taskName(tid)); + status = taskWait(tid, WAIT_FOREVER); + } + if (status) { + if (errno == S_taskLib_ILLEGAL_OPERATION) { + errlogPrintf("%s: This shouldn't happen!\n", fn); + } + else if (errno == S_objLib_OBJ_ID_ERROR) { + errlogPrintf("%s: %x is not a known thread\n", fn, tid); + } + else { + perror(fn); + } + cantProceed(fn); + } +#else + cantProceed("%s called when EPICS_THREAD_CAN_JOIN is 0\n", fn); #endif } From 8a072d3c043c2ba51214a7e56d550ff4c9dd95e4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 28 Jun 2019 12:40:07 -0500 Subject: [PATCH 065/281] More basic tests of epicsThreadMustJoin() --- modules/libcom/test/epicsThreadTest.cpp | 67 ++++++++++++++++++------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index edaada914..6785f32ba 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -86,46 +86,75 @@ void testMyThread() } } -struct selfJoiner { - epicsEvent finished; +struct joinStuff { + epicsThreadOpts *opts; + epicsEvent *trigger; + epicsEvent *finished; }; -void joiner(void *arg) { - epicsEvent *finished = (epicsEvent*)arg; +void donothing(void *arg) +{} + +void dowait(void *arg) +{ + epicsEvent *trigger = (epicsEvent *) arg; + trigger->wait(); + epicsThreadSleep(0.1); +} + +void joinTests(void *arg) +{ + struct joinStuff *stuff = (struct joinStuff *) arg; + + // Task finishes before parent joins + epicsThreadId tid = epicsThreadCreateOpt("nothing", + &donothing, 0, stuff->opts); + epicsThreadSleep(0.1); + epicsThreadMustJoin(tid); + + // Parent joins before task finishes + tid = epicsThreadCreateOpt("await", + &dowait, stuff->trigger, stuff->opts); + stuff->trigger->signal(); + epicsThreadMustJoin(tid); // This is a no-op - epicsThreadMustJoin(epicsThreadGetIdSelf()); + epicsThreadId self = epicsThreadGetIdSelf(); + epicsThreadMustJoin(self); // This is a no-op as well, except for a warning. eltc(0); - epicsThreadMustJoin(epicsThreadGetIdSelf()); + epicsThreadMustJoin(self); eltc(1); - testPass("Check double self-join"); - finished->signal(); + stuff->finished->signal(); } -typedef struct info { - int isOkToBlock; - int didSomething; -} info; - -void testSelfJoin() +void testJoining() { - epicsEvent finished; epicsThreadOpts opts; epicsThreadOptsDefaults(&opts); opts.priority = 50; opts.joinable = 1; - (void)epicsThreadCreateOpt("selfjoin", &joiner, &finished, &opts); + epicsEvent finished, trigger; - // as this thread "joins" itself, we can't. - finished.wait(); + struct joinStuff stuff = { + &opts, &trigger, &finished + }; + epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts); + + // as selfjoin joins itself, we can't. + testOk(finished.wait(10.0), "Join tests completed"); } } // namespace +typedef struct info { + int isOkToBlock; + int didSomething; +} info; + extern "C" { static void thread(void *arg) { @@ -174,8 +203,8 @@ MAIN(epicsThreadTest) testOk1(ncpus > 0); testDiag("main() thread %p", epicsThreadGetIdSelf()); + testJoining(); // Do this first, ~epicsThread() uses it... testMyThread(); - testSelfJoin(); testOkToBlock(); // attempt to self-join from a non-EPICS thread From 4b77d5e1c98f29a70129cf72e02145f68cf220d6 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 28 Jun 2019 13:24:29 -0500 Subject: [PATCH 066/281] Release Note updates VxWorks minimum version, and more about joinable threads. --- documentation/RELEASE_NOTES.html | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index fa9727aff..b3e266031 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -26,6 +26,13 @@ release.

--> +

VxWorks Minimum Version Requirements

+ +

The implementation of the epicsThreadMustJoin() functionality +described below requires facilities that were added to the OS in VxWorks 6.9, so +that is now the oldest version which this release of EPICS can be built +against.

+

Add epicsThreadCreateOpt() and epicsThreadMustJoin()

epicsThreadCreateOpt() is an alternative to epicsThreadCreate() which @@ -45,8 +52,16 @@ void startitup(void) {

If the new epicsThreadOpts::joinable option flag is set (not the default), -then epicsThreadMustJoin() needs to be called to free up thread resources. -This function will block until the thread main function has returned.

+then epicsThreadMustJoin() must be called with that +thread's epicsThreadId when/after the thread exits, to free up thread resources. +This function will block until the thread's main function has returned, after +which the epicsThreadId will no longer be valid.

+ +

A thread which was created with the joinable flag set may itself call +epicsThreadMustJoin() passing its own epicsThreadId. This marks the +thread as no longer being joinable, so it will then free the thread resources +itself when its main function returns. The epicsThreadId for a thread that is +not joinable gets invalidated as soon as its main function returns.

Launchpad Bugs

From fbf62189cbabdc96b9e431ed60b0557e0c6079ea Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 2 Jul 2019 17:27:27 -0500 Subject: [PATCH 067/281] Replace epicsThreadOptsDefaults() with EPICS_THREAD_OPTS_INIT The epicsThreadCreate() routines now interpose calls to epicsThreadGetStackSize() if an enum value is passed. --- modules/database/src/ioc/as/asCa.c | 4 +- modules/database/src/ioc/db/dbCa.c | 4 +- modules/database/src/ioc/db/dbEvent.c | 3 +- modules/libcom/src/osi/epicsThread.cpp | 9 ++- modules/libcom/src/osi/epicsThread.h | 15 +++-- modules/libcom/src/osi/os/RTEMS/osdThread.c | 20 +++--- modules/libcom/src/osi/os/WIN32/osdThread.c | 18 ++--- modules/libcom/src/osi/os/posix/osdThread.c | 66 +++++++++++-------- modules/libcom/src/osi/os/vxWorks/osdThread.c | 26 ++++---- modules/libcom/test/epicsThreadTest.cpp | 16 ++--- 10 files changed, 95 insertions(+), 86 deletions(-) diff --git a/modules/database/src/ioc/as/asCa.c b/modules/database/src/ioc/as/asCa.c index e8c5403d9..21bb47f5f 100644 --- a/modules/database/src/ioc/as/asCa.c +++ b/modules/database/src/ioc/as/asCa.c @@ -229,8 +229,8 @@ static void asCaTask(void) void asCaStart(void) { - epicsThreadOpts opts; - epicsThreadOptsDefaults(&opts); + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + opts.stackSize = epicsThreadGetStackSize(epicsThreadStackBig); opts.priority = epicsThreadPriorityScanLow - 3; opts.joinable = 1; diff --git a/modules/database/src/ioc/db/dbCa.c b/modules/database/src/ioc/db/dbCa.c index 935c397d4..ea0fad0d3 100644 --- a/modules/database/src/ioc/db/dbCa.c +++ b/modules/database/src/ioc/db/dbCa.c @@ -265,8 +265,8 @@ void dbCaShutdown(void) static void dbCaLinkInitImpl(int isolate) { - epicsThreadOpts opts; - epicsThreadOptsDefaults(&opts); + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + opts.stackSize = epicsThreadGetStackSize(epicsThreadStackBig); opts.priority = epicsThreadPriorityMedium; opts.joinable = 1; diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c index 48dc9012b..febe62634 100644 --- a/modules/database/src/ioc/db/dbEvent.c +++ b/modules/database/src/ioc/db/dbEvent.c @@ -1056,9 +1056,8 @@ int db_start_events ( void *init_func_arg, unsigned osiPriority ) { struct event_user * const evUser = (struct event_user *) ctx; - epicsThreadOpts opts; + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; - epicsThreadOptsDefaults(&opts); opts.stackSize = epicsThreadGetStackSize(epicsThreadStackMedium); opts.priority = osiPriority; opts.joinable = 1; diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 9a049133f..92f833847 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -35,7 +35,7 @@ epicsThreadId epicsShareAPI epicsThreadCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ) { - epicsThreadOpts opts; + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; opts.priority = priority; opts.stackSize = stackSize; opts.joinable = 0; @@ -202,11 +202,10 @@ epicsThread::epicsThread ( epicsThreadRunable & runableIn, const char * pName, unsigned stackSize, unsigned priority ) : runable ( runableIn ), id ( 0 ), pThreadDestroyed ( 0 ), - begin ( false ), cancel ( false ), terminated ( false ) - , joined(false) + begin ( false ), cancel ( false ), terminated ( false ), + joined ( false ) { - epicsThreadOpts opts; - epicsThreadOptsDefaults(&opts); + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; opts.stackSize = stackSize; opts.priority = priority; opts.joinable = 1; diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index 694ac94c7..82fa04b5b 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -84,9 +84,8 @@ epicsShareFunc void epicsShareAPI epicsThreadExitMain(void); typedef struct epicsThreadOpts { /** Thread priority in OSI range (cf. epicsThreadPriority*) */ unsigned int priority; - /** Thread stack size, as returned by epicsThreadGetStackSize(). - * - * @warning Do not pass enum epicsThreadStackSizeClass directly! + /** Thread stack size, either in bytes for this architecture or + * an enum epicsThreadStackSizeClass value. */ unsigned int stackSize; /** Should thread be joinable? (default (0) is not joinable). @@ -95,8 +94,14 @@ typedef struct epicsThreadOpts { unsigned int joinable; } epicsThreadOpts; -/** Fill in target specific default values. */ -epicsShareFunc void epicsThreadOptsDefaults(epicsThreadOpts *opts); +/** Default initial values for epicsThreadOpts + * Applications should always use this macro to initialize an epicsThreadOpts + * structure. Additional fields may be added in the future, and the order of + * the fields might also change, thus code that assumes the above definition + * might break if these rules are not followed. + */ +#define EPICS_THREAD_OPTS_INIT { \ + epicsThreadPriorityLow, epicsThreadStackMedium, 0} /** @brief Allocate and start a new OS thread. * @param name A name describing this thread. Appears in various log and error message. diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.c b/modules/libcom/src/osi/os/RTEMS/osdThread.c index fdc31759f..bdcd8c17e 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.c +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.c @@ -152,13 +152,6 @@ epicsThreadGetStackSize (epicsThreadStackSizeClass size) return stackSize; } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 5000, 0}; - -void epicsThreadOptsDefaults(epicsThreadOpts *opts) -{ - *opts = opts_default; -} - /* * Ensure integrity of task variable list */ @@ -315,15 +308,22 @@ epicsThreadCreateOpt ( const char * name, EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { + unsigned int stackSize; rtems_id tid; rtems_status_code sc; char c[4]; - unsigned stackSize; - if(!opts) opts = &opts_default; + if (!initialized) + epicsThreadInit(); + + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; + } stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); - if (!initialized) epicsThreadInit(); if (stackSize < RTEMS_MINIMUM_STACK_SIZE) { errlogPrintf ("Warning: epicsThreadCreate %s illegal stackSize %d\n", name, stackSize); diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 6d43e769f..1cfa1ec5c 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -469,13 +469,6 @@ epicsShareFunc unsigned int epicsShareAPI return stackSizeTable[stackSizeClass]; } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1), 0}; - -void epicsThreadOptsDefaults(epicsThreadOpts *opts) -{ - *opts = opts_default; -} - void epicsThreadCleanupWIN32 () { win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); @@ -599,6 +592,7 @@ epicsThreadId epicsThreadCreateOpt ( { win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); win32ThreadParam * pParmWIN32; + unsigned int stackSize; int osdPriority; DWORD wstat; BOOL bstat; @@ -607,7 +601,13 @@ epicsThreadId epicsThreadCreateOpt ( return NULL; } - if(!opts) opts = &opts_default; + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; + } + stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); pParmWIN32 = epicsThreadParmCreate ( pName ); if ( pParmWIN32 == 0 ) { @@ -620,7 +620,7 @@ epicsThreadId epicsThreadCreateOpt ( { unsigned threadId; pParmWIN32->handle = (HANDLE) _beginthreadex ( - 0, opts->stackSize, epicsWin32ThreadEntry, + 0, stackSize, epicsWin32ThreadEntry, pParmWIN32, CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION, & threadId ); diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index 5ed2cbc56..ea0d2b265 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -469,13 +469,6 @@ epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadSt return 0; #endif /*_POSIX_THREAD_ATTR_STACKSIZE*/ } - -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, STACK_SIZE(1), 0}; - -void epicsThreadOptsDefaults(epicsThreadOpts *opts) -{ - *opts = opts_default; -} epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg) { @@ -519,48 +512,65 @@ epicsShareFunc void epicsShareAPI epicsThreadOnce(epicsThreadOnceId *id, void (* } epicsThreadId -epicsThreadCreateOpt ( - const char * name, +epicsThreadCreateOpt(const char * name, EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { + unsigned int stackSize; epicsThreadOSD *pthreadInfo; int status; sigset_t blockAllSig, oldSig; - if(!opts) opts = &opts_default; - epicsThreadInit(); assert(pcommonAttr); + + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; + } + stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); + sigfillset(&blockAllSig); - pthread_sigmask(SIG_SETMASK,&blockAllSig,&oldSig); - pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm,opts->joinable); - if(pthreadInfo==0) return 0; + pthread_sigmask(SIG_SETMASK, &blockAllSig, &oldSig); + + pthreadInfo = init_threadInfo(name, opts->priority, stackSize, funptr, + parm, opts->joinable); + if (pthreadInfo==0) + return 0; + pthreadInfo->isEpicsThread = 1; - setSchedulingPolicy(pthreadInfo,SCHED_FIFO); + setSchedulingPolicy(pthreadInfo, SCHED_FIFO); pthreadInfo->isRealTimeScheduled = 1; - status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr, - start_routine,pthreadInfo); - if(status==EPERM){ + + status = pthread_create(&pthreadInfo->tid, &pthreadInfo->attr, + start_routine, pthreadInfo); + if (status==EPERM) { /* Try again without SCHED_FIFO*/ free_threadInfo(pthreadInfo); - pthreadInfo = init_threadInfo(name,opts->priority,opts->stackSize,funptr,parm,opts->joinable); - if(pthreadInfo==0) return 0; + + pthreadInfo = init_threadInfo(name, opts->priority, stackSize, + funptr, parm, opts->joinable); + if (pthreadInfo==0) + return 0; + pthreadInfo->isEpicsThread = 1; - status = pthread_create(&pthreadInfo->tid,&pthreadInfo->attr, - start_routine,pthreadInfo); + status = pthread_create(&pthreadInfo->tid, &pthreadInfo->attr, + start_routine, pthreadInfo); } - checkStatusOnce(status,"pthread_create"); - if(status) { + checkStatusOnce(status, "pthread_create"); + if (status) { free_threadInfo(pthreadInfo); return 0; } - status = pthread_sigmask(SIG_SETMASK,&oldSig,NULL); - checkStatusOnce(status,"pthread_sigmask"); - if(pthreadInfo->joinable) { + + status = pthread_sigmask(SIG_SETMASK, &oldSig, NULL); + checkStatusOnce(status, "pthread_sigmask"); + if (pthreadInfo->joinable) { /* extra ref for epicsThreadMustJoin() */ epicsAtomicIncrIntT(&pthreadInfo->refcnt); } - return(pthreadInfo); + return pthreadInfo; } /* diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 43770eab3..d5b859ade 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -150,13 +150,6 @@ unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) return stackSizeTable[stackSizeClass]; } -static const epicsThreadOpts opts_default = {epicsThreadPriorityLow, 4000*ARCH_STACK_FACTOR, 0}; - -void epicsThreadOptsDefaults(epicsThreadOpts *opts) -{ - *opts = opts_default; -} - struct epicsThreadOSD {}; /* Strictly speaking this should be a WIND_TCB, but we only need it to * be able to create an epicsThreadId that is guaranteed never to be @@ -256,20 +249,27 @@ static void createFunction(EPICSTHREADFUNC func, void *parm) epicsThreadId epicsThreadCreateOpt(const char * name, EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts ) { + unsigned int stackSize; int tid; - if (!opts) - opts = &opts_default; - epicsThreadInit(); - if (opts->stackSize < 100) { + + if (!opts) { + static const epicsThreadOpts opts_default = EPICS_THREAD_OPTS_INIT; + opts = &opts_default; + } + stackSize = opts->stackSize; + if (stackSize <= epicsThreadStackBig) + stackSize = epicsThreadGetStackSize(stackSize); + + if (stackSize < 100) { errlogPrintf("epicsThreadCreate %s illegal stackSize %d\n", - name, opts->stackSize); + name, stackSize); return 0; } tid = taskCreate((char *)name,getOssPriorityValue(opts->priority), - TASK_FLAGS, opts->stackSize, + TASK_FLAGS, stackSize, (FUNCPTR)createFunction, (int)funptr, (int)parm, 0,0,0,0,0,0,0,0); if (tid == ERROR) { diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index 6785f32ba..d07552d15 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -40,7 +40,7 @@ private: }; myThread::myThread(int arg,const char *name) : - thread(*this,name,epicsThreadGetStackSize(epicsThreadStackSmall),50+arg), + thread(*this,name,epicsThreadStackSmall,50+arg), argvalue(0) { argvalue = new int; @@ -132,16 +132,14 @@ void joinTests(void *arg) void testJoining() { - epicsThreadOpts opts; - epicsThreadOptsDefaults(&opts); - opts.priority = 50; - opts.joinable = 1; - + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; epicsEvent finished, trigger; - struct joinStuff stuff = { &opts, &trigger, &finished }; + + opts.priority = 50; + opts.joinable = 1; epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts); // as selfjoin joins itself, we can't. @@ -172,9 +170,8 @@ static void thread(void *arg) static void testOkToBlock() { + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; - epicsThreadOpts opts; - epicsThreadOptsDefaults(&opts); opts.priority = 50; opts.joinable = 1; @@ -190,7 +187,6 @@ static void testOkToBlock() epicsThreadMustJoin(threadA); testOk1(infoA.didSomething); - } From 99be9a86a0bb2a16eac334aa8e1d509e5558cb6c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 2 Jul 2019 17:31:37 -0500 Subject: [PATCH 068/281] Rework EPICS_THREAD_CAN_JOIN RTEMS osdThread.h was missing an extern "C" wrapper. --- modules/libcom/src/osi/epicsThread.h | 5 ++++- modules/libcom/src/osi/os/Linux/osdThread.h | 3 --- modules/libcom/src/osi/os/RTEMS/osdThread.h | 18 +++++++++++++----- modules/libcom/src/osi/os/WIN32/osdThread.h | 8 ++------ modules/libcom/src/osi/os/posix/osdThread.h | 8 ++------ modules/libcom/src/osi/os/vxWorks/osdThread.c | 8 +++----- modules/libcom/src/osi/os/vxWorks/osdThread.h | 13 +++++-------- 7 files changed, 29 insertions(+), 34 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.h b/modules/libcom/src/osi/epicsThread.h index 82fa04b5b..da16a0b25 100644 --- a/modules/libcom/src/osi/epicsThread.h +++ b/modules/libcom/src/osi/epicsThread.h @@ -124,7 +124,10 @@ epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( epicsShareFunc epicsThreadId epicsShareAPI epicsThreadMustCreate ( const char * name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr,void * parm ); -/** Wait for a joinable thread to exit (return from its main function */ + +/* This gets undefined in osdThread.h on VxWorks < 6.9 */ +#define EPICS_THREAD_CAN_JOIN +/** Wait for a joinable thread to exit (return from its main function) */ epicsShareFunc void epicsThreadMustJoin(epicsThreadId id); /** Block the current thread until epicsThreadResume(). */ epicsShareFunc void epicsShareAPI epicsThreadSuspendSelf(void); diff --git a/modules/libcom/src/osi/os/Linux/osdThread.h b/modules/libcom/src/osi/os/Linux/osdThread.h index 40a837e9f..bb1fdcb0a 100644 --- a/modules/libcom/src/osi/os/Linux/osdThread.h +++ b/modules/libcom/src/osi/os/Linux/osdThread.h @@ -16,9 +16,6 @@ #include "ellLib.h" #include "epicsEvent.h" -/* This target supports joining threads */ -#define EPICS_THREAD_CAN_JOIN (1) - #ifdef __cplusplus extern "C" { #endif diff --git a/modules/libcom/src/osi/os/RTEMS/osdThread.h b/modules/libcom/src/osi/os/RTEMS/osdThread.h index 84d579c0f..4eef8c01f 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdThread.h +++ b/modules/libcom/src/osi/os/RTEMS/osdThread.h @@ -3,13 +3,21 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ -/* This target supports joining threads */ -#define EPICS_THREAD_CAN_JOIN (1) +#ifndef INC_osdThread_H +#define INC_osdThread_H + +#ifdef __cplusplus +extern "C" { +#endif int epicsThreadGetOssPriorityValue(unsigned int osiPriority); +#ifdef __cplusplus +} +#endif + +#endif /* INC_osdThread_H */ diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.h b/modules/libcom/src/osi/os/WIN32/osdThread.h index fe60564d1..69bc364f0 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.h +++ b/modules/libcom/src/osi/os/WIN32/osdThread.h @@ -3,15 +3,11 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ #ifndef osdThreadh #define osdThreadh -/* This target supports joining threads */ -#define EPICS_THREAD_CAN_JOIN (1) - #endif /* osdThreadh */ diff --git a/modules/libcom/src/osi/os/posix/osdThread.h b/modules/libcom/src/osi/os/posix/osdThread.h index eee0c825d..8fe8f14eb 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.h +++ b/modules/libcom/src/osi/os/posix/osdThread.h @@ -3,9 +3,8 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ #ifndef osdThreadh #define osdThreadh @@ -16,9 +15,6 @@ #include "ellLib.h" #include "epicsEvent.h" -/* This target supports joining threads */ -#define EPICS_THREAD_CAN_JOIN (1) - #ifdef __cplusplus extern "C" { #endif diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index d5b859ade..0ed31389f 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -34,7 +34,7 @@ #include "vxLib.h" #include "epicsExit.h" -#if EPICS_THREAD_CAN_JOIN +#ifdef EPICS_THREAD_CAN_JOIN /* The implementation of epicsThreadMustJoin() here uses 2 features * of VxWorks that were first introduced in VxWorks 6.9: taskWait(), * and the taskSpareFieldGet/Set routines in taskUtilLib. @@ -188,7 +188,7 @@ void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg) semGive(epicsThreadOnceMutex); } -#if EPICS_THREAD_CAN_JOIN +#ifdef EPICS_THREAD_CAN_JOIN /* This routine is not static so it appears in the back-trace * of a thread that is waiting to be joined. @@ -286,8 +286,8 @@ epicsThreadId epicsThreadCreateOpt(const char * name, void epicsThreadMustJoin(epicsThreadId id) { +#ifdef EPICS_THREAD_CAN_JOIN const char *fn = "epicsThreadMustJoin"; -#if EPICS_THREAD_CAN_JOIN int tid = (int) id; SEM_ID joinSem; STATUS status; @@ -340,8 +340,6 @@ void epicsThreadMustJoin(epicsThreadId id) } cantProceed(fn); } -#else - cantProceed("%s called when EPICS_THREAD_CAN_JOIN is 0\n", fn); #endif } diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.h b/modules/libcom/src/osi/os/vxWorks/osdThread.h index 8fa454ce3..15145663b 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.h +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.h @@ -3,20 +3,17 @@ * National Laboratory. * Copyright (c) 2002 The Regents of the University of California, as * Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. \*************************************************************************/ + #ifndef osdThreadh #define osdThreadh /* VxWorks 6.9 and later can support joining threads */ -#if (_WRS_VXWORKS_MAJOR > 6) || \ - (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR >= 9) -# define EPICS_THREAD_CAN_JOIN (1) -#else -# define EPICS_THREAD_CAN_JOIN (0) +#if (_WRS_VXWORKS_MAJOR == 6 && _WRS_VXWORKS_MINOR < 9) +#undef EPICS_THREAD_CAN_JOIN #endif #endif /* osdThreadh */ From e5782ae716ea60f721ed0545d60412dcb68db5e5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 2 Jul 2019 17:38:16 -0500 Subject: [PATCH 069/281] Update release notes again, more detail --- documentation/RELEASE_NOTES.html | 95 +++++++++++++++++++++++--------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index b3e266031..203b7a873 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -26,42 +26,87 @@ release.

--> -

VxWorks Minimum Version Requirements

+

VxWorks Minimum Version Recommendation

-

The implementation of the epicsThreadMustJoin() functionality -described below requires facilities that were added to the OS in VxWorks 6.9, so -that is now the oldest version which this release of EPICS can be built -against.

+

The implementation of the epicsThreadMustJoin() feature +described below uses facilities that were added to VxWorks in version 6.9. When +built against an older version of VxWorks the join functionality will not be +available and calls to epicsThreadMustJoin() will return +immediately. In this case the epicsThread.h header will not define the C macro +EPICS_THREAD_CAN_JOIN to allow alternate code to be provided for +these targets. The IOC's use of the join feature has been designed to work for +either situation.

-

Add epicsThreadCreateOpt() and epicsThreadMustJoin()

-

epicsThreadCreateOpt() is an alternative to epicsThreadCreate() which -passes some arguments via a structure (struct epicsThreadOpts). -This epicsThreadOpts* may be NULL to use target specific -defaults. Caller wishing to provide thread options should first call -epicsThreadOptsDefaults() to fill in the defaults.

+

New and modified epicsThread APIs

+ +

epicsThreadCreateOpt()

+ +

A new routine epicsThreadCreateOpt() is an alternative to +epicsThreadCreate() which takes some arguments via a structure +(struct epicsThreadOpts) to allow for future extensions.

+ +
+typedef struct epicsThreadOpts {
+    unsigned int priority;
+    unsigned int stackSize;
+    unsigned int joinable;
+} epicsThreadOpts;
+#define EPICS_THREAD_OPTS_INIT { \
+    epicsThreadPriorityLow, epicsThreadStackMedium, 0}
+
+epicsThreadId epicsThreadCreateOpt(const char * name,
+    EPICSTHREADFUNC funptr, void * parm, const epicsThreadOpts *opts);
+
+ +

The final opts parameter may be NULL to use the +default values of thread priority (low) and stack size (medium). Callers wishing +to provide alternative settings for these thread options or to create a joinable +thread (see below) should create and pass in an epicsThreadOpts +structure as shown below. Always initialize one of these structures using the +EPICS_THREAD_OPTS_INIT macro to ensure that any additional fields +that get added in the future are set to their default values.

 void startitup(void) {
-    epicsThreadOpts opts;
-    epicsThreadOptsDefaults(&opts);
-    opts.priority = epicsThreadPriorityMedium;
+    epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
+    epicsThreadId tid;
 
-    ... = epicsThreadCreateOpt("my thread", &threadMain, NULL, &opts);
+    opts.priority = epicsThreadPriorityMedium;
+    tid = epicsThreadCreateOpt("my thread", &threadMain, NULL, &opts);
 }
 
-

If the new epicsThreadOpts::joinable option flag is set (not the default), -then epicsThreadMustJoin() must be called with that -thread's epicsThreadId when/after the thread exits, to free up thread resources. -This function will block until the thread's main function has returned, after -which the epicsThreadId will no longer be valid.

+

C or C++ Code that also needs to build on earlier versions of Base can use +#ifdef EPICS_THREAD_OPTS_INIT to determine whether the +epicsThreadCreateOpt() API is available on this Base version.

+ +

Thread stack sizes

+ +

The stackSize member of the epicsThreadOpts +structure and the equivalent parameters to the epicsThreadCreate() +and epicsThreadMustCreate() routines can now be passed either one +of the epicsThreadStackSizeClass enum values or a value returned +from the epicsThreadGetStackSize() routine.

+ +

epicsThreadMustJoin()

+ +

If the new joinable flag of an epicsThreadOpts +structure is non-zero (the default value is zero), the new API routine +epicsThreadMustJoin() must be called with the thread's +epicsThreadId when/after the thread exits, to free up thread +resources. This function will block until the thread's main function has +returned, allowing the parent to wait for its child thread. The child's +epicsThreadId will no longer be valid and should not be used after +the epicsThreadMustJoin() routine returns.

+ +

A thread that was originally created with its joinable flag set may itself +call epicsThreadMustJoin(), passing in its own epicsThreadId. This +marks the thread as no longer being joinable, so it will then free the thread +resources itself when its main function returns. The epicsThreadId +of a thread that is not joinable gets invalidated as soon as its main function +returns.

-

A thread which was created with the joinable flag set may itself call -epicsThreadMustJoin() passing its own epicsThreadId. This marks the -thread as no longer being joinable, so it will then free the thread resources -itself when its main function returns. The epicsThreadId for a thread that is -not joinable gets invalidated as soon as its main function returns.

Launchpad Bugs

From b4ee452c4d39424f9b5a8910d85776eb979e4211 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 2 Jul 2019 18:17:47 -0500 Subject: [PATCH 070/281] Test that a join actually delays the parent --- modules/libcom/test/epicsThreadTest.cpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index d07552d15..4796438a1 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -102,6 +102,11 @@ void dowait(void *arg) epicsThreadSleep(0.1); } +void dodelay(void *arg) +{ + epicsThreadSleep(2.0); +} + void joinTests(void *arg) { struct joinStuff *stuff = (struct joinStuff *) arg; @@ -118,6 +123,20 @@ void joinTests(void *arg) stuff->trigger->signal(); epicsThreadMustJoin(tid); + // Parent gets delayed until task finishes + epicsTime start, end; + start = epicsTime::getCurrent(); + tid = epicsThreadCreateOpt("delay", + &dodelay, 0, stuff->opts); + epicsThreadMustJoin(tid); + end = epicsTime::getCurrent(); + double duration = end - start; +#ifndef EPICS_THREAD_CAN_JOIN + testTodoBegin("Thread join doesn't work"); +#endif + testOk(duration > 1.0, "Join delayed parent (%g seconds)", duration); + testTodoEnd(); + // This is a no-op epicsThreadId self = epicsThreadGetIdSelf(); epicsThreadMustJoin(self); @@ -192,7 +211,7 @@ static void testOkToBlock() MAIN(epicsThreadTest) { - testPlan(12); + testPlan(13); unsigned int ncpus = epicsThreadGetCPUs(); testDiag("System has %u CPUs", ncpus); From 44ea66aaaf83c09a5991f52a13d1c436e61ce937 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Jul 2019 23:11:21 -0500 Subject: [PATCH 071/281] Add checks and summary of free-list size to decTest.c --- src/std/filters/test/decTest.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/std/filters/test/decTest.c b/src/std/filters/test/decTest.c index b6b2276c6..19aedc6dd 100644 --- a/src/std/filters/test/decTest.c +++ b/src/std/filters/test/decTest.c @@ -72,8 +72,7 @@ static void mustDrop(dbChannel *pch, db_field_log *pfl, char* m) { testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", oldFree, newFree); - if (newFree == oldFree) - db_delete_field_log(pfl); + db_delete_field_log(pfl2); } static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { @@ -85,8 +84,7 @@ static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { testOk(newFree == oldFree, "field_log was not freed - %d => %d", oldFree, newFree); - if (newFree == oldFree) - db_delete_field_log(pfl); + db_delete_field_log(pfl2); } static void checkAndOpenChannel(dbChannel *pch, const chFilterPlugin *plug) { @@ -125,10 +123,10 @@ MAIN(decTest) const chFilterPlugin *plug; char myname[] = "dec"; db_field_log *pfl[10]; - int i; + int i, logsFree, logsFinal; dbEventCtx evtctx; - testPlan(103); + testPlan(104); testdbPrepare(); @@ -164,6 +162,11 @@ MAIN(decTest) testOk(!!(pch = dbChannelCreate("x.VAL{\"dec\":{\"n\":1}}")), "dbChannel with plugin dec (n=1) created"); + /* Start the free-list */ + db_delete_field_log(db_create_read_log(pch)); + logsFree = db_available_logs(); + testDiag("%d field_logs on free-list", logsFree); + checkAndOpenChannel(pch, plug); for (i = 0; i < 5; i++) { @@ -181,6 +184,8 @@ MAIN(decTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Decimation (N=2) */ testHead("Decimation (n=2)"); @@ -209,6 +214,8 @@ MAIN(decTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Decimation (N=3) */ testHead("Decimation (n=3)"); @@ -237,6 +244,8 @@ MAIN(decTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Decimation (N=4) */ testHead("Decimation (n=4)"); @@ -265,6 +274,9 @@ MAIN(decTest) dbChannelDelete(pch); + logsFinal = db_available_logs(); + testOk(logsFree == logsFinal, "%d field_logs on free-list", logsFinal); + db_close_events(evtctx); testIocShutdownOk(); From 8ff6ce4821a98c7d0ca22ddbb3155479a535118b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Jul 2019 23:30:07 -0500 Subject: [PATCH 072/281] Fix leak in sync filter (while, unless modes) Always release field logs when we drop them. Adjust how first and after modes work to make them easier to test. Change stream checking code, fix leaks and double frees. Add mustStash(), mustSwap(), streamReset(), drop mustPassOld(). Modify test code to check free-list count and release all of the field-logs returned by the filter; it must release any of the field-logs that it decides to drop. --- src/std/filters/sync.c | 24 ++-- src/std/filters/test/syncTest.c | 189 +++++++++++++++++++++----------- 2 files changed, 144 insertions(+), 69 deletions(-) diff --git a/src/std/filters/sync.c b/src/std/filters/sync.c index c32e9afbd..6b841eab4 100644 --- a/src/std/filters/sync.c +++ b/src/std/filters/sync.c @@ -109,7 +109,9 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { passfl = pfl; pfl = NULL; } - break; + else + db_delete_field_log(pfl); + goto save_state; case syncModeLast: if (!actstate && my->laststate) { passfl = my->lastfl; @@ -121,28 +123,34 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { passfl = pfl; pfl = NULL; } - break; + else + db_delete_field_log(pfl); + goto save_state; case syncModeWhile: - if (actstate) { + if (actstate) passfl = pfl; - } + else + db_delete_field_log(pfl); goto no_shift; case syncModeUnless: - if (!actstate) { + if (!actstate) passfl = pfl; - } + else + db_delete_field_log(pfl); goto no_shift; } if (my->lastfl) db_delete_field_log(my->lastfl); my->lastfl = pfl; - my->laststate = actstate; /* since no copy is made we can't keep a reference to the returned fl */ assert(my->lastfl != passfl); - no_shift: +save_state: + my->laststate = actstate; + +no_shift: return passfl; } diff --git a/src/std/filters/test/syncTest.c b/src/std/filters/test/syncTest.c index 9af44afd7..47d6e268b 100644 --- a/src/std/filters/test/syncTest.c +++ b/src/std/filters/test/syncTest.c @@ -66,31 +66,92 @@ static void testHead (char* title) { testDiag("--------------------------------------------------------"); } -static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m) { - db_field_log *pfl = dbChannelRunPreChain(pch, pfl2); - testOk(NULL == pfl, "filter drops field_log (%s)", m); +/* + * Use mustDrop() and mustPass() to test filters with no memory + * of previous field_log pointers. + */ +static void mustDrop(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(NULL == pfl2, "filter drops field_log (%s)", m); + testOk(newFree == oldFree + 1, "a field_log was freed - %d+1 => %d", + oldFree, newFree); + + db_delete_field_log(pfl2); } -static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m) { - db_field_log *pfl; +static void mustPass(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(pfl == pfl2, "filter passes field_log (%s)", m); + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); + + db_delete_field_log(pfl2); +} + +/* + * Use mustStash() and mustSwap() to test filters that save + * field_log pointers and return them later. + * + * mustStash() expects the filter to save the current pointer + * (freeing any previously saved pointer) and return NULL. + * mustSwap() expects the filter to return the previously + * saved pointer and save the current pointer. + */ +static db_field_log *stashed; + +static void streamReset(void) { + stashed = NULL; +} + +static void mustStash(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(NULL == pfl2, "filter stashes field_log (%s)", m); + if (stashed) { + testOk(newFree == oldFree + 1, "a field_log was freed - %d+1 => %d", + oldFree, newFree); + } + else { + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); + } + stashed = pfl; + db_delete_field_log(pfl2); +} + +static void mustSwap(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(); + db_field_log *pfl2 = dbChannelRunPreChain(pch, pfl); + int newFree = db_available_logs(); + + testOk(stashed == pfl2, "filter returns stashed field log (%s)", m); + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); + + stashed = pfl; + db_delete_field_log(pfl2); +} + +static void mustPassTwice(dbChannel *pch, db_field_log *pfl, char* m) { + int oldFree = db_available_logs(), newFree; + db_field_log *pfl2; testDiag("%s: filter must pass twice", m); - pfl = dbChannelRunPreChain(pch, pfl2); + pfl2 = dbChannelRunPreChain(pch, pfl); testOk(pfl2 == pfl, "call 1 does not drop or replace field_log"); - pfl = dbChannelRunPreChain(pch, pfl2); + pfl2 = dbChannelRunPreChain(pch, pfl); testOk(pfl2 == pfl, "call 2 does not drop or replace field_log"); -} - -static void mustPassOld(dbChannel *pch, db_field_log *old, db_field_log *cur, char* m) { - db_field_log *pfl = dbChannelRunPreChain(pch, cur); - - testOk(old == pfl, "filter passes previous field log (%s)", m); -} - -static void mustPass(dbChannel *pch, db_field_log *cur, char* m) { - db_field_log *pfl = dbChannelRunPreChain(pch, cur); - - testOk(cur == pfl, "filter passes field_log (%s)", m); + newFree = db_available_logs(); + testOk(newFree == oldFree, "no field_logs were freed - %d => %d", + oldFree, newFree); } static void checkCtxRead(dbChannel *pch, dbStateId id) { @@ -138,10 +199,10 @@ MAIN(syncTest) const chFilterPlugin *plug; char myname[] = "sync"; db_field_log *pfl[10]; - int i; + int i, logsFree, logsFinal; dbEventCtx evtctx; - testPlan(139); + testPlan(214); testdbPrepare(); @@ -176,9 +237,14 @@ MAIN(syncTest) testOk(!!(pch = dbChannelCreate("x.VAL{\"sync\":{\"m\":\"while\",\"s\":\"red\"}}")), "dbChannel with plugin sync (m='while' s='red') created"); + /* Start the free-list */ + db_delete_field_log(db_create_read_log(pch)); + logsFree = db_available_logs(); + testDiag("%d field_logs on free-list", logsFree); + checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } @@ -198,11 +264,10 @@ MAIN(syncTest) mustDrop(pch, pfl[7], "state=FALSE, log7"); mustDrop(pch, pfl[8], "state=FALSE, log8"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode UNLESS */ testHead("Mode UNLESS (m='unless', s='red')"); @@ -211,7 +276,7 @@ MAIN(syncTest) checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } @@ -231,11 +296,10 @@ MAIN(syncTest) mustPass(pch, pfl[7], "state=FALSE, log7"); mustPass(pch, pfl[8], "state=FALSE, log8"); - for (i = 0; i < 10; i++) - db_delete_field_log(pfl[i]); - dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode BEFORE */ testHead("Mode BEFORE (m='before', s='red')"); @@ -251,24 +315,25 @@ MAIN(syncTest) testDiag("Test event stream"); + streamReset(); dbStateClear(red); - mustDrop(pch, pfl[0], "state=FALSE, log0"); - mustDrop(pch, pfl[1], "state=FALSE, log1"); - mustDrop(pch, pfl[2], "state=FALSE, log2"); + mustStash(pch, pfl[0], "state=FALSE, log0"); + mustStash(pch, pfl[1], "state=FALSE, log1"); + mustStash(pch, pfl[2], "state=FALSE, log2"); dbStateSet(red); - mustPassOld(pch, pfl[2], pfl[3], "state=TRUE, log3, pass=log2"); - mustDrop(pch, pfl[4], "state=TRUE, log4"); - mustDrop(pch, pfl[5], "state=TRUE, log5"); - mustDrop(pch, pfl[6], "state=TRUE, log6"); + mustSwap(pch, pfl[3], "state=TRUE, log3"); + mustStash(pch, pfl[4], "state=TRUE, log4"); + mustStash(pch, pfl[5], "state=TRUE, log5"); + mustStash(pch, pfl[6], "state=TRUE, log6"); dbStateClear(red); - mustDrop(pch, pfl[7], "state=FALSE, log7"); - mustDrop(pch, pfl[8], "state=FALSE, log8"); - mustDrop(pch, pfl[9], "state=FALSE, log9"); - - db_delete_field_log(pfl[2]); + mustStash(pch, pfl[7], "state=FALSE, log7"); + mustStash(pch, pfl[8], "state=FALSE, log8"); + mustStash(pch, pfl[9], "state=FALSE, log9"); dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode FIRST */ testHead("Mode FIRST (m='first', s='red')"); @@ -277,13 +342,14 @@ MAIN(syncTest) checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } testDiag("Test event stream"); + streamReset(); dbStateClear(red); mustDrop(pch, pfl[0], "state=FALSE, log0"); mustDrop(pch, pfl[1], "state=FALSE, log1"); @@ -297,11 +363,10 @@ MAIN(syncTest) mustDrop(pch, pfl[7], "state=FALSE, log7"); mustDrop(pch, pfl[8], "state=FALSE, log8"); - db_delete_field_log(pfl[3]); - db_delete_field_log(pfl[9]); - dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode LAST */ testHead("Mode LAST (m='last', s='red')"); @@ -317,24 +382,25 @@ MAIN(syncTest) testDiag("Test event stream"); + streamReset(); dbStateClear(red); - mustDrop(pch, pfl[0], "state=FALSE, log0"); - mustDrop(pch, pfl[1], "state=FALSE, log1"); - mustDrop(pch, pfl[2], "state=FALSE, log2"); + mustStash(pch, pfl[0], "state=FALSE, log0"); + mustStash(pch, pfl[1], "state=FALSE, log1"); + mustStash(pch, pfl[2], "state=FALSE, log2"); dbStateSet(red); - mustDrop(pch, pfl[3], "state=TRUE, log3"); - mustDrop(pch, pfl[4], "state=TRUE, log4"); - mustDrop(pch, pfl[5], "state=TRUE, log5"); + mustStash(pch, pfl[3], "state=TRUE, log3"); + mustStash(pch, pfl[4], "state=TRUE, log4"); + mustStash(pch, pfl[5], "state=TRUE, log5"); dbStateClear(red); - mustPassOld(pch, pfl[5], pfl[6], "state=TRUE, log6, pass=log5"); - mustDrop(pch, pfl[7], "state=FALSE, log7"); - mustDrop(pch, pfl[8], "state=FALSE, log8"); - mustDrop(pch, pfl[9], "state=FALSE, log9"); - - db_delete_field_log(pfl[5]); + mustSwap(pch, pfl[6], "state=TRUE, log6"); + mustStash(pch, pfl[7], "state=FALSE, log7"); + mustStash(pch, pfl[8], "state=FALSE, log8"); + mustStash(pch, pfl[9], "state=FALSE, log9"); dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* mode AFTER */ testHead("Mode AFTER (m='after', s='red')"); @@ -343,13 +409,14 @@ MAIN(syncTest) checkAndOpenChannel(pch, plug); - for (i = 0; i < 10; i++) { + for (i = 0; i < 9; i++) { pfl[i] = db_create_read_log(pch); fl_setup(pch, pfl[i], 120 + i); } testDiag("Test event stream"); + streamReset(); dbStateClear(red); mustDrop(pch, pfl[0], "state=FALSE, log0"); mustDrop(pch, pfl[1], "state=FALSE, log1"); @@ -363,11 +430,11 @@ MAIN(syncTest) mustDrop(pch, pfl[7], "state=FALSE, log7"); mustDrop(pch, pfl[8], "state=FALSE, log8"); - db_delete_field_log(pfl[6]); - db_delete_field_log(pfl[9]); - dbChannelDelete(pch); + logsFinal = db_available_logs(); + testOk(logsFree == logsFinal, "%d field_logs on free-list", logsFinal); + db_close_events(evtctx); testIocShutdownOk(); From cac3e2dc3bb22b9892729a0eb224f9222daf4544 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 7 Jul 2019 23:32:12 -0500 Subject: [PATCH 073/281] Add checks of freelist to dbndTest.c --- src/std/filters/test/dbndTest.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/std/filters/test/dbndTest.c b/src/std/filters/test/dbndTest.c index b35b9a6cc..dc0c3e20e 100644 --- a/src/std/filters/test/dbndTest.c +++ b/src/std/filters/test/dbndTest.c @@ -62,6 +62,7 @@ static void changeValue(db_field_log *pfl2, long val) { } static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) { + int oldFree = db_available_logs(), newFree; db_field_log *pfl; changeValue(pfl2, val); @@ -71,18 +72,26 @@ static void mustPassOnce(dbChannel *pch, db_field_log *pfl2, char* m, double d, testOk(fl_equal(pfl, pfl2), "call 1 does not change field_log data"); pfl = dbChannelRunPreChain(pch, pfl2); testOk(NULL == pfl, "call 2 drops field_log"); + newFree = db_available_logs(); + testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", + oldFree, newFree); } static void mustDrop(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) { + int oldFree = db_available_logs(), newFree; db_field_log *pfl; changeValue(pfl2, val); testDiag("mode=%s delta=%g filter must drop", m, d); pfl = dbChannelRunPreChain(pch, pfl2); testOk(NULL == pfl, "call 1 drops field_log"); + newFree = db_available_logs(); + testOk(newFree == oldFree + 1, "field_log was freed - %d+1 => %d", + oldFree, newFree); } static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, long val) { + int oldFree = db_available_logs(), newFree; db_field_log *pfl; changeValue(pfl2, val); @@ -93,6 +102,9 @@ static void mustPassTwice(dbChannel *pch, db_field_log *pfl2, char* m, double d, pfl = dbChannelRunPreChain(pch, pfl2); testOk(pfl2 == pfl, "call 2 does not drop or replace field_log"); testOk(fl_equal(pfl, pfl2), "call 2 does not change field_log data"); + newFree = db_available_logs(); + testOk(newFree == oldFree, "field_log was not freed - %d => %d", + oldFree, newFree); } static void testHead (char* title) { @@ -113,8 +125,9 @@ MAIN(dbndTest) db_field_log *pfl2; db_field_log fl1; dbEventCtx evtctx; + int logsFree, logsFinal; - testPlan(59); + testPlan(77); testdbPrepare(); @@ -135,6 +148,11 @@ MAIN(dbndTest) testOk(!!(pch = dbChannelCreate("x.VAL{\"dbnd\":{}}")), "dbChannel with plugin dbnd (delta=0) created"); testOk((ellCount(&pch->filters) == 1), "channel has one plugin"); + /* Start the free-list */ + db_delete_field_log(db_create_read_log(pch)); + logsFree = db_available_logs(); + testDiag("%d field_logs on free-list", logsFree); + memset(&fl, PATTERN, sizeof(fl)); fl1 = fl; node = ellFirst(&pch->filters); @@ -176,6 +194,8 @@ MAIN(dbndTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Delta = -1: pass any update */ testHead("Delta = -1: pass any update"); @@ -192,6 +212,8 @@ MAIN(dbndTest) db_delete_field_log(pfl2); dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Delta = absolute */ testHead("Delta = absolute"); @@ -224,6 +246,8 @@ MAIN(dbndTest) dbChannelDelete(pch); + testDiag("%d field_logs on free-list", db_available_logs()); + /* Delta = relative */ testHead("Delta = relative"); @@ -275,6 +299,9 @@ MAIN(dbndTest) dbChannelDelete(pch); + logsFinal = db_available_logs(); + testOk(logsFree == logsFinal, "%d field_logs on free-list", logsFinal); + db_close_events(evtctx); testIocShutdownOk(); From 84c86e67e817e17024cc9fff151a8bfbd61cc89e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Jul 2019 12:55:21 -0500 Subject: [PATCH 074/281] Fix valgrind warnings in filter tests --- src/std/filters/test/dbndTest.c | 2 ++ src/std/filters/test/decTest.c | 2 ++ src/std/filters/test/syncTest.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/std/filters/test/dbndTest.c b/src/std/filters/test/dbndTest.c index dc0c3e20e..4d70f83ad 100644 --- a/src/std/filters/test/dbndTest.c +++ b/src/std/filters/test/dbndTest.c @@ -39,12 +39,14 @@ static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { static void fl_setup(dbChannel *chan, db_field_log *pfl) { struct dbCommon *prec = dbChannelRecord(chan); + memset(pfl, 0, sizeof(db_field_log)); pfl->ctx = dbfl_context_read; pfl->type = dbfl_type_val; pfl->stat = prec->stat; pfl->sevr = prec->sevr; pfl->time = prec->time; pfl->field_type = dbChannelFieldType(chan); + pfl->field_size = dbChannelFieldSize(chan); pfl->no_elements = dbChannelElements(chan); /* * use memcpy to avoid a bus error on diff --git a/src/std/filters/test/decTest.c b/src/std/filters/test/decTest.c index 19aedc6dd..3b6784248 100644 --- a/src/std/filters/test/decTest.c +++ b/src/std/filters/test/decTest.c @@ -39,12 +39,14 @@ static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) { struct dbCommon *prec = dbChannelRecord(chan); + memset(pfl, 0, sizeof(db_field_log)); pfl->ctx = dbfl_context_event; pfl->type = dbfl_type_val; pfl->stat = prec->stat; pfl->sevr = prec->sevr; pfl->time = prec->time; pfl->field_type = DBF_LONG; + pfl->field_size = sizeof(epicsInt32); pfl->no_elements = 1; /* * use memcpy to avoid a bus error on diff --git a/src/std/filters/test/syncTest.c b/src/std/filters/test/syncTest.c index 47d6e268b..9be23b05d 100644 --- a/src/std/filters/test/syncTest.c +++ b/src/std/filters/test/syncTest.c @@ -42,12 +42,14 @@ static int fl_equal(const db_field_log *pfl1, const db_field_log *pfl2) { static void fl_setup(dbChannel *chan, db_field_log *pfl, long val) { struct dbCommon *prec = dbChannelRecord(chan); + memset(pfl, 0, sizeof(db_field_log)); pfl->ctx = dbfl_context_event; pfl->type = dbfl_type_val; pfl->stat = prec->stat; pfl->sevr = prec->sevr; pfl->time = prec->time; pfl->field_type = DBF_LONG; + pfl->field_size = sizeof(epicsInt32); pfl->no_elements = 1; /* * use memcpy to avoid a bus error on From 1a94376c19fda2073a0e8c2ce3ea34cf58367f2c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 9 Jul 2019 18:42:19 -0700 Subject: [PATCH 075/281] restore ModuleDirs in caPerlApp --- modules/ca/src/template/top/caPerlApp/caget.pl | 3 ++- modules/ca/src/template/top/caPerlApp/cainfo.pl | 3 ++- modules/ca/src/template/top/caPerlApp/camonitor.pl | 3 ++- modules/ca/src/template/top/caPerlApp/caput.pl | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/ca/src/template/top/caPerlApp/caget.pl b/modules/ca/src/template/top/caPerlApp/caget.pl index d206d8a36..0d9af37a1 100644 --- a/modules/ca/src/template/top/caPerlApp/caget.pl +++ b/modules/ca/src/template/top/caPerlApp/caget.pl @@ -4,8 +4,9 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl"); +use lib ($Bin, "$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; +no lib $Bin; use Getopt::Std; use Scalar::Util qw(looks_like_number); diff --git a/modules/ca/src/template/top/caPerlApp/cainfo.pl b/modules/ca/src/template/top/caPerlApp/cainfo.pl index 4d4a1ffbe..3e38e8baf 100644 --- a/modules/ca/src/template/top/caPerlApp/cainfo.pl +++ b/modules/ca/src/template/top/caPerlApp/cainfo.pl @@ -4,8 +4,9 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl"); +use lib ($Bin, "$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; +no lib $Bin; use Getopt::Std; use CA; diff --git a/modules/ca/src/template/top/caPerlApp/camonitor.pl b/modules/ca/src/template/top/caPerlApp/camonitor.pl index c426fa536..564688d68 100644 --- a/modules/ca/src/template/top/caPerlApp/camonitor.pl +++ b/modules/ca/src/template/top/caPerlApp/camonitor.pl @@ -4,8 +4,9 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl"); +use lib ($Bin, "$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; +no lib $Bin; use Getopt::Std; use Scalar::Util qw(looks_like_number); diff --git a/modules/ca/src/template/top/caPerlApp/caput.pl b/modules/ca/src/template/top/caPerlApp/caput.pl index 03842d397..64ff9cbda 100644 --- a/modules/ca/src/template/top/caPerlApp/caput.pl +++ b/modules/ca/src/template/top/caPerlApp/caput.pl @@ -4,8 +4,9 @@ use strict; # This construct sets @INC to search lib/perl of all RELEASE entries use FindBin qw($Bin); -use lib ("$Bin/../../lib/perl"); +use lib ($Bin, "$Bin/../../lib/perl"); use _APPNAME_ModuleDirs; +no lib $Bin; use Getopt::Std; use CA; From 29fc49199d3c42e1df9fc2ba0ba7bf40635f19e0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 31 Jul 2019 14:29:18 -0500 Subject: [PATCH 076/281] Update versions after tag, set DEVELOPMENT_FLAG/DEV_SNAPSHOT --- configure/CONFIG_BASE_VERSION | 10 +++++----- modules/ca/configure/CONFIG_CA_VERSION | 12 ++++++++++-- modules/database/configure/CONFIG_DATABASE_VERSION | 12 ++++++++++-- modules/libcom/configure/CONFIG_LIBCOM_VERSION | 12 ++++++++++-- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 53753d7e4..4e61e48cd 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -52,12 +52,12 @@ EPICS_MODIFICATION = 3 # 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 -# Between official releases, the EPICS_PATCH_LEVEL gets incremented -# and a -DEV suffix is added (similar to the Maven -SNAPSHOT versions) -EPICS_DEV_SNAPSHOT= -#EPICS_DEV_SNAPSHOT=-DEV +# 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 #EPICS_DEV_SNAPSHOT=-pre1 #EPICS_DEV_SNAPSHOT=-pre1-DEV #EPICS_DEV_SNAPSHOT=-pre2 diff --git a/modules/ca/configure/CONFIG_CA_VERSION b/modules/ca/configure/CONFIG_CA_VERSION index 8a6649666..cac0fcbfe 100644 --- a/modules/ca/configure/CONFIG_CA_VERSION +++ b/modules/ca/configure/CONFIG_CA_VERSION @@ -1,4 +1,12 @@ +# Version number for the Channel Access API and shared library + EPICS_CA_MAJOR_VERSION = 4 EPICS_CA_MINOR_VERSION = 13 -EPICS_CA_MAINTENANCE_VERSION = 4 -EPICS_CA_DEVELOPMENT_FLAG = 0 +EPICS_CA_MAINTENANCE_VERSION = 5 + +# Development flag, must be zero for official release versions + +EPICS_CA_DEVELOPMENT_FLAG = 1 + +# Immediately after an official release the MAINTENANCE_VERSION +# will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/modules/database/configure/CONFIG_DATABASE_VERSION b/modules/database/configure/CONFIG_DATABASE_VERSION index ad8d54ab5..a43738cfb 100644 --- a/modules/database/configure/CONFIG_DATABASE_VERSION +++ b/modules/database/configure/CONFIG_DATABASE_VERSION @@ -1,4 +1,12 @@ +# Version number for the database APIs and shared library + EPICS_DATABASE_MAJOR_VERSION = 3 EPICS_DATABASE_MINOR_VERSION = 17 -EPICS_DATABASE_MAINTENANCE_VERSION = 4 -EPICS_DATABASE_DEVELOPMENT_FLAG = 0 +EPICS_DATABASE_MAINTENANCE_VERSION = 5 + +# Development flag, must be zero for official release versions + +EPICS_DATABASE_DEVELOPMENT_FLAG = 1 + +# Immediately after an official release the MAINTENANCE_VERSION +# will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/modules/libcom/configure/CONFIG_LIBCOM_VERSION b/modules/libcom/configure/CONFIG_LIBCOM_VERSION index f5d91037c..92c374f88 100644 --- a/modules/libcom/configure/CONFIG_LIBCOM_VERSION +++ b/modules/libcom/configure/CONFIG_LIBCOM_VERSION @@ -1,4 +1,12 @@ +# Version number for the libcom APIs and shared library + EPICS_LIBCOM_MAJOR_VERSION = 3 EPICS_LIBCOM_MINOR_VERSION = 17 -EPICS_LIBCOM_MAINTENANCE_VERSION = 5 -EPICS_LIBCOM_DEVELOPMENT_FLAG = 0 +EPICS_LIBCOM_MAINTENANCE_VERSION = 6 + +# Development flag, must be zero for official release versions + +EPICS_LIBCOM_DEVELOPMENT_FLAG = 1 + +# Immediately after an official release the MAINTENANCE_VERSION +# will be incremented and the DEVELOPMENT_FLAG set to 1 From 969ffa3598ff36738328afec78882f6e751377ee Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 31 Jul 2019 14:34:42 -0500 Subject: [PATCH 077/281] Checklist: Update version update instructions --- documentation/ReleaseChecklist.html | 52 +++++++++++++++++------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index 81784e8cc..a29552dc2 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -289,13 +289,20 @@ starting at Release Approval.

Release Manager Edit and commit changes to the EPICS Base version number file and - the embedded module version files: + these embedded module version files:
  • configure/CONFIG_BASE_VERSION
  • modules/libcom/configure/CONFIG_LIBCOM_VERSION
  • modules/ca/configure/CONFIG_CA_VERSION
  • modules/database/configure/CONFIG_DATABASE_VERSION
  • -
+ +

Version numbers should be set according to the level of changes + made since the last release. Note that the MAINTENANCE_VERSION or + PATCH_LEVEL value should have been incremented after the previous + release tag was applied.

+

Set all DEVELOPMENT_FLAG values to 0 and EPICS_DEV_SNAPSHOT to the + empty string.

+ @@ -305,7 +312,26 @@ starting at Release Approval.

cd base-7.0
git tag -m 'ANJ: Tagged for 7.0.3' R7.0.3 - Don't push the new tag to the Launchpad repository yet. +

Don't push these commits or the new tag to the Launchpad repository + yet. + + + + Release Manager + Edit and commit changes to the EPICS Base version number file and + the embedded module version files as follows: +

    +
  • configure/CONFIG_BASE_VERSION
  • +
  • modules/libcom/configure/CONFIG_LIBCOM_VERSION
  • +
  • modules/ca/configure/CONFIG_CA_VERSION
  • +
  • modules/database/configure/CONFIG_DATABASE_VERSION
  • +
+

Version numbers should be set for the next expected patch/maintenance + release by incrementing the MAINTENANCE_VERSION or PATCH_LEVEL + value in each file.

+

Set all DEVELOPMENT_FLAG values to 1 and EPICS_DEV_SNAPSHOT to + "-DEV".

+ @@ -327,29 +353,13 @@ starting at Release Approval.

Release Manager Test the tar file by extracting its contents and building it on at - least one supported platform. When this succeeds the new git tag can be - pushed to the Launchpad repository: + least one supported platform. When this succeeds the commits and new git + tag can be pushed to the Launchpad repository:
git push --follow-tags upstream 7.0
- - - Release Manager - Edit and commit changes to the EPICS Base version number file and - the embedded module version files: -
    -
  • configure/CONFIG_BASE_VERSION
  • -
  • modules/libcom/configure/CONFIG_LIBCOM_VERSION
  • -
  • modules/ca/configure/CONFIG_CA_VERSION
  • -
  • modules/database/configure/CONFIG_DATABASE_VERSION
  • -
- Version numbers should be set to the next expected patch release, - with a "-DEV" tag added (where applicable). - - - Publish to epics.anl.gov From e0039d4e86431a682209e19e410f164441ebb225 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 1 Aug 2019 16:20:53 -0500 Subject: [PATCH 078/281] Expand epics-controls publication instructions --- documentation/ReleaseChecklist.html | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index a29552dc2..7c58a61d2 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -408,7 +408,11 @@ starting at Release Approval.

Website Manager Upload the tar file and its .asc signature file to the - epics-controls web-server [ToDo: ssh-key, location] + epics-controls web-server. +
+ scp base-7.0.3.tar.gz base-7.0.3.tar.gz.asc epics-controls:download/base
+
+ @@ -416,7 +420,10 @@ starting at Release Approval.

Follow instructions on Add a page for a new release to create a new release webpage (not - required for a patch release though, just edit the existing page). + required for a patch release, just edit the existing page). Update the + TablePress "Point Releases" table and add the new download, and adjust + the XYZ Html Snippet for the series download. + From fd48ee9aeced4096a96a8ba310ac19980e688524 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 13 Aug 2019 11:21:26 -0500 Subject: [PATCH 079/281] Update submodules Adjust comments in the embedded module CONFIG_*_VERSION files --- modules/ca/configure/CONFIG_CA_VERSION | 4 ++-- modules/database/configure/CONFIG_DATABASE_VERSION | 4 ++-- modules/libcom/configure/CONFIG_LIBCOM_VERSION | 4 ++-- modules/normativeTypes | 2 +- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/ca/configure/CONFIG_CA_VERSION b/modules/ca/configure/CONFIG_CA_VERSION index cac0fcbfe..57bcd89ac 100644 --- a/modules/ca/configure/CONFIG_CA_VERSION +++ b/modules/ca/configure/CONFIG_CA_VERSION @@ -4,9 +4,9 @@ EPICS_CA_MAJOR_VERSION = 4 EPICS_CA_MINOR_VERSION = 13 EPICS_CA_MAINTENANCE_VERSION = 5 -# Development flag, must be zero for official release versions +# Development flag, set to zero for release versions EPICS_CA_DEVELOPMENT_FLAG = 1 -# Immediately after an official release the MAINTENANCE_VERSION +# Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/modules/database/configure/CONFIG_DATABASE_VERSION b/modules/database/configure/CONFIG_DATABASE_VERSION index a43738cfb..ebf04180a 100644 --- a/modules/database/configure/CONFIG_DATABASE_VERSION +++ b/modules/database/configure/CONFIG_DATABASE_VERSION @@ -4,9 +4,9 @@ EPICS_DATABASE_MAJOR_VERSION = 3 EPICS_DATABASE_MINOR_VERSION = 17 EPICS_DATABASE_MAINTENANCE_VERSION = 5 -# Development flag, must be zero for official release versions +# Development flag, set to zero for release versions EPICS_DATABASE_DEVELOPMENT_FLAG = 1 -# Immediately after an official release the MAINTENANCE_VERSION +# Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/modules/libcom/configure/CONFIG_LIBCOM_VERSION b/modules/libcom/configure/CONFIG_LIBCOM_VERSION index 92c374f88..5953c7175 100644 --- a/modules/libcom/configure/CONFIG_LIBCOM_VERSION +++ b/modules/libcom/configure/CONFIG_LIBCOM_VERSION @@ -4,9 +4,9 @@ EPICS_LIBCOM_MAJOR_VERSION = 3 EPICS_LIBCOM_MINOR_VERSION = 17 EPICS_LIBCOM_MAINTENANCE_VERSION = 6 -# Development flag, must be zero for official release versions +# Development flag, set to zero for release versions EPICS_LIBCOM_DEVELOPMENT_FLAG = 1 -# Immediately after an official release the MAINTENANCE_VERSION +# Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/modules/normativeTypes b/modules/normativeTypes index c6168a747..ba33c7443 160000 --- a/modules/normativeTypes +++ b/modules/normativeTypes @@ -1 +1 @@ -Subproject commit c6168a74772a93f18facc83631c13db381ff15bb +Subproject commit ba33c7443c52689641c2a7377e39544d5dd326d2 diff --git a/modules/pvAccess b/modules/pvAccess index 936f5d35d..c8c3cf4fd 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 936f5d35d845a3c47a55176876a0f607a582cf09 +Subproject commit c8c3cf4fd8b3490221c1e231c354e73735ee3813 diff --git a/modules/pvData b/modules/pvData index 6ceaa6adb..b903df5d0 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 6ceaa6adb0b39dc3e37f064ca7e7bb5eea459d96 +Subproject commit b903df5d0daf08592368be2978efb2d828617a8c diff --git a/modules/pvDatabase b/modules/pvDatabase index 70ee85778..d7bd5628d 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit 70ee85778268bb47397d4cf8aa07e019ccdd8392 +Subproject commit d7bd5628d47f82b2ad2cab2ea97dade98c2ee128 diff --git a/modules/pva2pva b/modules/pva2pva index ce39c9320..d70a2ff8c 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit ce39c932013e3af1d4750394ee69ba20bd13fa74 +Subproject commit d70a2ff8c31bc042477b4997d733b77e6029e8f9 diff --git a/modules/pvaClient b/modules/pvaClient index aba40922e..246cceae3 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit aba40922e6a96519c214c7644bfdf49a8bd0d7f6 +Subproject commit 246cceae3e682ac99413673195fec07dffa77267 From 05cd95a8212551aa0d6205093ea1e2ac9fcdc128 Mon Sep 17 00:00:00 2001 From: Zimoch Dirk Date: Tue, 13 Aug 2019 20:35:05 -0700 Subject: [PATCH 080/281] astac argument checks --- modules/database/src/ioc/as/asDbLib.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/database/src/ioc/as/asDbLib.c b/modules/database/src/ioc/as/asDbLib.c index c0fe192b0..49be480bc 100644 --- a/modules/database/src/ioc/as/asDbLib.c +++ b/modules/database/src/ioc/as/asDbLib.c @@ -240,6 +240,10 @@ int astac(const char *pname,const char *user,const char *location) char *puser; char *plocation; + if (!pname || !user || !location){ + printf("Usage: astac \"record name\", \"user\", \"host\"\n"); + return(1); + } paddr = dbCalloc(1,sizeof(DBADDR) + sizeof(ASCLIENTPVT)); pasclientpvt = (ASCLIENTPVT *)(paddr + 1); status=dbNameToAddr(pname,paddr); From 2fb41d7a36748fe3e3b8c76019f696044ef5e46b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 23 Aug 2019 15:54:32 -0500 Subject: [PATCH 081/281] VxWorks: Measure CPU time-base frequency if necessary The BSP routine sysTimeBaseFreq() is optional. If not present or non-functional we measure the frequency of the CPU's time-base counter (against the OS system clock) once at initialization-time. --- .../libcom/src/osi/os/vxWorks/osdMonotonic.c | 52 ++++++++++++++----- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c b/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c index e0c6b2278..1e6b0a8ad 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c +++ b/modules/libcom/src/osi/os/vxWorks/osdMonotonic.c @@ -9,10 +9,13 @@ #include #include +#include +#include #define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE #include "epicsTypes.h" #include "epicsTime.h" +#include "cantProceed.h" #define NS_PER_SEC 1000000000 @@ -23,6 +26,7 @@ union timebase { UINT64 u64; /* epicsMonotonicGet() */ }; +static void measureTickRate(void); #if CPU_FAMILY == PPC #include @@ -46,12 +50,15 @@ void osdMonotonicInit(void) if (sysTimeBaseFreq) { ticksPerSec = sysTimeBaseFreq(); - if (!ticksPerSec) - printf("Warning: Failed to set up monotonic time source.\n"); - /* Warn here only if the BSP routine exists but returned 0 */ + if (ticksPerSec) + return; + + /* This should never happen */ + printf("Warning: sysTimeBaseFreq() present but returned zero.\n"); } - else - ticksPerSec = 0; /* Warn on first use */ + + /* Fall back to measuring */ + measureTickRate(); } @@ -73,8 +80,14 @@ void osdMonotonicInit(void) { ticksPerSec = vxCpuIdGetFreq(); - if (!ticksPerSec) - printf("Warning: Failed to set up monotonic time source.\n"); + if (ticksPerSec) + return; + + /* This should never happen */ + printf("Warning: vxCpuIdGetFreq() returned zero.\n"); + + /* Fall back to measuring */ + measureTickRate(); } @@ -96,13 +109,7 @@ epicsUInt64 epicsMonotonicGet(void) union timebase tbNow; if (!ticksPerSec) { - static int warned = 0; - - if (!warned) { - printf("Warning: Monotonic time source is not available.\n"); - warned = 1; - } - return 0; + cantProceed("Monotonic time source not available.\n"); } TIMEBASEGET(tbNow); @@ -111,3 +118,20 @@ epicsUInt64 epicsMonotonicGet(void) */ return ((long double) tbNow.u64) * NS_PER_SEC / ticksPerSec; } + +static void measureTickRate(void) +{ + union timebase start, end; + int sysTicks = sysClkRateGet(); /* 1 second */ + + printf("osdMonotonicInit: Measuring CPU time-base frequency ..."); + fflush(stdout); + + taskDelay(1); + TIMEBASEGET(start); + taskDelay(sysTicks); + TIMEBASEGET(end); + ticksPerSec = end.u64 - start.u64; + + printf(" %llu ticks/sec.\n", (unsigned long long) ticksPerSec); +} From a625acbb182f5c90810983aed74ecd4df4359d2e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sat, 24 Aug 2019 20:30:47 -0700 Subject: [PATCH 082/281] iocsh handle redirect and similar early errors --- modules/libcom/src/iocsh/iocsh.cpp | 73 +++++++++++++++++------------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 7392bca42..b3fe936cb 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -623,9 +623,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } } - /* - * Check for existing macro context or construct a new one. - */ + // Check for existing context or construct a new one. context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); if (!context) { @@ -654,6 +652,29 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Read commands till EOF or exit */ for (;;) { + if(!scope.interactive && scope.errored) { + if(scope.onerr==Continue) { + /* do nothing */ + + } else if(scope.onerr==Break) { + ret = -1; + fprintf(epicsGetStderr(), "iocsh Error: Break\n" ); + break; + + } else if(scope.onerr==Halt) { + ret = -1; + if(scope.timeout<=0.0 || isinf(scope.timeout)) { + fprintf(epicsGetStderr(), "iocsh Error: Halt\n" ); + epicsThreadSuspendSelf(); + break; + + } else { + fprintf(epicsGetStderr(), "iocsh Error: Waiting %.1f sec ...\n", scope.timeout); + epicsThreadSleep(scope.timeout); + } + } + } + /* * Read a line */ @@ -692,8 +713,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Expand macros */ free(line); - if ((line = macDefExpand(raw, handle)) == NULL) + if ((line = macDefExpand(raw, handle)) == NULL) { + scope.errored = true; continue; + } /* * Skip leading white-space coming from a macro @@ -706,9 +729,11 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) * Echo non-empty lines read from a script. * Comments delineated with '#-' aren't echoed. */ - if ((prompt == NULL) && *line && (commandLine == NULL)) - if ((c != '#') || (line[icin + 1] != '-')) + if ((prompt == NULL) && *line && (commandLine == NULL)) { + if ((c != '#') || (line[icin + 1] != '-')) { puts(line); + } + } /* * Ignore lines that became a comment or empty after macro expansion @@ -732,6 +757,7 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (newv == NULL) { fprintf (epicsGetStderr(), "Out of memory!\n"); argc = -1; + scope.errored = true; break; } argv = newv; @@ -805,8 +831,9 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } else { if (!sep) { - if (((c == '"') || (c == '\'')) && !backslash) + if (((c == '"') || (c == '\'')) && !backslash) { quote = c; + } if (redirect != NULL) { if (redirect->name != NULL) { argc = -1; @@ -827,16 +854,20 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } if (redirect != NULL) { showError(filename, lineno, "Illegal redirection."); + scope.errored = true; continue; } - if (argc < 0) + if (argc < 0) { break; + } if (quote != EOF) { showError(filename, lineno, "Unbalanced quote."); + scope.errored = true; continue; } if (backslash) { showError(filename, lineno, "Trailing backslash."); + scope.errored = true; continue; } if (inword) @@ -853,7 +884,8 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) if (openRedirect(filename, lineno, redirects) < 0) continue; startRedirect(filename, lineno, redirects); - iocshBody(commandFile, NULL, macros); + if(iocshBody(commandFile, NULL, macros)) + scope.errored = true; stopRedirect(filename, lineno, redirects); continue; } @@ -930,29 +962,6 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) } } stopRedirect(filename, lineno, redirects); - - if(!scope.interactive && scope.errored) { - if(scope.onerr==Continue) { - /* do nothing */ - - } else if(scope.onerr==Break) { - ret = -1; - fprintf(epicsGetStderr(), "iocsh Error: Break\n" ); - break; - - } else if(scope.onerr==Halt) { - ret = -1; - if(scope.timeout<=0.0 || isinf(scope.timeout)) { - fprintf(epicsGetStderr(), "iocsh Error: Halt\n" ); - epicsThreadSuspendSelf(); - break; - - } else { - fprintf(epicsGetStderr(), "iocsh Error: Waiting %f sec ...\n", scope.timeout); - epicsThreadSleep(scope.timeout); - } - } - } } macPopScope(handle); From 58473e825c76e859d9785a3fc4c7aee404adb95e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 25 Aug 2019 16:29:55 -0700 Subject: [PATCH 083/281] iocsh more error handling sooo many ways to fail... --- modules/libcom/src/iocsh/iocsh.cpp | 51 +++++++++++++++++++----------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index b3fe936cb..1ba1de635 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -1156,34 +1156,49 @@ static void onCallFunc(const iocshArgBuf *args) { iocshContext *context = (iocshContext *) epicsThreadPrivateGet(iocshContextId); +#define USAGE() fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n") + if(!context || !context->scope) { // we are not called through iocshBody()... } else if(args->aval.ac<3 || strcmp(args->aval.av[1], "error")!=0) { - fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n"); + USAGE(); } else if(context->scope->interactive) { fprintf(epicsGetStderr(), "Interactive shell ignores on error ...\n"); - } else if(strcmp(args->aval.av[2], "continue")==0) { - context->scope->onerr = Continue; - - } else if(strcmp(args->aval.av[2], "break")==0) { - context->scope->onerr = Break; - - } else if(strcmp(args->aval.av[2], "halt")==0) { - context->scope->onerr = Halt; - context->scope->timeout = 0.0; - - } else if(strcmp(args->aval.av[2], "wait")==0) { - context->scope->onerr = Halt; - if(args->aval.ac==3 || epicsParseDouble(args->aval.av[3], &context->scope->timeout, NULL)) { - context->scope->timeout = 5.0; - } - } else { - fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n"); + // don't fault on previous, ignored, errors + context->scope->errored = false; + + if(strcmp(args->aval.av[2], "continue")==0) { + context->scope->onerr = Continue; + + } else if(strcmp(args->aval.av[2], "break")==0) { + context->scope->onerr = Break; + + } else if(strcmp(args->aval.av[2], "halt")==0) { + context->scope->onerr = Halt; + context->scope->timeout = 0.0; + + } else if(strcmp(args->aval.av[2], "wait")==0) { + context->scope->onerr = Halt; + if(args->aval.ac<=3) { + USAGE(); + } else if(epicsParseDouble(args->aval.av[3], &context->scope->timeout, NULL)) { + context->scope->timeout = 5.0; + } else { + USAGE(); + fprintf(epicsGetStderr(), "Unable to parse 'on error wait' time %s\n", args->aval.av[3]); + } + + } else { + fprintf(epicsGetStderr(), "Usage: on error [continue | break | halt | wait ]\n"); + context->scope->errored = true; + } } + +#undef USAGE } /* From 2557d147853c944f4fd3b5e8baa21b78e67d88dc Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 25 Aug 2019 19:37:47 -0700 Subject: [PATCH 084/281] iocshCmd() imply "on error break" --- modules/libcom/src/iocsh/iocsh.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index 1ba1de635..a795c9b70 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -600,6 +600,10 @@ iocshBody (const char *pathname, const char *commandLine, const char *macros) fclose(fp); return -1; } + + } else { + // use of iocshCmd() implies "on error break" + scope.onerr = Break; } /* From 85517d761d028822ddae546aea20e235a4b3749c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 25 Aug 2019 17:40:26 -0700 Subject: [PATCH 085/281] iocshTest start --- modules/libcom/test/Makefile | 8 ++ modules/libcom/test/iocshTest.cpp | 131 ++++++++++++++++++ modules/libcom/test/iocshTestBadArg.cmd | 4 + .../libcom/test/iocshTestBadArgIndirect.cmd | 3 + modules/libcom/test/iocshTestSuccess.cmd | 8 ++ .../libcom/test/iocshTestSuccessIndirect.cmd | 3 + modules/libcom/test/rtemsTestData.c | 6 - 7 files changed, 157 insertions(+), 6 deletions(-) create mode 100644 modules/libcom/test/iocshTest.cpp create mode 100644 modules/libcom/test/iocshTestBadArg.cmd create mode 100644 modules/libcom/test/iocshTestBadArgIndirect.cmd create mode 100644 modules/libcom/test/iocshTestSuccess.cmd create mode 100644 modules/libcom/test/iocshTestSuccessIndirect.cmd delete mode 100644 modules/libcom/test/rtemsTestData.c diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index f2e495a90..27577f012 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -241,6 +241,11 @@ TESTS += yajlTest endif endif +TESTPROD_HOST += iocshTest +iocshTest_SRCS += iocshTest.cpp +TESTS += iocshTest +TESTFILES += $(wildcard ../iocshTest*.cmd) + # The testHarness runs all the test programs in a known working order. testHarness_SRCS += epicsRunLibComTests.c @@ -300,3 +305,6 @@ endif endif include $(TOP)/configure/RULES + +rtemsTestData.c : $(TESTFILES) $(TOOLS)/epicsMakeMemFs.pl + $(PERL) $(TOOLS)/epicsMakeMemFs.pl $@ epicsRtemsFSImage $(TESTFILES) diff --git a/modules/libcom/test/iocshTest.cpp b/modules/libcom/test/iocshTest.cpp new file mode 100644 index 000000000..1216ed579 --- /dev/null +++ b/modules/libcom/test/iocshTest.cpp @@ -0,0 +1,131 @@ +/*************************************************************************\ +* Copyright (c) 2019 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace { +void findTestData() +{ + const char *locations[] = { + ".", + "..", + ".." OSI_PATH_LIST_SEPARATOR "O.Common", + "O.Common", + }; + + for(size_t i=0; i %d", expect ? "ran" : "expected error from", fname, err); +} + +void testCmd(const char *cmd, bool expect=true) +{ + testDiag("eval \"%s\"", cmd); + int err = iocshCmd(cmd); + testOk((err==0) ^ (!expect), "%s \"%s\" -> %d", expect ? "eval'd" : "expected error from", cmd, err); +} + +std::set reached; +const iocshArg positionArg0 = {"position", iocshArgString}; +const iocshArg * const positionArgs[1] = { &positionArg0 }; +const iocshFuncDef positionFuncDef = {"position",1,positionArgs}; +void positionCallFunc(const iocshArgBuf *args) +{ + testDiag("Reaching \"%s\"", args[0].sval); + reached.insert(args[0].sval); +} + +void testPosition(const std::string& pos, bool expect=true) +{ + testOk((reached.find(pos)!=reached.end()) ^ !expect, + "%sreached position %s", expect ? "" : "not ", pos.c_str()); +} + +const iocshArg assertArg0 = {"condition", iocshArgInt}; +const iocshArg * const assertArgs[1] = {&assertArg0}; +const iocshFuncDef assertFuncDef = {"assert",1,assertArgs}; +void assertCallFunc(const iocshArgBuf *args) +{ + iocshSetError(args[0].ival); +} + +} // namespace + +MAIN(iocshTest) +{ + testPlan(19); + libComRegister(); + iocshRegister(&positionFuncDef, &positionCallFunc); + iocshRegister(&assertFuncDef, &assertCallFunc); + findTestData(); + + testFile("iocshTestSuccess.cmd"); + testPosition("success"); + reached.clear(); + testPosition("success", false); + + testCmd(" Date: Mon, 26 Aug 2019 09:45:23 -0700 Subject: [PATCH 086/281] deprecate iocshFindCommand() This function, and struct iocshFuncDef, expose internal details. Specifically iocshCmdDef::func . Which prevents changing/extending the iocsh function signature. Deprecate in favor of iocshCmd() and iocshRun(). --- modules/libcom/src/iocsh/iocsh.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h index 2e8dc225e..6781e2404 100644 --- a/modules/libcom/src/iocsh/iocsh.h +++ b/modules/libcom/src/iocsh/iocsh.h @@ -76,7 +76,7 @@ epicsShareFunc void epicsShareAPI iocshRegister( epicsShareFunc void epicsShareAPI iocshRegisterVariable ( const iocshVarDef *piocshVarDef); epicsShareFunc const iocshCmdDef * epicsShareAPI iocshFindCommand( - const char* name); + const char* name) EPICS_DEPRECATED; epicsShareFunc const iocshVarDef * epicsShareAPI iocshFindVariable( const char* name); From c63a564ad455ae94235b1ce0b65c426acf411a58 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 25 Aug 2019 20:30:14 -0700 Subject: [PATCH 087/281] doc --- documentation/RELEASE_NOTES.html | 21 +++++++++++++++++++++ modules/libcom/src/iocsh/iocsh.h | 17 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index df783606d..bdefbe0b8 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -30,6 +30,27 @@ release.

--> +

Iocsh "on error ..."

+ +

A new statement is added to enable IOC shell commands +to signal error conditions, and for scripts to respond. +This first is through the new function

iocshSetError(int)
+A script may be prefixed with eg. "on error break" +to stop at the failed command.

+ +
+on error continue | break | wait [value] | halt
+
+ +

A suggested form for IOC shell commands is:

+ +
+static void doSomethingCallFunc(const iocshArgBuf *args)
+{
+    iocshSetError(doSomething(...)); /* return 0 == success */
+}
+
+

EPICS Release 7.0.2.2

Build System changes

diff --git a/modules/libcom/src/iocsh/iocsh.h b/modules/libcom/src/iocsh/iocsh.h index 6781e2404..a63af64ce 100644 --- a/modules/libcom/src/iocsh/iocsh.h +++ b/modules/libcom/src/iocsh/iocsh.h @@ -84,11 +84,28 @@ epicsShareFunc const iocshVarDef * epicsShareAPI iocshFindVariable( /* This should only be called when iocsh is no longer needed*/ epicsShareFunc void epicsShareAPI iocshFree(void); +/** shorthand for @code iocshLoad(pathname, NULL) @endcode */ epicsShareFunc int epicsShareAPI iocsh(const char *pathname); +/** shorthand for @code iocshRun(cmd, NULL) @endcode */ epicsShareFunc int epicsShareAPI iocshCmd(const char *cmd); +/** Read and evaluate IOC shell commands from the given file. + * @param pathname Path to script file + * @param macros NULL or a comma seperated list of macro definitions. eg. "VAR1=x,VAR2=y" + * @return 0 on success, non-zero on error + */ epicsShareFunc int epicsShareAPI iocshLoad(const char *pathname, const char* macros); +/** Evaluate a single IOC shell command + * @param cmd Command string. eg. "echo \"something or other\"" + * @param macros NULL or a comma seperated list of macro definitions. eg. "VAR1=x,VAR2=y" + * @return 0 on success, non-zero on error + */ epicsShareFunc int epicsShareAPI iocshRun(const char *cmd, const char* macros); +/** @brief Signal error from an IOC shell function. + * + * @param err 0 - success (no op), !=0 - error + * @return The err argument value. + */ epicsShareFunc int iocshSetError(int err); /* Makes macros that shadow environment variables work correctly with epicsEnvSet */ From b2938459f8003cd5ed1484603e228d73afbe0d9b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 28 Aug 2019 15:28:08 -0500 Subject: [PATCH 088/281] Define pdevLibVME on non-VME RTEMS targets --- documentation/RELEASE_NOTES.html | 14 +++++++++++++- modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c | 7 ++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 103e5a957..10910080d 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -20,7 +20,7 @@ release.

which should also be read to understand what has changed since an earlier release.

-

EPICS Release 7.0.3

+

EPICS Release 7.0.3.1

+

Non-VME RTEMS targets now define pdevLibVME

+ +

Previously IOC executables that made calls to devLib routines would fail to +link when built for some non-VME based RTEMS targets, which would have to be +explicitly filtered out by sites that build Base for those targets. +This fix makes +that no longer necessary, all RTEMS targets should now link although the IOC +won't be able to be used with the VME I/O on those systems (that we don't have +VMEbus I/O support for in libCom).

+ +

EPICS Release 7.0.3

+

epicsTimeGetCurrent() optimization

Add a fast path to epicsTimeGetCurrent() and related calls diff --git a/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c b/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c index 0a96bad1a..b8f79e706 100644 --- a/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c +++ b/modules/libcom/src/osi/os/RTEMS/devLibVMEOSD.c @@ -350,7 +350,12 @@ static void unsolicitedHandlerEPICS(int vectorNumber) ); } -#endif /* defined(__PPC__) && defined(mpc750) */ +#else /* !defined(__PPC__) && !defined(__mcf528x__) */ + +/* No known VME interface here, provide a dummy */ +devLibVME *pdevLibVME; + +#endif /* defined(__PPC__) || defined(__mcf528x__) */ /* * Some vxWorks convenience routines From 62c3b0a585a4abcaae7794e487627bea29712be8 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 27 Aug 2019 16:51:00 +0200 Subject: [PATCH 089/281] don't send errlog on all logClients --- modules/libcom/src/log/iocLog.c | 14 ++++++++++++++ modules/libcom/src/log/logClient.c | 4 ---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/modules/libcom/src/log/iocLog.c b/modules/libcom/src/log/iocLog.c index e62da2050..8cb1349a1 100644 --- a/modules/libcom/src/log/iocLog.c +++ b/modules/libcom/src/log/iocLog.c @@ -18,8 +18,10 @@ #define epicsExportSharedSymbols #include "envDefs.h" +#include "errlog.h" #include "logClient.h" #include "iocLog.h" +#include "epicsExit.h" int iocLogDisable = 0; @@ -74,6 +76,14 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void) } } +/* + * logClientDestroy() + */ +static void iocLogClientDestroy (logClientId id) +{ + errlogRemoveListeners (logClientSendMessage, id); +} + /* * iocLogClientInit() */ @@ -89,6 +99,10 @@ static logClientId iocLogClientInit (void) return NULL; } id = logClientCreate (addr, port); + if (id != NULL) { + errlogAddListener (logClientSendMessage, id); + epicsAtExit (iocLogClientDestroy, id); + } return id; } diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 99ee671d9..b076d50cb 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -154,8 +154,6 @@ static void logClientDestroy (logClientId id) return; } - errlogRemoveListeners ( logClientSendMessage, (void *) pClient ); - logClientClose ( pClient ); epicsMutexDestroy ( pClient->mutex ); @@ -549,8 +547,6 @@ logClientId epicsShareAPI logClientCreate ( pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); } - errlogAddListener ( logClientSendMessage, (void *) pClient ); - return (void *) pClient; } From 243287877311748057baa61937ea8d8a530f8d27 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 27 Aug 2019 17:34:01 +0200 Subject: [PATCH 090/281] speed up logRestart thread termination at exit --- modules/libcom/src/log/logClient.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index b076d50cb..96382a2eb 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -44,6 +44,7 @@ typedef struct { SOCKET sock; epicsThreadId restartThreadId; epicsEventId stateChangeNotify; + epicsEventId shutdownNotify; unsigned connectCount; unsigned nextMsgIndex; unsigned connected; @@ -113,6 +114,7 @@ static void logClientDestroy (logClientId id) epicsMutexMustLock ( pClient->mutex ); pClient->shutdown = 1u; epicsMutexUnlock ( pClient->mutex ); + epicsEventSignal ( pClient->shutdownNotify ); /* unblock log client thread blocking in send() or connect() */ interruptInfo = @@ -157,8 +159,8 @@ static void logClientDestroy (logClientId id) logClientClose ( pClient ); epicsMutexDestroy ( pClient->mutex ); - epicsEventDestroy ( pClient->stateChangeNotify ); + epicsEventDestroy ( pClient->shutdownNotify ); free ( pClient ); } @@ -461,8 +463,8 @@ static void logClientRestart ( logClientId id ) else { logClientConnect ( pClient ); } - - epicsThreadSleep ( LOG_RESTART_DELAY ); + + epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY); epicsMutexMustLock ( pClient->mutex ); } @@ -505,14 +507,22 @@ logClientId epicsShareAPI logClientCreate ( pClient->shutdownConfirm = 0; epicsAtExit (logClientDestroy, (void*) pClient); - + pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty); if ( ! pClient->stateChangeNotify ) { epicsMutexDestroy ( pClient->mutex ); free ( pClient ); return NULL; } - + + pClient->shutdownNotify = epicsEventCreate (epicsEventEmpty); + if ( ! pClient->shutdownNotify ) { + epicsMutexDestroy ( pClient->mutex ); + epicsEventDestroy ( pClient->stateChangeNotify ); + free ( pClient ); + return NULL; + } + pClient->restartThreadId = epicsThreadCreate ( "logRestart", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackSmall), @@ -520,6 +530,7 @@ logClientId epicsShareAPI logClientCreate ( if ( pClient->restartThreadId == NULL ) { epicsMutexDestroy ( pClient->mutex ); epicsEventDestroy ( pClient->stateChangeNotify ); + epicsEventDestroy ( pClient->shutdownNotify ); free (pClient); fprintf(stderr, "log client: unable to start log client connection watch dog thread\n"); return NULL; From 0a3427c835e367792dd3419bc2a5bc1aea02386a Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 28 Aug 2019 09:29:57 +0200 Subject: [PATCH 091/281] do not discard unsent messages when log server has closed connection, instead try to send them after reconnect --- modules/libcom/src/log/logClient.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 96382a2eb..75984404c 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -85,8 +85,6 @@ static void logClientClose ( logClient *pClient ) pClient->sock = INVALID_SOCKET; } - pClient->nextMsgIndex = 0u; - memset ( pClient->msgBuf, '\0', sizeof ( pClient->msgBuf ) ); pClient->connected = 0u; /* From 709208ef5cd4db2764875175aacd94fd500e984a Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 28 Aug 2019 11:41:12 +0200 Subject: [PATCH 092/281] elimitate duplicate code in logClient --- modules/libcom/src/log/logClient.c | 62 +++++++----------------------- 1 file changed, 14 insertions(+), 48 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 75984404c..90fde98b5 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -174,57 +174,23 @@ static void sendMessageChunk(logClient * pClient, const char * message) { unsigned msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; - if ( strSize > msgBufBytesLeft ) { - int status; - - if ( ! pClient->connected ) { - break; - } - - if ( msgBufBytesLeft > 0u ) { - memcpy ( & pClient->msgBuf[pClient->nextMsgIndex], - message, msgBufBytesLeft ); - pClient->nextMsgIndex += msgBufBytesLeft; - strSize -= msgBufBytesLeft; - message += msgBufBytesLeft; - } - - status = send ( pClient->sock, pClient->msgBuf, - pClient->nextMsgIndex, 0 ); - if ( status > 0 ) { - unsigned nSent = (unsigned) status; - if ( nSent < pClient->nextMsgIndex ) { - unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent; - memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], - newNextMsgIndex ); - pClient->nextMsgIndex = newNextMsgIndex; - } - else { - pClient->nextMsgIndex = 0u; - } - } - else { - if ( ! pClient->shutdown ) { - char sockErrBuf[64]; - if ( status ) { - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - } - else { - strcpy ( sockErrBuf, "server initiated disconnect" ); - } - fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", - pClient->name, sockErrBuf ); - } - logClientClose ( pClient ); - break; - } + if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected) + { + /* buffer is full, thus flush it */ + logClientFlush ( pClient ); + msgBufBytesLeft = sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex; } - else { - memcpy ( & pClient->msgBuf[pClient->nextMsgIndex], - message, strSize ); - pClient->nextMsgIndex += strSize; + if ( msgBufBytesLeft == 0u ) { + fprintf ( stderr, "log client: messages to \"%s\" are lost\n", + pClient->name ); break; } + if ( msgBufBytesLeft > strSize) msgBufBytesLeft = strSize; + memcpy ( & pClient->msgBuf[pClient->nextMsgIndex], + message, msgBufBytesLeft ); + pClient->nextMsgIndex += msgBufBytesLeft; + strSize -= msgBufBytesLeft; + message += msgBufBytesLeft; } } From 59aa9cfe746b3fc08d7b94b82f47973f6c5ed92c Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 28 Aug 2019 15:15:19 +0200 Subject: [PATCH 093/281] avoid needless memmove calls --- modules/libcom/src/log/logClient.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 90fde98b5..203f29dd3 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -219,6 +219,8 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message ) void epicsShareAPI logClientFlush ( logClientId id ) { + unsigned nSent = 0u; + logClient * pClient = ( logClient * ) id; if ( ! pClient ) { @@ -227,20 +229,11 @@ void epicsShareAPI logClientFlush ( logClientId id ) epicsMutexMustLock ( pClient->mutex ); - while ( pClient->nextMsgIndex && pClient->connected ) { - int status = send ( pClient->sock, pClient->msgBuf, - pClient->nextMsgIndex, 0 ); + while ( nSent < pClient->nextMsgIndex && pClient->connected ) { + int status = send ( pClient->sock, pClient->msgBuf + nSent, + pClient->nextMsgIndex - nSent, 0 ); if ( status > 0 ) { - unsigned nSent = (unsigned) status; - if ( nSent < pClient->nextMsgIndex ) { - unsigned newNextMsgIndex = pClient->nextMsgIndex - nSent; - memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], - newNextMsgIndex ); - pClient->nextMsgIndex = newNextMsgIndex; - } - else { - pClient->nextMsgIndex = 0u; - } + nSent += (unsigned) status; } else { if ( ! pClient->shutdown ) { @@ -258,6 +251,11 @@ void epicsShareAPI logClientFlush ( logClientId id ) break; } } + pClient->nextMsgIndex -= nSent; + if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { + memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], + pClient->nextMsgIndex ); + } epicsMutexUnlock ( pClient->mutex ); } From 9df98c18386f1204fdf21a58f0f6dc1aae04126e Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 28 Aug 2019 15:23:00 +0200 Subject: [PATCH 094/281] send pending log messages directly after connecting --- modules/libcom/src/log/logClient.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 203f29dd3..743910fb8 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -223,7 +223,7 @@ void epicsShareAPI logClientFlush ( logClientId id ) logClient * pClient = ( logClient * ) id; - if ( ! pClient ) { + if ( ! pClient || ! pClient->connected ) { return; } @@ -419,12 +419,8 @@ static void logClientRestart ( logClientId id ) epicsMutexUnlock ( pClient->mutex ); - if ( isConn ) { - logClientFlush ( pClient ); - } - else { - logClientConnect ( pClient ); - } + if ( ! isConn ) logClientConnect ( pClient ); + logClientFlush ( pClient ); epicsEventWaitWithTimeout ( pClient->shutdownNotify, LOG_RESTART_DELAY); From 2b0161d9bfd8fc604942996d1812d245bf4a00f7 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 28 Aug 2019 15:29:23 +0200 Subject: [PATCH 095/281] no need to delay startup only because log server is currently not available --- modules/libcom/src/log/logClient.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 743910fb8..72a2e1364 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -54,7 +54,6 @@ typedef struct { } logClient; static const double LOG_RESTART_DELAY = 5.0; /* sec */ -static const double LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT = 5.0; /* sec */ static const double LOG_SERVER_SHUTDOWN_TIMEOUT = 30.0; /* sec */ /* @@ -438,9 +437,7 @@ static void logClientRestart ( logClientId id ) logClientId epicsShareAPI logClientCreate ( struct in_addr server_addr, unsigned short server_port) { - epicsTimeStamp begin, current; logClient *pClient; - double diff; pClient = calloc (1, sizeof (*pClient)); if (pClient==NULL) { @@ -494,28 +491,6 @@ logClientId epicsShareAPI logClientCreate ( return NULL; } - /* - * attempt to synchronize with circuit connect - */ - epicsTimeGetCurrent ( & begin ); - epicsMutexMustLock ( pClient->mutex ); - do { - epicsMutexUnlock ( pClient->mutex ); - epicsEventWaitWithTimeout ( - pClient->stateChangeNotify, - LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 ); - epicsTimeGetCurrent ( & current ); - diff = epicsTimeDiffInSeconds ( & current, & begin ); - epicsMutexMustLock ( pClient->mutex ); - } - while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); - epicsMutexUnlock ( pClient->mutex ); - - if ( ! pClient->connected ) { - fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n", - pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); - } - return (void *) pClient; } From b9bc836d1e446ad110b8c296f45833ffd092fd03 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Mon, 2 Sep 2019 14:47:39 +0200 Subject: [PATCH 096/281] appveyor-ci: disable cygwin x86 builds (install is broken) --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index b6fb2f2ae..21ec93c86 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -64,6 +64,9 @@ matrix: # Cygwin static-debug has compiler problems - configuration: static-debug TOOLCHAIN: cygwin + # Cygwin x86 install is currently (08/2019) broken (libncursesw-devel fails) + - platform: x86 + TOOLCHAIN: cygwin #---------------------------------# From 8a39ca74891e327f051f091030aa4bcbf7d126ff Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Tue, 3 Sep 2019 14:20:24 +0200 Subject: [PATCH 097/281] Preparing the waveform record DBD-POD file; Creation of the menuFtype DBD-POD file --- .../db/{menuFtype.dbd => menuFtype.dbd.pod} | 9 + src/std/rec/waveformRecord.dbd.pod | 517 +++++++++++++++++- 2 files changed, 499 insertions(+), 27 deletions(-) rename src/ioc/db/{menuFtype.dbd => menuFtype.dbd.pod} (88%) diff --git a/src/ioc/db/menuFtype.dbd b/src/ioc/db/menuFtype.dbd.pod similarity index 88% rename from src/ioc/db/menuFtype.dbd rename to src/ioc/db/menuFtype.dbd.pod index ff20e0ca4..fd643f625 100644 --- a/src/ioc/db/menuFtype.dbd +++ b/src/ioc/db/menuFtype.dbd.pod @@ -7,6 +7,15 @@ # and higher are distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuFtype + +This menu is used for the C field of all record types. + +=menu menuFtype + +=cut + menu(menuFtype) { choice(menuFtypeSTRING,"STRING") choice(menuFtypeCHAR,"CHAR") diff --git a/src/std/rec/waveformRecord.dbd.pod b/src/std/rec/waveformRecord.dbd.pod index db2fa05fb..e40aa2a21 100644 --- a/src/std/rec/waveformRecord.dbd.pod +++ b/src/std/rec/waveformRecord.dbd.pod @@ -1,35 +1,13 @@ -#************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne -# National Laboratory. -# Copyright (c) 2002 The Regents of the University of California, as -# Operator of Los Alamos National Laboratory. -# EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. -#************************************************************************* +=pod =title Waveform Record (waveform) -... - -=head2 Record-specific Menus - -=head3 Menu waveformPOST - -The MPST and APST fields use this menu to determine when to post new value -and archive monitors respectively. - -=menu waveformPOST - -... - -=head2 Parameter Fields - -The record-specific fields are described below. +The waveform record type is used to interface waveform digitizers. The record +stores its data in arrays. The array can contain any of the supported data +types. =recordtype waveform -... - =cut menu(waveformPOST) { @@ -39,7 +17,492 @@ menu(waveformPOST) { recordtype(waveform) { -=fields VAL, FTVL, MPST, APST +=pod + +=head1 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +


+ +=end html + +=head2 Parameter Fields + +The waveform's fields fall into the following categories: + +=over + +=item * L; + +=item * L; + +=item * L; + +=item * L; + +=back + +=head3 Scan Parameters + +The waveform record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Read Parameters + +These fields are configurable by the user to specify how and from where the +record reads its data. How the INP field is configured determines where the +waveform gets its input. It can be a hardware address, a channel access or +database link, or a constant. Only in records that use soft device support can +the INP field be a channel access link, a database link, or a constant. +Otherwise, the INP field must be a hardware address. See L
for information on the format of hardware addresses and database +links. + +=head4 Fields related to waveform reading + +=fields DTYP, INP, NELM, FTVL, RARM + +The DTYP field must contain the name of the appropriate device support module. +The values retrieved from the input link are placed in an array referenced by +VAL. (If the INP link is a constant, elements can be placed in the array via +dbPuts.) NELM specifies the number of elements that the array will hold, while +FTVL specifies the data type of the elements. +The RARM field causes the device to re-arm when this field is set to 1. + +=head4 Possible data types for FTVL + +=begin html + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
IndexIdentifierChoice String
0menuFtypeSTRINGSTRING
1menuFtypeCHARCHAR
2menuFtypeUCHARUCHAR
3menuFtypeSHORTSHORT
4menuFtypeUSHORTUSHORT
5menuFtypeLONGLONG
6menuFtypeULONGULONG
7menuFtypeFLOATFLOAT
8menuFtypeDOUBLEDOUBLE
9menuFtypeENUMENUM
+ + +=end html + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the waveform either textually or +graphically. + +=head4 Fields related to I + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +EGU is a string of up to 16 characters describing the units that the waveform +measures. It is retrieved by the C<<< get_units >>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for array +elements referenced by the VAL field. Both the C<<< get_graphic_double >>> and +C<<< get_control_double >>> record support routines retrieve these fields. + +The PREC field determines the floating point precision with which to display the +array values. It is used whenever the C<<< get_precision >>> record support +routine is called. + +See L for more on the record name (NAME) and +description (DESC) fields. + + +=head3 Alarm Parameters + +The waveform record has the alarm parameters common to all record types. L lists other fields related to a alarms that are common to all record +types. + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the VAL +field. The APST and MPST fields are a menu with choices "Always" and "On +Change". The default is "Always", thus monitors will normally be sent every time +the record processes. Selecting "On Change" causes a 32-bit hash of the VAL +field buffer to be calculated and compared with the previous hash value every +time the record processes; the monitor will only be sent if the hash is +different, indicating that the buffer has changed. Note that there is a small +chance that two different value buffers might result in the same hash value, so +for critical systems "Always" may be a better choice, even though it re-sends +duplicate data. + +=head4 Record fields related to I + +=fields APST, MPST, HASH + +=head4 Menu choices for C and C fields + +=menu waveformPOST + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the waveform. They +are not configured using a configuration tool. Only the VAL field is modifiable +at run-time. + +VAL references the array where the waveform stores its data. The BPTR field +holds the address of the array. + +The NORD field holds a counter of the number of elements that have been read +into the array. It is reset to 0 when the device is rearmed. The BUSY field +indicates if the device is armed but has not yet been digitized. + +=fields VAL, BPTR, NORD, BUSY + +The following fields are used to operate the waveform in the simulation mode. +See L for more information on the simulation mode fields. + +=fields SIOL, SIML, SIMM, SIMS + +=begin html + +
+
+
+ +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + + static long init_record(waveformRecord *prec, int pass) + +Using NELM and FTVL space for the array is allocated. The array address is +stored in the record. + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. VAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated + +If device support includes C, it is called. + +=head4 process + + static long process(waveformRecord *prec) + +See L section below. + +=head4 cvt_dbaddr + + static long cvt_dbaddr(DBADDR *paddr) + +This is called by dbNameToAddr. It makes the dbAddr structure refer to the +actual buffer holding the result. + +=head4 get_array_info + + static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) + +Obtains values from the array referenced by VAL. + +=head4 put_array_info + + static long put_array_info(DBADDR *paddr, long nNew) + +Writes values into the array referenced by VAL. + +=head4 get_units + + static long get_units(DBADDR *paddr, char *units) + +Retrieves EGU. + +=head4 get_prec + + static long get_precision(DBADDR *paddr, long *precision) + +Retrieves PREC if field is VAL field. Otherwise, calls C<<< recGblGetPrec() >>>. + +=head4 get_graphic_double + + static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) + +Sets the upper display and lower display limits for a field. If the field is VAL +the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +Sets the following values: + + upper_disp_limit = HOPR + lower_disp_limit = LOPR + +=head4 get_control_double + + static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) + +Sets the upper control and the lower control limits for a field. If the field is +VAL the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +Sets the following values + + upper_ctrl_limit = HOPR + lower_ctrl_limit = LOPR + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +Call device support read routine. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed writing the new value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if APST or MPST are Always or if +the result of the hash calculation is different. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 5. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
+
+
+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each waveform record must have an associated set of device support routines. The +primary responsibility of the device support routines is to obtain a new array +value whenever read_wf is called. The device support routines are primarily +interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, INP, NELM, FTVL, RARM, BPTR, NORD, BUSY + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 read_wf + + read_wf(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C<<< Soft Channel >>> device support module is provided to read values from +other records and store them in arrays. If INP is a constant link, then read_wf +does nothing. In this case, the record can be used to hold arrays written via +dbPuts. If INP is a database or channel access link, the new array value is read +from the link. NORD is set. + +This module places a value directly in VAL. + +If the INP link type is constant, then NORD is set to zero. If the INP link type +is PV_LINK, then dbCaAddInlink is called by C. + +read_wf calls recGblGetLinkValue which performs the following steps: + +=over + +=item * + +If the INP link type is CONSTANT recGblGetLinkValue does nothing. + +=item * + +If the INP link type is DB_LINK, then dbGetLink is called to obtain a new input +value. If dbGetLink returns an error, a LINK_ALARM with a severity of +INVALID_ALARM is raised. + +=item * + +If the INP link type is CA_LINK, then dbCaGetLink is called to obtain a new +input value. If dbCaGetLink returns an error, a LINK_ALARM with a severity of +INVALID_ALARM is raised. + +=item * + +NORD is set to the number of values returned and read_wf returns. + +=back =cut From 67583b4bda38190952a9cb3e76ace2a4eb0b40af Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Wed, 4 Sep 2019 10:58:20 +0200 Subject: [PATCH 098/281] Update compressRecord.dbd.pod based on Wiki + Content update --- src/std/rec/Makefile | 6 + src/std/rec/compressRecord.dbd.pod | 386 +++++++++++++++++++++++++++-- src/std/rec/image/compress-1.jpg | Bin 0 -> 16781 bytes src/std/rec/image/compress-2.gif | Bin 0 -> 4136 bytes 4 files changed, 371 insertions(+), 21 deletions(-) create mode 100644 src/std/rec/image/compress-1.jpg create mode 100644 src/std/rec/image/compress-2.gif diff --git a/src/std/rec/Makefile b/src/std/rec/Makefile index 7515d769c..307662ebb 100644 --- a/src/std/rec/Makefile +++ b/src/std/rec/Makefile @@ -53,3 +53,9 @@ stdRecords_DBD = $(patsubst %,%.dbd,$(stdRecords)) dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords)) HTMLS += $(patsubst %.dbd.pod,%.html,$(notdir $(wildcard ../rec/*Record.dbd.pod))) + +vpath %.jpg $(USR_VPATH) .. $(SRC_DIRS) ../rec/image +vpath %.gif $(USR_VPATH) .. $(SRC_DIRS) ../rec/image + +HTMLS += compress-1.jpg +HTMLS += compress-2.gif diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index a67e12d3c..90cacb77d 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -7,43 +7,387 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=title Compress Record (compress) +=title Compression Record (compress) -... +The data compression record is used to collect and compress data from arrays. +When the INP field references a data array field, it immediately compresses the +entire array into an element of an array using one of several algorithms, +overwriting the previous element. If the INP field obtains its value from a +scalar-value field, the compression record will collect a new sample each time +the record is processed and add it to the compressed data array as a circular +buffer. -=head2 Record-specific Menus - -=head3 Menu compressALG - -The ALG field which uses this menu controls the compression algorithm used. - -... - -=menu compressALG - -... - -=head2 Parameter Fields - -The record-specific fields are described below. +The INP link can also specify a constant; however, if this is the case, the +compression algorithms are ignored, and the record support routines merely +return after checking the FLNK field. =recordtype compress -... - =cut menu(compressALG) { choice(compressALG_N_to_1_Low_Value,"N to 1 Low Value") choice(compressALG_N_to_1_High_Value,"N to 1 High Value") choice(compressALG_N_to_1_Average,"N to 1 Average") + choice(compressALG_N_to_1_Median,"N to 1 Median") choice(compressALG_Average,"Average") choice(compressALG_Circular_Buffer,"Circular Buffer") - choice(compressALG_N_to_1_Median,"N to 1 Median") } recordtype(compress) { -=fields VAL +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=back + +=begin html + +
+
+
+ +=end html + +=head2 Parameter Fields + +=head3 Scanning Parameters + +The compression record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. In addition, +L +explains how these fields are used. Since the compression record supports no +direct interfaces to hardware, its SCAN field cannot specify C<<< I/O Intr >>>. + +=head3 Algorithms and Related Parameters + +The user specifies the algorithm to be used in the ALG field. There are six possible +algorithms which can be specified as follows: + +=head4 Menu compressALG + +=menu compressALG + +The following fields determine what channel to read and how to compress the data: + +=fields ALG, INP, NSAM, N, ILIL, IHIL, OFF, RES + +As stated above, the ALG field specifies which algorithm to be performed on the data. + +The INP should be a database or channel access link. Though INP can be a constant, +the data compression algorithms are supported only when INP is a database link. See +L
+for information on specifying links. + + +IHIL and ILIL can be set to provide an initial value filter on the input array. +If ILIL E IHIL, the input elements will be skipped until a value is found +that is in the range of ILIL to IHIL. Note that ILIL and IHIL are used only in +C<<< N to 1 >>> algorithms. + +OFF provides the offset to the current beginning of the array data. +Note that OFF is used only in C<<< N to 1 >>> algorithms. + +The RES field can be accessed at run time to cause the algorithm to reset +itself before the maximum number of samples are reached. + +=head4 Algorithms + +B algorithm keeps a circular buffer of length NSAM. +Each time the record is processed, it gets the data referenced by INP and puts +it into the circular buffer referenced by VAL. The INP can refer to both scalar or +array data and VAL is just a time ordered circular buffer of values obtained +from INP. +Note that N, ILIL, IHIL and OFF are not used in C<<< Circular Buffer >>> algorithm. + +B takes an average of every element of the array obtained from +INP over time; that is, the entire array referenced by INP is retrieved, and for +each element, the new average is calculated and placed in the corresponding +element of the value buffer. The retrieved array is truncated to be of length +NSAM. N successive arrays are averaged and placed in the buffer. Thus, VAL[0] +holds the average of the first element of INP over N samples, VAL[1] holds the +average of the next element of INP over N samples, and so on. The following +shows the equation: + +=begin html + + + +=end html + +B If any of the C<<< N to 1 >>> algorithms are chosen, then VAL is a circular +buffer of NSAM samples. +The actual algorithm depends on whether INP references a scalar or an array. + +If INP refers to a scalar, then N successive time ordered samples of INP are taken. +After the Nth sample is obtained, a new value determined by the algorithm +(Lowest, Highest, or Average), is written to the circular buffer referenced by +VAL. If C<<< Low Value >>> the lowest value of all the samples is written; if +C<<< High Value >>> the highest value is written; and if C<<< Average >>>, the +average of all the samples are written. The C<<< Median >>> setting behaves +like C<<< Average >>> with scalar input data. + +If INP refers to an array, then the following applies: + +=over + +=item C<<< N to 1 Low Value >>> + +Compress N to 1 samples, keeping the lowest value. + +=item C<<< N to 1 High Value >>> + +Compress N to 1 samples, keeping the highest value. + +=item C<<< N to 1 Average >>> + +Compress N to 1 samples, taking the average value. + +=item C<<< N to 1 Median >>> + +Compress N to 1 samples, taking the median value. + +=back + +The compression record keeps NSAM data samples. + +The field N determines the number of elements to compress into each result. + +Thus, if NSAM was 3, and N was also equal to 3, then the algorithms would work +as in the following diagram: + +=begin html + + + +=end html + + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the record either textually or +graphically. + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +The EGU field should be given a string that describes the value of VAL, but is +used whenever the C<<< get_units >>> record support routine is called. + +The HOPR and LOPR fields only specify the upper and lower display limits for +VAL, HIHI, HIGH, LOLO and LOW fields. + +PREC controls the floating-point precision whenever C<<< get_precision >>> is +called, and the field being referenced is the VAL field (i.e., one of the values +contained in the circular buffer). + +See L +for more on the record name (NAME) and description (DESC) fields. + + +=head3 Alarm Parameters + +The compression record has the alarm parameters common to all record types described in +L. + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the data +compression algorithm. They are not configurable by the user, though some are +accessible at run-time. They can represent the current state of the waveform or +of the record whose field is referenced by the INP field. + +=fields NUSE, OUSE, BPTR, SPTR, WPTR, CVB, INPN, INX + +NUSE and OUSE hold the current and previous number of elements stored in VAL. + +BPTR is a pointer that refers to the buffer referenced by VAL. + +SPTR points to an array that is used for array averages. + +WPTR is used by the dbGetlinks routines. + +=begin html + +
+
+
+ +=end html + +=head2 Record Support + +=head3 Record Support Routines (compressRecord.c) + +=head4 init_record + + static long init_record(compressRecord *prec, int pass) + +Space for all necessary arrays is allocated. The addresses are stored in the +appropriate fields in the record. + +=head4 process + + static long process(compressRecord *prec) + +See L + +=head4 special + + static long special(DBADDR *paddr, int after) + +This routine is called when RSET, ALG, or N are set. It performs a reset. + +=head4 cvt_dbaddr + + static long cvt_dbaddr(DBADDR *paddr) + +This is called by dbNameToAddr. It makes the dbAddr structure refer to the +actual buffer holding the result. + +=head4 get_array_info + + static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) + +Obtains values from the circular buffer referenced by VAL. + +=head4 put_array_info + + static long put_array_info(DBADDR *paddr, long nNew) + +Writes values into the circular buffer referenced by VAL. + +=head4 get_units + + static long get_units(DBADDR *paddr, char *units) + +Retrieves EGU. + +=head4 get_precision + + static long get_precision(DBADDR *paddr, long *precision) + +Retrieves PREC. + +=head4 get_graphic_double + + static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) + +Sets the upper display and lower display limits for a field. If the field is +VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +=head4 get_control_double + + static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) + +Sets the upper control and the lower control limits for a field. If the field is +VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower +limits defined they will be used, else the upper and lower maximum values for +the field type will be used. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +If INP is not a database link, check monitors and the forward link and return. + +=item 2. + +Get the current data referenced by INP. + +=item 3. + +Perform the appropriate algorithm: + +=over + +=item * + +Average: Read N successive instances of INP and perform an element by element +average. Until N instances have been obtained it just return without checking +monitors or the forward link. When N instances have been obtained complete the +algorithm, store the result in the VAL array, check monitors and the forward +link, and return. + +=item * + +Circular Buffer: Write the values obtained from INP into the VAL array as a +circular buffer, check monitors and the forward link, and return. + +=item * + +N to 1 xxx when INP refers to a scalar: Obtain N successive values from INP and +apply the N to 1 xxx algorithm to these values. Until N values are obtained +monitors and forward links are not triggered. When N successive values have been +obtained, complete the algorithm, check monitors and trigger the forward link, +and return. + +=item * + +N to 1 xxx when INP refers to an array: The ILIL and IHIL are honored if ILIL +E IHIL. The input array is divided into subarrays of length N. The specified +N to 1 xxx compression algorithm is applied to each sub-array and the result +stored in the array referenced by VAL. The monitors and forward link are +checked. + +=back + +=item 4. + +If success, set UDF to FALSE. + +=item 5. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back =cut diff --git a/src/std/rec/image/compress-1.jpg b/src/std/rec/image/compress-1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9ce8f4145887e0361016b4cf3c7543d00d83cbc5 GIT binary patch literal 16781 zcmeHt2RvL|yYFT&`Vd{TC?VQJ5+VshB!~zig6PqW(Mt@5(M2Z`LJ}euxPfnNyxLf{tyzYzF^z<);s46N<#?S!sbJ39GT zyI9+h*~7oF1zMM%i2Py;{~gE0FPncM@C$)o2>e3e7Xp8afB|3)*pq*DWY@wqa@rAa z0({7K7qXDq1KCGG@8sm;<8cuRb@P_BwsW_!m$h|wg(9szpmMUOp@5PK(!<&oVecbk zWA6xeQx@N-Z4eiN+bN41%j=xh@wj5|1iu#GWp5Cmd)qbuVSB+&Tm{BNuY|maboFqx z_pug2y1KY|UqmVk|5p1&a{A|Es4z^)%g*8At*aV;lpyDnh5u-apP!$s-&t9AFGr}{ zg$oy;r_VsooRJ}ykn#3+^RY(CxOt2GQNdMvZ(A?8hY#G{P3UKZ);8|GKFY$rzHqyX z4%QCxHg5FBSeZy8b_d>)%+Ty&IV-`jI&yX&kr$fT^izsHwm-)HJkUFfBbR1DRvc zb3j-aS-ClQdAK>axsD5npE%Ah#?QqqEGsM~aY{;BidP7F7Akp0TvAH%XC)M1T3UKK zdUgf|c1b>NKFPm)ks1M3TA+mTI*39Tpk$>0u~Lv)0YS1ajhY<0`x(Cb{9KO-)4(+))IP-vd;v)W=T9U8Z5vw+0J)vY!b}$)y!hD{tbs z)r%E9YvUD0N6*Q{&BH5pQe5JcLsr^cGMHuSwc*``WZQgs#4ggQVi2f}aPnU2#>Fe}Y|KmHPh?p-`mC z3ah_2d`|mNg?Wr{2TQQ8GLyNrus+X4w3Hq*G8Z(L5DbMqS`U^QNY}&$mleJrlX*R# z3Y*bYF?}_CBydSEIzZ!*CwB^$Ug8D){fUSBl{;NIOc2OwTCf=QD6RY@?9i+;?M}C6 zR>yY%NZ@h)vuB|+P6E=I zpY&Ll%bh9PMyC^99x`e$8$b71@{(#nJAX#Ho^xktLNIz<;Y*d&J(OeWAm|0PUnJ zJ%?M9AyB+AM!X$*+_c+s2F-vEAYSsLlciIOh>wr10pr@-(ak1@YUrNm91<|qMs8f@ z{_0FYQW;DD+0JA%?vvJie?z9JF-_Q?psBxM<+IFNmG=IHnR9^oswdo+`@t#pITmyY zfb2)s?nW3&qrka$0~A#X#t>k0d>gK~#pCVRaOn0SlHL9#=h-@E;!Upz+EcX!Qk^GAjdeG1YiZwL}e>A)G1u#Mk0}aWOeKXC)PrD^LhT8yWxmO+>BaF z%80fGr|yVdQ^P`Bbky3dF%cmhwMnt&unAF6wGxZ+<(;z2N16FkSm#mX(Zt*;2}p80 z=mD4LtFr@tO;9_Bs;IMXdI@4AfKEK3BwH_S5_7)GT_p06`O)Ut_^5Whk3bNEI&%02 z33!ROy@Q24D>GZ}B>`?DmE+$nl;StR>t0%o_ClEaKpBADID~-0>P5|2NcL;?=IXH_ z!wu;8TkXSHf)7uBqn$H;jTdhW5DeLltmrA>1uB0K+2q6TY#E*xuSSAdfqOr@fzMvd6bdSyvQT1rL4DTb{mLq zVyWblj89!QXGHVW^L_deGkfQAF~_N0la^!3G+(ltYr7f|{uE0$!}pE9HdL&=6>k@S zK5Tz^Edp^okXe4AohA*K{g6zMxLu&- zFQ}VI0t`RI_VrOui1sTQ>aXjVmg>#wh0NmPW;lBm2Sne{*ge+ab)OI9=lp#I=p4|W4wZjixa0bdm~JP%DE#)X^7?tu487htjKJ641FIpUYkLsui;Y4 z<;@my#uf;cA4EE~?ACK&+oGZi(h-5&SFd&NJ>l2d6F*sx!aqY$1`ok_=#CXU+to~U zYG2smvpbxId9QP=Z`bGuGE^Ul zkDJyOyboik>4U1h7}=6>qg~)poj$t6x@<+idQq7KM9YttKySyCY`Dyy5h zG*=`X&u5%L{1S=5+xj9TPOMd((vQwgY^+~VST>^)0JC#6p=uX~m zp%BupI-f|_j#M%40r#^TN1;IYnz6MHc$Kze4~L|O?cY{l-B{5fi}+!|`v<&x7XgXa zuIOe{uGp)B*kpLQRnXJ&h|X(rsRLoOO|x~+XU?}IFv}hw@w5_D|(RdR)2)Qgu&hs*?pGX;mJf#t&u3)lk;6 z`!}5J?rW64=aFRSN`};f=T!x-IAtzm&ngS^>uF{bynO;QPhe};Wrlp3X6;;;w9qyv z@7-Q5+c7IFkrA@!(>WVyC@?ozG)EN0Gehs!v$`?|sc8caS`oc3iN@vT@rglBlncd} zY-Xo=!FR*ZDly{MTA|CH?rh&gJ4Nqmybb_;y$f&P3+7)r$gh7^fRFxK`#xEn-Qm-W zpPVA-s&w-O2r>@?+};D2mWrmrd}OQ0N-Rbs#)$ooYp z@y`2uF(41d-bJ|JhAjH}L2SLlQQo$8Ha+t2DsDHC{@erMPoLXQCOzst{M<2P`Lz^( z(APa9T7SCo?yCHQF6ZaP*DVIdkBK_hSJ5L>qn#fRudGp2px0sYR3 z_6m)rltz2&p76FFigQkO?7JKDnd8UA8mEas0!p;NuwM{Kxz(l?{HV};9`A2SsLstx~m5n zcytIk;#Uak=bigZRzXYX6zlW26=awO`)ZcfJE}U+;cMj6*=Ag9Ca@D1{JEm8wqBpK- zZm)Z$CWeK`k@pO>Dy(e!u{OGfp|U5R`rj@Q37Y~GuvogeVa+_PS30>STBR+Fys2t0 z7bLhVL@>#8YgXcTwpp46e@udAyPqX^fM8$rKqS`8DD~4DgX~9!HYh%i3w(|PnLC1b zOG`3M%Y)8B4p-1b%^ZkpUY$0PD?Nb(EXCo&i3emmQkFB|yLJ#q`OeM01Ua1gMFVx#h+IdeaaHbp6j4jG107W0}P3e#5kn%af!N#apLBw!;aMPeAk{o4;hwXhiU{V^2z8(7E=)5oE~^SkqfT3~RJSIG z5Lp>X06eDYmiHTR+y)7-<>|%`Pj=PX>_47Jdg6X#_%VS4Z>dB#vpXPfe++SuJmq_0 zuC*YAo9H-jB-Kx5dw+0%vJ5oBeV-0*MXdQw?koM_e#0&3nkxx7p~64{hL2|-(O(1( z&TEi>WTxn&Kut0ikDY-DlYlO5yf+E3zCZ%DwMsYs=kIfvL73s@;wNSecs&AV8TEWE zU0GiBOeo*}Y9a>Tpklfa%!D$mCNs2Nrd3hXwFjZTESRtSR7J`V&k-WWvUJgkA$bi5 zqwN%~zm3nG4lghs}H9Ly7@BhIo}Jkk~{% zg)LQD${n6WcY<22cDA^PVTe(JCkYUy`A7opE|X0*DLZzQCUa}AIZOQAqZhX`k-eGc zB^ue4qWHqsB|uA3tA`e6nh_IfvzHJ~EOix~Be(SjQmrnaPW3qAHac|7W_ic!Ol3X} zl(|ZUDJ|2EWuyl4aYCkN@;5&7_P0k z+>M=_6dUK$7c#uO1Wezg8X!-GGyl=rRG*N3q)h@oAQqvcengEj-XI$i&@-O{$#Zvi z-Cn&QyJ3Il?tS}-T6D}>=ull;n-v#I-yX--LgeoyC`hkWne^MYzc?$3<80wbFq4~h z+}QddH7eEW`h>^^8Ef`O51Aq@TWsb$DpHab7K!^g5Vx`?FmdwO7)2T!ebzhT-PwMI z8pWv)bw4*}ubZNmhI1eBGLP0)ZO?v1@zg9)j5Z2{g(%;uH^zTzBn}7&0%2Fv08I5p@iG&r zWl^=?u9CO?RbesTi_D16QmqQ1Rd*yX@mr~>=G1#Xa5EMLw_WuN2kS2T7hVD*-j^AF zk-o?m!QJ6v%U=i@Twxfmc`YpqmE{&S!o4l+c%z?6DE_L~SWMZP#D|>FK!S|91^1bY z&4asnsrPu(V^L;7JcqsCSFW#2SxxkSZLuW4^dnBNrIz2(z+-DlQ?!Mii`L{FBSgIo z+3};61c(?Xz{=4}Uc(Je2l8dnD0#&5<)*fhgqkRsMVTrM8a;1I(4j2ZD>8`Ddu?^V z_m*N?XJ_mVe2**DlfON@c>0=Xy2cHo`3cC z{Ezn{-pMN4nTcboMuP<`CSw|QkGgYyC~GZI12%*!xb-L4z2-{iu~hKGc^TKx{eo0J ziQRQQYfD3{apOT!tnYrXIDXY<&rjD%H}>+Lrrufp5IzY)kkm8m?z30K9umMdWjQSD zq$HCM8(I72(Q<(`d?LvR_B6n_zg(S<<;Bgs4nAiNRt?I~M#>PupYA?Oz39pZs(m_Crf8U zuc3Y~_$<~k3DeEo^?Vg~Nv-vaHYk1SZV0xF$#5;V9%+Eyc0y!BU5} zO_T2XcDlGd-<*3>Rg&L2q{&IS90So8oG3=SltdjZRRMJz?FwhZF(p1(!WEx4RRhBYV`kZs ztcd)$koNKtE$kTP_7kJ}zQr_TZbiRKK5LjoBc%~vt*vN?TH;g8 z$scKN@Ws0izcgyO&jiWbVSe8Is6ypLINkszV=+F3-)pSrtIbk$o!qZFo+=e-kzA^w zg(*c#0^83{j+sH3Ovb)n>(ge+(^y{=dn`niYNbN_+^{K+>|f;~M#}_2nC7?+&||KA zT@0^A4zDpPYXp$pr8^v3|84>60r#FChFceWx72C9hdWoY{d1{os;59)^x;LvpiD|E z+N(bd72Z+|ojUh;KTMLblJEUA^WgeHLIm&23~%dubYUweqf`s1iWvpayz>MmY-RHl z=YwXZmJ_9B8nnZWak(gnK%EaJ4Ku?ASMJH=>FXq zp$FXO^BXz-Ns#|zIb(N5ZRt4NUg-QwO;em61BwdA6}E$TcBRFNHQ~ju`3>gS3hD3* zO-!fw^-OnHBtR-x-VVI>x$nC3QODP8ush@4yJmoZ+oV)&#FRLZmDnLu^@et2l!dVi zA2P){lh2wfKlmPHE|`uu-QngvR##OILKsi6NTbZkko!AQt6G>;;$>~l`76ocE;ahY z)d9Pi|Iir*6q&wDDnN|6WCm9{a;&|mnPU9>-V7`vvTE#<14)HR;Y}ft4Qwv*Nzrfg zz@vA~4)5Pi*Y;d+S@BYlg-W@H|_9SoN%TDZfYL`RD}c<8-_lv*L~_l zBZB+J;yV_S)O$rD(WCxWo=4Px-v`<7e5AJ?=S7YPPR`so+PgZ%sRKs{wcp7(Md>QL z%jW5;H?`050m?ckKiu$aKOSS|dR+Z!0!_Q#!&kE_m)o~io>wng86m4% zkvoweJJ^)t@-CJ6ewOkGoHkBFw@4yIh+*~QgID8y75rDg9~^~tazBRGY%zqPJkZaOhK5+lGH4OKpRd1;(JK| zcli)T74osvXM>yM^NI=wWtmY9liku5&LE|!keLpLlLe=cEt5eA6TQvi+av@tV zwIp?Z_CSC-i0$yCdIDSPt*x)E+H1|JM+nEis}NC-55x{@;t>TFqf5qI)vObr#8S#c zHSVf5f}9K60N?F@FiU>U9*1S3K;PRET@s+*|Kq{&uj(xm-{@pc@t@IJ8}TVR$POo{ zlpx*(d@IQ}o3t7|W#;cdU043}XfmVQ>x`6hEMQk?7m6_&F}WTED&R-7Dal~jS}hp{ zOMM|sC=G>F3(wORB|9q^7pcy@@Kr{P7v?Y?G56mp?>kXFv?D+0ZVa;@8>ag*ILvpOnf18=wES~6Fh(uGyOdhBX@@puGVyl&xt-|f6Pgl8(TLaCPH+&*F! z2g*vs6ZQ6~rOh5Ot1(r~Xj)FJjye6`30tQ;7EZGbq0!2JEy%a>ITy)bHZc0`DD#sM zcnS{M5e~WF9yVHsU8pSWgaz4}ey9QS--NXtalS(N<581PEOPK%VfXG(QpVb-BAmsm z6H>+_fSLT@9(mDySFbsV*^~vuz&(dT`$u62tEH=|0zp{ES$aHqD8BjXg*i0p;M^x zd@~xl)PM{JCYu!|gD+6W#ve>Y*U9c0F$lL-k2Q^~-!0`E{%m4@ zDeId4V+@Zdr4wb_AAIqj7H;<>p2mB_F}BjC?X@NO5k#uX-J|%wIoe_)Cw1KI9_YqW3F8+x`BQ87Kr;H!(=E`Pa0_zq5 zo18dd7ZW=3Fj-akgFsbo?$U0(K#z-09NC@XP#$_W&YwEAu<;wfLy$cBGq6U{LC_>m z8%^MoZkBk=_b}wl*IJ;%c$^`5+XZqZGH&ksY^x)Hl(#cyk z@7_7w3`W__?OyIKrD3uq+^c;;AQy^5z5!y3GXXeY|I;B6-DL-=B0Jy}B9NMLw8ZAo#!b!*}yu>mmX4 zhaCxTQy%qtLHZYSsL1ZEe!(NQZUGW7ok{{KOKY2hPg!xoD<);*UON%Z>#b6Y$M%n% z2i6%=;LahK7=ai#m%UFpiXN^*AJCRTkMbMl63o%VKLih0%Wn3e=NRls zfF+Jxzi^1mZ=sLB9OV47@BU(N^gsNL;tM{hDFvV2I!5!#7lmud(;cRBE)Nq+j;Fkn z1#EXDe|4Ju-5o?4{TE^RBvAkW literal 0 HcmV?d00001 diff --git a/src/std/rec/image/compress-2.gif b/src/std/rec/image/compress-2.gif new file mode 100644 index 0000000000000000000000000000000000000000..e4cbf62a7f500e418fe548c9785fa24831703ac6 GIT binary patch literal 4136 zcmeH``9BkmqjSBh8Vk z8k?(JIlt237$H|k=KJ{k5#L`vkMHvzcs-u4$Kz=Uu`n?7__lBVzF85Gy}dn=|L4Ex zfxSK9f051qxr*}kfqfz(6cMfeEd8em5ecD)zT`=8WnLRrLRQ0-SDF7l@tBGg6#Qvse)UKZX6_so*k9>8Q0g{5@YAuzVziTH z&C!O`IlpqQ?c%)p(sF1eqp9>n<=6MP(RV$aTY=v?UZ_~QT^p(T(M7y6>`Kk9nfaJ! zmZarsuw-A(bSQh+(@?uGTkC@WI)|dlwzEc>9Q-B+>NA!qOu~HViycikBt-N@EoPC!EDx5te@V^LPc?jom0~8tXC)Y%D#_2V){(rC zY$XR_Wt|g^JezgRew&$d|AOFLu0|~IY!1|D)HCaX7^EoOo524{Hf-3=rvl#@7Lsl= z@d`2FL3mY~QWXDO-q|)2UVQ87sfcv;_WsQI#K$?9iy z`x4Zh0cwuQFYmYODlcm}>%UO+$+SK%reg-^K`=P*p}l1P+Xc+QS9d0L}uFBc-ztIh!2SN7ol`_~BCqHyR;* zF^C>&Q=uFEPq)hRkX5dk^!hp((TkcAtpNn}p-+E&vI$QsL-$-tmELKaage&aHG9}! zdjnj3@yhQZQARl(shy_vhHFRgU+xw-W>=dRY{uhb4wf@^V>Yh;*;u|i*vSz6I;?e| zx&*_KnIdY{o!>9@3*)dlMKu^XFQRRURXN}xt_uEF!s1T+^|2iCt*xto1bo7ivmUR5 ziN<1jT^QkT|L4PS0LcCLN=#el8EJULb)nJ<)+~@IEepQB_h5zapqnYT>%av?tt34< z!UB9`eYi|sN%pnzjE=i6BP->l5mXL7iO}i552mLeyIH3;c^#&IR?=c#OZzVIJOdA(#S~7~cX?!Oie*d+e;sSF}suWh%4l*xB| zIS+S!e$%k=GI+ND8fpL8CufZoQOiHMVCC3kzoCNMEwdCw-H%(U)h$p?g4Hrdnoh*4 z7ejcCZiEqzu3i=G=}#EY_zj=_x;nW>%NrE%5AP79`f$p37b`{Q!WZGSMe4#Nuh&L0 zLo?>DU!ntpYzF|Nt2u8T{?i2y>l$nSmc!w|lS43+J40f;%gu|R&|;JV3nX6|Z(b4Z zY3(L(l=q^i_&YU~P5dCs*B7BHZqm9Y)ufSv$(pzOtn5G>Zo`KIS72f@(>j#MCdAcwA?c{6m!!*3B}{3B zGVN-w`@B{qn)b?O@!G817m`Y(9h|y5;d4!zoQIiQrkiEV?c0OW1H`)TN}6~iHq`fD z>O&Mr2F_Uq6!e|(Lzw;pI$`@gYmg%Mge`s4*U{5($Q;coz9Q;x^xk>sjrK;NeAB!O zg4``r688A=*`EV4e38>I8DRv2FWv z1gbfiF6C3u=pRtx5~)A;?|US0bTNXZTq z{Wk2ge^=ts8*+xqAs%d znp?5b*nE(11?pp%X^nb3Xl8Q5Fb(cyuN8H*5w*dDn~dR`kq1uIW6@e$IintPKi zPnS(%5{<{FzUOYAY|(4WXM|L0wzL=q3G>y3EJTKr;tCEFJ%4$5<*!l8dz@4KqM6+j zg6iqtGc)0wn!TY53rL}|SVOO7MWoP$&TjKYif%<|OdEE$yVJ}glHBMOTVeGVb;Eh#m@@2W>mWX-zJ78`cQ2tr)uksT5G z#oR?%EO7!BJrsewq>p;WLj?UBEd=5e2w(t?XeHYbmokS-;NfbW;u*6*1QC+!i<^|Q zqSV1iBN(Oup#T|vy3Wh3Bf)($ycidI9!F62MXPVc-|GlhQ44$dAX=53#CZ@`Bazf- z5cP_OYMCRH_$I;h6S%x2zFKULTGD%7a_wC5fJ90MIK?k9<$)7nVkBj9D`g6h`pqEq z2ivYsEqPc1+xFl|JubD1i2cZpJ$4_X?VG%2;P*=+$XG3ch6L>TVy4xg>vQsZYJU5- zQx4*7#G&BBqbZV*7e`CL$Dsu2QTc!PFXGvEWl0f02viAwUl9mVE&-^FV&whgRn^l^ z``M`T!RJfxnubCf5I=ozJwwqT^DHoP6Y$~>(N+%+zD~mZE5IAo$C?2#29OMM^+anR z7!nDw+y>t*K{}AE?n_!ak)ol7Ko^L$8!2k2>b3{ad$27N5}xSkm;-}Y>@&=HY>0S* z&-pQz+;2tlsUmna7&ewQFdY-imnAtp(Z@ajZ^ zj@&vml9+&q_92<$NQX*DX%JHM4-!M2jP=XO7GzRKbIbUsylrBs9~pIvd~B5L?oH85 zq=XhyEVz`>-{f1+%xXhQGsKdMmuL(zrpO0nmVEa`bx9ibTg|BfQ z5on}7bqsHPtRqobKkOlZ&hn$_eMSj#DaSf!mN>*t1ohl+x^o1LL8K0!gY9dlf7_&N zl8~)F?!W8kqVu$7-4OLzMyq&^Zjn4HHg6VB{Vth54GsAv8FrkE7n1Tn;PSgR-UC`bVD&^y;x3_Efb?a4I-0Fplm_|J9&(a JQaC1J{J)wmzxn_G literal 0 HcmV?d00001 From 128d2a93c8bbadc5df148c8c1284923daa2fa9a7 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Wed, 4 Sep 2019 17:25:28 +0200 Subject: [PATCH 099/281] Fixing waveform record documentation after review --- src/ioc/db/menuFtype.dbd.pod | 2 +- src/std/rec/waveformRecord.dbd.pod | 70 +++++------------------------- 2 files changed, 12 insertions(+), 60 deletions(-) diff --git a/src/ioc/db/menuFtype.dbd.pod b/src/ioc/db/menuFtype.dbd.pod index fd643f625..6b783dfec 100644 --- a/src/ioc/db/menuFtype.dbd.pod +++ b/src/ioc/db/menuFtype.dbd.pod @@ -10,7 +10,7 @@ =head1 Menu menuFtype -This menu is used for the C field of all record types. +This menu is used for the C and similar fields of many record types. =menu menuFtype diff --git a/src/std/rec/waveformRecord.dbd.pod b/src/std/rec/waveformRecord.dbd.pod index e40aa2a21..ca48e4792 100644 --- a/src/std/rec/waveformRecord.dbd.pod +++ b/src/std/rec/waveformRecord.dbd.pod @@ -1,4 +1,11 @@ -=pod +#************************************************************************* +# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# National Laboratory. +# Copyright (c) 2002 The Regents of the University of California, as +# Operator of Los Alamos National Laboratory. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. +#************************************************************************* =title Waveform Record (waveform) @@ -10,6 +17,8 @@ types. =cut +include "menuFtype.dbd" + menu(waveformPOST) { choice(waveformPOST_Always,"Always") choice(waveformPOST_OnChange,"On Change") @@ -115,64 +124,7 @@ The RARM field causes the device to re-arm when this field is set to 1. =head4 Possible data types for FTVL -=begin html - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IndexIdentifierChoice String
0menuFtypeSTRINGSTRING
1menuFtypeCHARCHAR
2menuFtypeUCHARUCHAR
3menuFtypeSHORTSHORT
4menuFtypeUSHORTUSHORT
5menuFtypeLONGLONG
6menuFtypeULONGULONG
7menuFtypeFLOATFLOAT
8menuFtypeDOUBLEDOUBLE
9menuFtypeENUMENUM
- - -=end html +=menu menuFtype =head3 Operator Display Parameters From 31811e53b33f944ef5fbba52c3b0a5c6d81f721f Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Wed, 4 Sep 2019 21:14:11 +0200 Subject: [PATCH 100/281] Compress record pod update after review - Revert "N to 1 Median" choice entry place - Convert images to PNG and update Makefile - Update record support routins definition based on epics7 recSup.h --- src/std/rec/Makefile | 8 +++----- src/std/rec/compressRecord.dbd.pod | 28 +++++++++++++++------------- src/std/rec/image/compress-1.jpg | Bin 16781 -> 0 bytes src/std/rec/image/compress-1.png | Bin 0 -> 2126 bytes src/std/rec/image/compress-2.gif | Bin 4136 -> 0 bytes src/std/rec/image/compress-2.png | Bin 0 -> 7608 bytes 6 files changed, 18 insertions(+), 18 deletions(-) delete mode 100644 src/std/rec/image/compress-1.jpg create mode 100644 src/std/rec/image/compress-1.png delete mode 100644 src/std/rec/image/compress-2.gif create mode 100644 src/std/rec/image/compress-2.png diff --git a/src/std/rec/Makefile b/src/std/rec/Makefile index 307662ebb..3f9c763b5 100644 --- a/src/std/rec/Makefile +++ b/src/std/rec/Makefile @@ -54,8 +54,6 @@ dbRecStd_SRCS += $(patsubst %,%.c,$(stdRecords)) HTMLS += $(patsubst %.dbd.pod,%.html,$(notdir $(wildcard ../rec/*Record.dbd.pod))) -vpath %.jpg $(USR_VPATH) .. $(SRC_DIRS) ../rec/image -vpath %.gif $(USR_VPATH) .. $(SRC_DIRS) ../rec/image - -HTMLS += compress-1.jpg -HTMLS += compress-2.gif +vpath %.png $(SRC_DIRS) +HTMLS += image/compress-1.png +HTMLS += image/compress-2.png diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index 90cacb77d..f0a586baa 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -29,9 +29,9 @@ menu(compressALG) { choice(compressALG_N_to_1_Low_Value,"N to 1 Low Value") choice(compressALG_N_to_1_High_Value,"N to 1 High Value") choice(compressALG_N_to_1_Average,"N to 1 Average") - choice(compressALG_N_to_1_Median,"N to 1 Median") choice(compressALG_Average,"Average") choice(compressALG_Circular_Buffer,"Circular Buffer") + choice(compressALG_N_to_1_Median,"N to 1 Median") } recordtype(compress) { @@ -134,9 +134,11 @@ holds the average of the first element of INP over N samples, VAL[1] holds the average of the next element of INP over N samples, and so on. The following shows the equation: +=for comment Latex form of equation bellow : VAL[i] \leftarrow \frac{1}{N}\sum_{n=1}^NINP_{n}[i] + =begin html - + =end html @@ -183,7 +185,7 @@ as in the following diagram: =begin html - + =end html @@ -246,57 +248,57 @@ WPTR is used by the dbGetlinks routines. =head4 init_record - static long init_record(compressRecord *prec, int pass) + long (*init_record)(struct dbCommon *precord, int pass) Space for all necessary arrays is allocated. The addresses are stored in the appropriate fields in the record. =head4 process - static long process(compressRecord *prec) + long (*process)(struct dbCommon *precord) See L =head4 special - static long special(DBADDR *paddr, int after) + long (*special)(struct dbAddr *paddr, int after) This routine is called when RSET, ALG, or N are set. It performs a reset. =head4 cvt_dbaddr - static long cvt_dbaddr(DBADDR *paddr) + long (*cvt_dbaddr)(struct dbAddr *paddr) This is called by dbNameToAddr. It makes the dbAddr structure refer to the actual buffer holding the result. =head4 get_array_info - static long get_array_info(DBADDR *paddr, long *no_elements, long *offset) + long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset) Obtains values from the circular buffer referenced by VAL. =head4 put_array_info - static long put_array_info(DBADDR *paddr, long nNew) + long (*put_array_info)(struct dbAddr *paddr, long nNew); Writes values into the circular buffer referenced by VAL. =head4 get_units - static long get_units(DBADDR *paddr, char *units) + long (*get_units)(struct dbAddr *paddr, char *units); Retrieves EGU. =head4 get_precision - static long get_precision(DBADDR *paddr, long *precision) + long (*get_precision)(const struct dbAddr *paddr, long *precision); Retrieves PREC. =head4 get_graphic_double - static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd) + long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p); Sets the upper display and lower display limits for a field. If the field is VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower @@ -305,7 +307,7 @@ the field type will be used. =head4 get_control_double - static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd) + long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p); Sets the upper control and the lower control limits for a field. If the field is VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower diff --git a/src/std/rec/image/compress-1.jpg b/src/std/rec/image/compress-1.jpg deleted file mode 100644 index 9ce8f4145887e0361016b4cf3c7543d00d83cbc5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16781 zcmeHt2RvL|yYFT&`Vd{TC?VQJ5+VshB!~zig6PqW(Mt@5(M2Z`LJ}euxPfnNyxLf{tyzYzF^z<);s46N<#?S!sbJ39GT zyI9+h*~7oF1zMM%i2Py;{~gE0FPncM@C$)o2>e3e7Xp8afB|3)*pq*DWY@wqa@rAa z0({7K7qXDq1KCGG@8sm;<8cuRb@P_BwsW_!m$h|wg(9szpmMUOp@5PK(!<&oVecbk zWA6xeQx@N-Z4eiN+bN41%j=xh@wj5|1iu#GWp5Cmd)qbuVSB+&Tm{BNuY|maboFqx z_pug2y1KY|UqmVk|5p1&a{A|Es4z^)%g*8At*aV;lpyDnh5u-apP!$s-&t9AFGr}{ zg$oy;r_VsooRJ}ykn#3+^RY(CxOt2GQNdMvZ(A?8hY#G{P3UKZ);8|GKFY$rzHqyX z4%QCxHg5FBSeZy8b_d>)%+Ty&IV-`jI&yX&kr$fT^izsHwm-)HJkUFfBbR1DRvc zb3j-aS-ClQdAK>axsD5npE%Ah#?QqqEGsM~aY{;BidP7F7Akp0TvAH%XC)M1T3UKK zdUgf|c1b>NKFPm)ks1M3TA+mTI*39Tpk$>0u~Lv)0YS1ajhY<0`x(Cb{9KO-)4(+))IP-vd;v)W=T9U8Z5vw+0J)vY!b}$)y!hD{tbs z)r%E9YvUD0N6*Q{&BH5pQe5JcLsr^cGMHuSwc*``WZQgs#4ggQVi2f}aPnU2#>Fe}Y|KmHPh?p-`mC z3ah_2d`|mNg?Wr{2TQQ8GLyNrus+X4w3Hq*G8Z(L5DbMqS`U^QNY}&$mleJrlX*R# z3Y*bYF?}_CBydSEIzZ!*CwB^$Ug8D){fUSBl{;NIOc2OwTCf=QD6RY@?9i+;?M}C6 zR>yY%NZ@h)vuB|+P6E=I zpY&Ll%bh9PMyC^99x`e$8$b71@{(#nJAX#Ho^xktLNIz<;Y*d&J(OeWAm|0PUnJ zJ%?M9AyB+AM!X$*+_c+s2F-vEAYSsLlciIOh>wr10pr@-(ak1@YUrNm91<|qMs8f@ z{_0FYQW;DD+0JA%?vvJie?z9JF-_Q?psBxM<+IFNmG=IHnR9^oswdo+`@t#pITmyY zfb2)s?nW3&qrka$0~A#X#t>k0d>gK~#pCVRaOn0SlHL9#=h-@E;!Upz+EcX!Qk^GAjdeG1YiZwL}e>A)G1u#Mk0}aWOeKXC)PrD^LhT8yWxmO+>BaF z%80fGr|yVdQ^P`Bbky3dF%cmhwMnt&unAF6wGxZ+<(;z2N16FkSm#mX(Zt*;2}p80 z=mD4LtFr@tO;9_Bs;IMXdI@4AfKEK3BwH_S5_7)GT_p06`O)Ut_^5Whk3bNEI&%02 z33!ROy@Q24D>GZ}B>`?DmE+$nl;StR>t0%o_ClEaKpBADID~-0>P5|2NcL;?=IXH_ z!wu;8TkXSHf)7uBqn$H;jTdhW5DeLltmrA>1uB0K+2q6TY#E*xuSSAdfqOr@fzMvd6bdSyvQT1rL4DTb{mLq zVyWblj89!QXGHVW^L_deGkfQAF~_N0la^!3G+(ltYr7f|{uE0$!}pE9HdL&=6>k@S zK5Tz^Edp^okXe4AohA*K{g6zMxLu&- zFQ}VI0t`RI_VrOui1sTQ>aXjVmg>#wh0NmPW;lBm2Sne{*ge+ab)OI9=lp#I=p4|W4wZjixa0bdm~JP%DE#)X^7?tu487htjKJ641FIpUYkLsui;Y4 z<;@my#uf;cA4EE~?ACK&+oGZi(h-5&SFd&NJ>l2d6F*sx!aqY$1`ok_=#CXU+to~U zYG2smvpbxId9QP=Z`bGuGE^Ul zkDJyOyboik>4U1h7}=6>qg~)poj$t6x@<+idQq7KM9YttKySyCY`Dyy5h zG*=`X&u5%L{1S=5+xj9TPOMd((vQwgY^+~VST>^)0JC#6p=uX~m zp%BupI-f|_j#M%40r#^TN1;IYnz6MHc$Kze4~L|O?cY{l-B{5fi}+!|`v<&x7XgXa zuIOe{uGp)B*kpLQRnXJ&h|X(rsRLoOO|x~+XU?}IFv}hw@w5_D|(RdR)2)Qgu&hs*?pGX;mJf#t&u3)lk;6 z`!}5J?rW64=aFRSN`};f=T!x-IAtzm&ngS^>uF{bynO;QPhe};Wrlp3X6;;;w9qyv z@7-Q5+c7IFkrA@!(>WVyC@?ozG)EN0Gehs!v$`?|sc8caS`oc3iN@vT@rglBlncd} zY-Xo=!FR*ZDly{MTA|CH?rh&gJ4Nqmybb_;y$f&P3+7)r$gh7^fRFxK`#xEn-Qm-W zpPVA-s&w-O2r>@?+};D2mWrmrd}OQ0N-Rbs#)$ooYp z@y`2uF(41d-bJ|JhAjH}L2SLlQQo$8Ha+t2DsDHC{@erMPoLXQCOzst{M<2P`Lz^( z(APa9T7SCo?yCHQF6ZaP*DVIdkBK_hSJ5L>qn#fRudGp2px0sYR3 z_6m)rltz2&p76FFigQkO?7JKDnd8UA8mEas0!p;NuwM{Kxz(l?{HV};9`A2SsLstx~m5n zcytIk;#Uak=bigZRzXYX6zlW26=awO`)ZcfJE}U+;cMj6*=Ag9Ca@D1{JEm8wqBpK- zZm)Z$CWeK`k@pO>Dy(e!u{OGfp|U5R`rj@Q37Y~GuvogeVa+_PS30>STBR+Fys2t0 z7bLhVL@>#8YgXcTwpp46e@udAyPqX^fM8$rKqS`8DD~4DgX~9!HYh%i3w(|PnLC1b zOG`3M%Y)8B4p-1b%^ZkpUY$0PD?Nb(EXCo&i3emmQkFB|yLJ#q`OeM01Ua1gMFVx#h+IdeaaHbp6j4jG107W0}P3e#5kn%af!N#apLBw!;aMPeAk{o4;hwXhiU{V^2z8(7E=)5oE~^SkqfT3~RJSIG z5Lp>X06eDYmiHTR+y)7-<>|%`Pj=PX>_47Jdg6X#_%VS4Z>dB#vpXPfe++SuJmq_0 zuC*YAo9H-jB-Kx5dw+0%vJ5oBeV-0*MXdQw?koM_e#0&3nkxx7p~64{hL2|-(O(1( z&TEi>WTxn&Kut0ikDY-DlYlO5yf+E3zCZ%DwMsYs=kIfvL73s@;wNSecs&AV8TEWE zU0GiBOeo*}Y9a>Tpklfa%!D$mCNs2Nrd3hXwFjZTESRtSR7J`V&k-WWvUJgkA$bi5 zqwN%~zm3nG4lghs}H9Ly7@BhIo}Jkk~{% zg)LQD${n6WcY<22cDA^PVTe(JCkYUy`A7opE|X0*DLZzQCUa}AIZOQAqZhX`k-eGc zB^ue4qWHqsB|uA3tA`e6nh_IfvzHJ~EOix~Be(SjQmrnaPW3qAHac|7W_ic!Ol3X} zl(|ZUDJ|2EWuyl4aYCkN@;5&7_P0k z+>M=_6dUK$7c#uO1Wezg8X!-GGyl=rRG*N3q)h@oAQqvcengEj-XI$i&@-O{$#Zvi z-Cn&QyJ3Il?tS}-T6D}>=ull;n-v#I-yX--LgeoyC`hkWne^MYzc?$3<80wbFq4~h z+}QddH7eEW`h>^^8Ef`O51Aq@TWsb$DpHab7K!^g5Vx`?FmdwO7)2T!ebzhT-PwMI z8pWv)bw4*}ubZNmhI1eBGLP0)ZO?v1@zg9)j5Z2{g(%;uH^zTzBn}7&0%2Fv08I5p@iG&r zWl^=?u9CO?RbesTi_D16QmqQ1Rd*yX@mr~>=G1#Xa5EMLw_WuN2kS2T7hVD*-j^AF zk-o?m!QJ6v%U=i@Twxfmc`YpqmE{&S!o4l+c%z?6DE_L~SWMZP#D|>FK!S|91^1bY z&4asnsrPu(V^L;7JcqsCSFW#2SxxkSZLuW4^dnBNrIz2(z+-DlQ?!Mii`L{FBSgIo z+3};61c(?Xz{=4}Uc(Je2l8dnD0#&5<)*fhgqkRsMVTrM8a;1I(4j2ZD>8`Ddu?^V z_m*N?XJ_mVe2**DlfON@c>0=Xy2cHo`3cC z{Ezn{-pMN4nTcboMuP<`CSw|QkGgYyC~GZI12%*!xb-L4z2-{iu~hKGc^TKx{eo0J ziQRQQYfD3{apOT!tnYrXIDXY<&rjD%H}>+Lrrufp5IzY)kkm8m?z30K9umMdWjQSD zq$HCM8(I72(Q<(`d?LvR_B6n_zg(S<<;Bgs4nAiNRt?I~M#>PupYA?Oz39pZs(m_Crf8U zuc3Y~_$<~k3DeEo^?Vg~Nv-vaHYk1SZV0xF$#5;V9%+Eyc0y!BU5} zO_T2XcDlGd-<*3>Rg&L2q{&IS90So8oG3=SltdjZRRMJz?FwhZF(p1(!WEx4RRhBYV`kZs ztcd)$koNKtE$kTP_7kJ}zQr_TZbiRKK5LjoBc%~vt*vN?TH;g8 z$scKN@Ws0izcgyO&jiWbVSe8Is6ypLINkszV=+F3-)pSrtIbk$o!qZFo+=e-kzA^w zg(*c#0^83{j+sH3Ovb)n>(ge+(^y{=dn`niYNbN_+^{K+>|f;~M#}_2nC7?+&||KA zT@0^A4zDpPYXp$pr8^v3|84>60r#FChFceWx72C9hdWoY{d1{os;59)^x;LvpiD|E z+N(bd72Z+|ojUh;KTMLblJEUA^WgeHLIm&23~%dubYUweqf`s1iWvpayz>MmY-RHl z=YwXZmJ_9B8nnZWak(gnK%EaJ4Ku?ASMJH=>FXq zp$FXO^BXz-Ns#|zIb(N5ZRt4NUg-QwO;em61BwdA6}E$TcBRFNHQ~ju`3>gS3hD3* zO-!fw^-OnHBtR-x-VVI>x$nC3QODP8ush@4yJmoZ+oV)&#FRLZmDnLu^@et2l!dVi zA2P){lh2wfKlmPHE|`uu-QngvR##OILKsi6NTbZkko!AQt6G>;;$>~l`76ocE;ahY z)d9Pi|Iir*6q&wDDnN|6WCm9{a;&|mnPU9>-V7`vvTE#<14)HR;Y}ft4Qwv*Nzrfg zz@vA~4)5Pi*Y;d+S@BYlg-W@H|_9SoN%TDZfYL`RD}c<8-_lv*L~_l zBZB+J;yV_S)O$rD(WCxWo=4Px-v`<7e5AJ?=S7YPPR`so+PgZ%sRKs{wcp7(Md>QL z%jW5;H?`050m?ckKiu$aKOSS|dR+Z!0!_Q#!&kE_m)o~io>wng86m4% zkvoweJJ^)t@-CJ6ewOkGoHkBFw@4yIh+*~QgID8y75rDg9~^~tazBRGY%zqPJkZaOhK5+lGH4OKpRd1;(JK| zcli)T74osvXM>yM^NI=wWtmY9liku5&LE|!keLpLlLe=cEt5eA6TQvi+av@tV zwIp?Z_CSC-i0$yCdIDSPt*x)E+H1|JM+nEis}NC-55x{@;t>TFqf5qI)vObr#8S#c zHSVf5f}9K60N?F@FiU>U9*1S3K;PRET@s+*|Kq{&uj(xm-{@pc@t@IJ8}TVR$POo{ zlpx*(d@IQ}o3t7|W#;cdU043}XfmVQ>x`6hEMQk?7m6_&F}WTED&R-7Dal~jS}hp{ zOMM|sC=G>F3(wORB|9q^7pcy@@Kr{P7v?Y?G56mp?>kXFv?D+0ZVa;@8>ag*ILvpOnf18=wES~6Fh(uGyOdhBX@@puGVyl&xt-|f6Pgl8(TLaCPH+&*F! z2g*vs6ZQ6~rOh5Ot1(r~Xj)FJjye6`30tQ;7EZGbq0!2JEy%a>ITy)bHZc0`DD#sM zcnS{M5e~WF9yVHsU8pSWgaz4}ey9QS--NXtalS(N<581PEOPK%VfXG(QpVb-BAmsm z6H>+_fSLT@9(mDySFbsV*^~vuz&(dT`$u62tEH=|0zp{ES$aHqD8BjXg*i0p;M^x zd@~xl)PM{JCYu!|gD+6W#ve>Y*U9c0F$lL-k2Q^~-!0`E{%m4@ zDeId4V+@Zdr4wb_AAIqj7H;<>p2mB_F}BjC?X@NO5k#uX-J|%wIoe_)Cw1KI9_YqW3F8+x`BQ87Kr;H!(=E`Pa0_zq5 zo18dd7ZW=3Fj-akgFsbo?$U0(K#z-09NC@XP#$_W&YwEAu<;wfLy$cBGq6U{LC_>m z8%^MoZkBk=_b}wl*IJ;%c$^`5+XZqZGH&ksY^x)Hl(#cyk z@7_7w3`W__?OyIKrD3uq+^c;;AQy^5z5!y3GXXeY|I;B6-DL-=B0Jy}B9NMLw8ZAo#!b!*}yu>mmX4 zhaCxTQy%qtLHZYSsL1ZEe!(NQZUGW7ok{{KOKY2hPg!xoD<);*UON%Z>#b6Y$M%n% z2i6%=;LahK7=ai#m%UFpiXN^*AJCRTkMbMl63o%VKLih0%Wn3e=NRls zfF+Jxzi^1mZ=sLB9OV47@BU(N^gsNL;tM{hDFvV2I!5!#7lmud(;cRBE)Nq+j;Fkn z1#EXDe|4Ju-5o?4{TE^RBvAkW diff --git a/src/std/rec/image/compress-1.png b/src/std/rec/image/compress-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3001ce9f548d1c1761ddb5e3aa9d7bff8951ac90 GIT binary patch literal 2126 zcmV-U2(kBxP)KaTLv5q{=E;Kw8Ub%ei<@GBRLG1q}05ho(d{BndJ{`=Dyb0w^X-yeZh zlT|YE+y9@&n2V8{%Bo3-SeV8Be<~MUmEiyN~_}cL@_DAOb7iP7ppWvoRkFMjl;744!MOPG`V{ zl`sis^UF|2|4*PB!U}?s5_$%J(Gjoq{^wnhd#teg9oXGseT|~U8DNKb?6I-ZL_yqG z=hAp$GtpkjyR-$!Hb=gES5Q4xwhyQ6lR~LfPdqf1%w{29@*icSE-=#YJY!p!Ut#>? ziR#RxyPMIm2Z=KqcZ9q~MAa&n{OO-rac;3s3MRBz5v7)B8a~o6Dn(o>*keUx7G@ds zyTUV0RASA70CW{3F3_!M5*DF$wa`w@tIlaEFjG@_g+^)|Hb_#{dEe;#go;CHop3 zua?cRC~<#f?6=sb8kZyUeZ_^1nahVSRU|?h;*AB`S;Wif zYve{yjs}dfO0(dXhIgP}$Y*wPdUxnQ#)5Fgep6#V($B=r^~tuw=g2rS5s(hAkUSK$ zqMd0s`JA>-DnJFJE3x9j(y^qYU{^-{bRK;Y%e@OS_Us})g5KCiYNC_KsCP-cB_7$nZT6`dk_5HJ zw`i>l5X-%{{X^nlRHwKLNXkJ<@dW#TtL>z>i%WtLM zW}ifwIq;!E5*&es=1MZSF%AvW@=sjKQwI_F&i&H$Oig6Or7gM9a7LJC(!L9f39A4` z_(*DFPakJwXVi;$*idO~Mafno*jFxhq`f&Fwm_X~Ty38(!%8FGso@wwoYYG7X5!O| zgOM=kd2*ZqgKh1b?hO4K-EI0w6G_Pp|8)DTa+iinoP5?mP-g@QCOy!VKJ@;Tm{}v$jX4U1uOYhIUrmnXC4xkA`u`E;1es{Z@0U?_i%r?$B`Ri&&^L z!YsL&+&d!x3=21{Ci+##_fv$q!fl1gjKwUE8`nE(Cob{ie!L4&h}uhLB;FMy_+J0b zLcXnokvnh)`@Ahtn5;mED7#Lphc((a?OfHEAgE7mbvNeiVdl)D!Qh!yBdnOSARtz> zm9!ZIPCeO!Q9p&p!~WMI!^%tulaU3_%neVj2DQrce%?jcM>xnqxLj2Wb~zl^YlL!2x7OJmF; zy~7hdIx)sP7**0ocWn$B)=l|D)5-Z@7x;mA|Ociy#zllG3Lc!-)mtS^I}+- z#!SMV6<3o_Tu)vEAnbe|YGE2P34%m895BU$CBDa>eQ~hF0ZuQJ4yPQ07Z#>53n0SyldSk^pROa`(l1MLuq$iK2K4Kc2qHpE zyqg;Zy9)VOn8r+i0P`C|xV5a9rPXf+{n`alBL3_$n?e2sgQV5yZ9L070000vbVXQn zY+-a|cmP&GOj~JPAY5!^W^`e4a&LDaTxN1%V|y`udro~^b9HTBdu}~3eO^vUPEcQa zZhc#6UHK97cmMzZ4s=CWbaG{LZ)|mRX>V=-F*PuXMnC2N000bhMObuWZ)|UJ05C8x zFfcH}pZ1{u000(rMObuGZ)S9NVRB^vY+-a|crtKqXD(xJZAt~H3IG5A07*qoM6N<$ Ef^+cjn*aa+ literal 0 HcmV?d00001 diff --git a/src/std/rec/image/compress-2.gif b/src/std/rec/image/compress-2.gif deleted file mode 100644 index e4cbf62a7f500e418fe548c9785fa24831703ac6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4136 zcmeH``9BkmqjSBh8Vk z8k?(JIlt237$H|k=KJ{k5#L`vkMHvzcs-u4$Kz=Uu`n?7__lBVzF85Gy}dn=|L4Ex zfxSK9f051qxr*}kfqfz(6cMfeEd8em5ecD)zT`=8WnLRrLRQ0-SDF7l@tBGg6#Qvse)UKZX6_so*k9>8Q0g{5@YAuzVziTH z&C!O`IlpqQ?c%)p(sF1eqp9>n<=6MP(RV$aTY=v?UZ_~QT^p(T(M7y6>`Kk9nfaJ! zmZarsuw-A(bSQh+(@?uGTkC@WI)|dlwzEc>9Q-B+>NA!qOu~HViycikBt-N@EoPC!EDx5te@V^LPc?jom0~8tXC)Y%D#_2V){(rC zY$XR_Wt|g^JezgRew&$d|AOFLu0|~IY!1|D)HCaX7^EoOo524{Hf-3=rvl#@7Lsl= z@d`2FL3mY~QWXDO-q|)2UVQ87sfcv;_WsQI#K$?9iy z`x4Zh0cwuQFYmYODlcm}>%UO+$+SK%reg-^K`=P*p}l1P+Xc+QS9d0L}uFBc-ztIh!2SN7ol`_~BCqHyR;* zF^C>&Q=uFEPq)hRkX5dk^!hp((TkcAtpNn}p-+E&vI$QsL-$-tmELKaage&aHG9}! zdjnj3@yhQZQARl(shy_vhHFRgU+xw-W>=dRY{uhb4wf@^V>Yh;*;u|i*vSz6I;?e| zx&*_KnIdY{o!>9@3*)dlMKu^XFQRRURXN}xt_uEF!s1T+^|2iCt*xto1bo7ivmUR5 ziN<1jT^QkT|L4PS0LcCLN=#el8EJULb)nJ<)+~@IEepQB_h5zapqnYT>%av?tt34< z!UB9`eYi|sN%pnzjE=i6BP->l5mXL7iO}i552mLeyIH3;c^#&IR?=c#OZzVIJOdA(#S~7~cX?!Oie*d+e;sSF}suWh%4l*xB| zIS+S!e$%k=GI+ND8fpL8CufZoQOiHMVCC3kzoCNMEwdCw-H%(U)h$p?g4Hrdnoh*4 z7ejcCZiEqzu3i=G=}#EY_zj=_x;nW>%NrE%5AP79`f$p37b`{Q!WZGSMe4#Nuh&L0 zLo?>DU!ntpYzF|Nt2u8T{?i2y>l$nSmc!w|lS43+J40f;%gu|R&|;JV3nX6|Z(b4Z zY3(L(l=q^i_&YU~P5dCs*B7BHZqm9Y)ufSv$(pzOtn5G>Zo`KIS72f@(>j#MCdAcwA?c{6m!!*3B}{3B zGVN-w`@B{qn)b?O@!G817m`Y(9h|y5;d4!zoQIiQrkiEV?c0OW1H`)TN}6~iHq`fD z>O&Mr2F_Uq6!e|(Lzw;pI$`@gYmg%Mge`s4*U{5($Q;coz9Q;x^xk>sjrK;NeAB!O zg4``r688A=*`EV4e38>I8DRv2FWv z1gbfiF6C3u=pRtx5~)A;?|US0bTNXZTq z{Wk2ge^=ts8*+xqAs%d znp?5b*nE(11?pp%X^nb3Xl8Q5Fb(cyuN8H*5w*dDn~dR`kq1uIW6@e$IintPKi zPnS(%5{<{FzUOYAY|(4WXM|L0wzL=q3G>y3EJTKr;tCEFJ%4$5<*!l8dz@4KqM6+j zg6iqtGc)0wn!TY53rL}|SVOO7MWoP$&TjKYif%<|OdEE$yVJ}glHBMOTVeGVb;Eh#m@@2W>mWX-zJ78`cQ2tr)uksT5G z#oR?%EO7!BJrsewq>p;WLj?UBEd=5e2w(t?XeHYbmokS-;NfbW;u*6*1QC+!i<^|Q zqSV1iBN(Oup#T|vy3Wh3Bf)($ycidI9!F62MXPVc-|GlhQ44$dAX=53#CZ@`Bazf- z5cP_OYMCRH_$I;h6S%x2zFKULTGD%7a_wC5fJ90MIK?k9<$)7nVkBj9D`g6h`pqEq z2ivYsEqPc1+xFl|JubD1i2cZpJ$4_X?VG%2;P*=+$XG3ch6L>TVy4xg>vQsZYJU5- zQx4*7#G&BBqbZV*7e`CL$Dsu2QTc!PFXGvEWl0f02viAwUl9mVE&-^FV&whgRn^l^ z``M`T!RJfxnubCf5I=ozJwwqT^DHoP6Y$~>(N+%+zD~mZE5IAo$C?2#29OMM^+anR z7!nDw+y>t*K{}AE?n_!ak)ol7Ko^L$8!2k2>b3{ad$27N5}xSkm;-}Y>@&=HY>0S* z&-pQz+;2tlsUmna7&ewQFdY-imnAtp(Z@ajZ^ zj@&vml9+&q_92<$NQX*DX%JHM4-!M2jP=XO7GzRKbIbUsylrBs9~pIvd~B5L?oH85 zq=XhyEVz`>-{f1+%xXhQGsKdMmuL(zrpO0nmVEa`bx9ibTg|BfQ z5on}7bqsHPtRqobKkOlZ&hn$_eMSj#DaSf!mN>*t1ohl+x^o1LL8K0!gY9dlf7_&N zl8~)F?!W8kqVu$7-4OLzMyq&^Zjn4HHg6VB{Vth54GsAv8FrkE7n1Tn;PSgR-UC`bVD&^y;x3_Efb?a4I-0Fplm_|J9&(a JQaC1J{J)wmzxn_G diff --git a/src/std/rec/image/compress-2.png b/src/std/rec/image/compress-2.png new file mode 100644 index 0000000000000000000000000000000000000000..5ce46e0413c9c606467ac552a9b7a07630dc0113 GIT binary patch literal 7608 zcmbVRc{tSH_a93ll(A$9lcu6%Uz4>o%48Qcm>AhbL$*Q4HW;*63R#luCS_-=W67>; zA!_VR2s3v2y+@z#^L&5L@A*By<&Syheeaxe&%Nh;&g*sVnJ7bj9rj}a$3P$u`^_8L z#vl+K3HUHDGXXP;t4G5?Afcd}+FGW*$fegy6|WW9v|nrnEqIq23tR;S-T0uh(VL;j zYmv0sk;0I6RwL*)D?LXri19Qi#EJ2-zQwC>5fB}-CWxM6D+Fx9_|H#KjMAj2-**N6 ziUxyC7&toM-!tGp=kGq=`6^Q+zrl9hpu^(C{qzJ-q-6fXx9lN*m<5^qHQI9*)%W+v z4({v0>~zeGoQ+t9ADja849s=>tLTcAk@~jueDzrV_v}f*jrD+$z;cIq7Y;H0)zU7q zE%~#REUXS@^*%-$_(>b}>>{HubHcI*e#E5>8GGtGM{pyEo^KV@afvQOlU`zOhpN7P z>sdO7*vTxB-`c^~bgVQ_D}_7Z(n z*2HGgQvt?{%!7QZe&zvtl@z<;=yUw^bj-fMhSi)nS?O(A5)PinJzuQfpM}`^G&ysO zrh#B}esu2x4}J9#4uYn4Wegqq&e{{$)ZCHAjlUyFI-IX$kXhuRk9z=Psl1@^zoTm4 zSk-%Xg$~`SC>jiQM}k}-hod>b^8A{E*WvR2gE6!#o#mfnO{0m}{vDSl zij@}{Hw%9R%s}V@jzWbI<$SA#6PK9in9rUL2HO&^by0$#2lEhigM;n$`4fqj$IqFr zU0zcTy0B`5dbDOV@aukdUMeRvT%aZ$9~l(w>1bkRi8DA~T3}5)Qh$-16NIKd@?Xsx3CBh?OQD4o{7`X z6=oSy&031pHDJopJYObT8igCRy!$bAA&^0L+nVS#t6(9AcCDcen$Ebd8nSp zjdpAuKE@g>U0?!cQ%_}yfMAvbH+Tf{e%7`zK=fW;L0voXd`mhKaLcejMRz+^1_j^0 zA#YS(Tj-)*0Lk3?O>r2qCi0b5g9Yem-&p~V^>Xq(bzCLhd{qehPioeGE&8^i=VZsX z2Gddh(tC;9x-^;HGy!R{!k5pCjGs>TxP0oKyJS)=VK?R8_R#NAbrP<>pfX>_Y4%xP z{`TsWi`8a|W4zllM7eDAaOd;*Tr--pzC>oXy^P&*H5-9>r8vdsZ*=>~cKZwBtIDrh zj`;8V84kb*>?n*V>0LsUD-KkyA`yNw(^*5W{mDY;w`RpS-LbOa)$#58*y+HM5>?6S z)pmRLt8{NG);D8Yu&fi#r-*9Z<8{dC7A%>y?zWtJu`~%&Tm)fTUbiT3$CAr{H?2&K zYsSiu{y>@#!VMMOvGrZf58C)vcSW$n$Dqp(zS+*(5KHT1NFlJjjXT9K)H2pZY+qp7 zhIq2L3R*JK*@9Iot4WtSP$M-^Td?CUHFiue)ebD&=j6EoX%c7F)JQSRb?6vP)R~Ax z*bt|HI9pQqCfm}A?W=w2`GZ`UXd!%eW1>e@Xh!sl^Ml@EcGB_vgA4nZ{Y6%{a|3m_ zQIkR>%-!{pm#0!gQqB5sXBQS)<~(!>A&w7-Q&yY*S#xk*DPVs1DaiO|e+AhMwwC~l z-==ow%lyu(a^HfJ6H7GsclSf}V<=5UF7UU>@r;Oerpk9h$=4pdFSmgMwcuJ;aBn9JGEpq6r9Ufib0Q@-(0 z1<+?jZ+|oWiMUQnjJRJ6Iiq~&kf*vW#t#-GeB^Ral$w$^Uq8)FnD=q7wC z+V!}->5RAfZ&FqaHX$jJvg%lqgMRW4XgNX@lJWVs-1;3? z_2zM}NC13$m!a#HIxW9x@bKqUsR)w^4LFOmgGEa>bCKft;#Iu3JBHlGPe6?C092GA zWgWqSPqg-+ID$3l=>g5O%v-i5s_KGbLX71BsKw3e=C*H>3?M_Jcb##AYf(8Fmuif! z=|{vp`iI)Q>G?`ui-1r6CAx0_2)jMH6-L8nI_6OTpuHo?!M-{sa9vwLjMIW)>JiM) zb5xojfa7Ur<)hI>YGzlZPDD?mGDnn$i)Lt=HKEW8e(-9Mr(Pm`^Q~9fV=GP-#RQA=$N;_joAG= zNoQ8|-)i3=t6-cKjXIeKx?xq403!;Evd5wXUE&k_yFy7-d6K;*%i@Kp=A69ne?Iw? zf?9aBosmHJzd5EED?$CDmfTE+DcPOD=rv6e#4ujjsj^^#H0qf9u@K9c&tm=Jydjof zJ?f=NmOStZS`l;-N~6q}MEUU$AW)vhfB+tuFSzp|{E*hYSbp%-m#w*!a$1ed}q3;QE3NANn}l?y*a7zBUdLxTpb zp>wBk+r;J8uj0K`xwin_odSceAa9l-U;CQZ2g~0?8ZhU(*v2H7`l^>3t zaCS~3tnuqS{H2Qws3YON1@=4hp*cn)-y_54c^oEs+e>CzbtHQ4L{FQUO#e#kQ+{G= zzDAnnarm_yYSw}cZA1~L8z;@yRK7c--_fxn@5FvIS8p197rsdo5@7BNmq8h%OqJFh z>jSp+I^OD2Ogtj3l)Jt7UE5dj3^XInK)ZPF=(nTA5#XaCvvIzHcb2iaz(Gd~MG9M2 zt+V+Udg*|=fzB}W8b&DWyL@iA`E+(tpS%t7q#5m@0MoSn<`S&PY;HC{?7Ive)Tt}o z915cT(vrEy_NX1ZetYSh?J+*6zEz_Zp3@A~j8ud+3a#2d`Dk?*w*6;vspn( zSEV9e^_9)xzy{Z*2){dzHrcuh%ha^`z06CBADbN9%9{;ErZZ~W+7RC~GfpW8_ss2( z5l2T{=KK0Ggc^c&{y@!~e#y+KY#!`ZrlqfK8|xK6!_0&tr+Y78Rvj^x<@=SKfZb|8 zEthOx*%mV{LaJ?S6LO^LR8UX(mnyh|%dG9mg_DgbCoq2EoG$VU3TF6oX5tFv=M<|) z&#MaTrY>)ej!Xqv)u!HePs{c5+13SArmZB01M25CJz#jB!~yY*(CE!=#2I9MzC`J# zR>e|_Y{z0Famb2C>D-GR>;QSwCBLJ1V&u1Y_kCBHRVUEKpV940SB4GDIWpb0F{hYGrQo<4H6hu6Ah_%0v z;A}nIdkfQ6)FR3rKGV(U$Za2XjUjWyaAK~tzYAw54uTcsv>*Gbs&>)J=3e149l_&5 z46>S1(0LMC(o8&k7%IVYK60MrnuC9BhcJYLEU-#k(QMgC#=-PR8~)Lt0|qQRpnBN#@>q zm<{Gzg`uV@3cRI<){F|-XnL6=N^}(C!l!U`zS8%~P5Fn)Pga#8Y3Xes*Z-ZxIbd*& zr7c5T6_y5<>T?~UnNKfLL(vv(4=r^#T*mihXbqk!VgpjZ#eq zkrP7s%qc)9qde`k*A7i&dXM(VfuS?=`KQAl&LEJN<8dY}x%N2oUg*eLr{DcF0d)o2 zIuGIMB=g>JViUIV*$zH-Sg<=q2Fa*XGMl*Gp{x+#+~zy0>LGzo(`n29VItQiKL56;-OH5p{K6KL*n>*v8kFMZX%pqm*3@dTe|N$ce?pTh%DMDAwZ z5aVp+Qxqeekv~D0qQLmu(Xp~ijJmf53ST?Tuu-Dlriv-T(ry&746Bk5`>) zyX=b2=U7OD>r*;&Mh0DFNcmg2l1OLnk=haeH=CQyBej#ecW|RR_LQ|B$`_AeV$Tp7 zRrprv&v?6K4T`C>cpI2><@!UlxP}1S;|e2ODH4E`2h=o`D1)I$qoEqL!&m)NEbdfJ zn~p>VT6eJcE$u-iIu$4xmB2eTsm@1DBp~ITv^Y9}3FOk0DnC{|6AEUH;Yv#xYclN; zgo&GciO`@4q<@0Z&EfX(Frj$yPD4gEz znlyng?23+WXaY~(`$XQRg`CnTk0^>LUVx|+Ef394G7xG-XVZ{dPCu$9k@jGsgMMMe zw|f5SN4>wyaTZ{XpI6QPG6xI599&sn&;Ml(pxjjOdi8o}Ref=fx)I+F8F87s^13vy zT>18Zc-#Zi`|>eoQl%w(WU?GXjUUT?-R*P6RSmyC`oQI@UB7rnnPZZ{$EP?M5=YU6 zCrP);-rXE@D=Rx`Z*~4I3X8Ohfa)YrFooMGeg?Z@J>pi7PZ8yAK*vrEp;f%B+J` zHz+bdVEKzi;^^AS$(6$H_1*z-^Xmx|mDnvObFf3v`3%c2UH}l0H@e%36OP+2#%&!$ z9gz3YJ+-sO>apV%ZoW|`Fitm-p9|;WM%QseGuhW4X1hw0Vu|$+${$Jl3+#TGUdW9w z;qt#{x3hv>nXjh&U?z|XiXPQtVynzQrUZ~2IksN_4HEYdVEx#;>Iyrbp})qM%J8zb zxUB<6$`V=(L%oe!3>fmDs@N)QQ2m~yoWP-N|M`W)LIK@2a}|vd zDaA>M&b^zevHmf74ZOu7VPGD6O+*fCAmwV05XJn~N&sTr9J11Llz`&d94_2AzVpBw zyiMes5L1EGJsWMZP}2z4*hjznp2ISw1tO?q>ZL!ie{lqh5QfH`sdbpBZ145|+&`s& zS#){S$I-LqWY*0Gl{|x@)qu1{OdJR%*q+q!PY>-39j*$CrTb^3OwWfFw4io4PrWhi z($UlSe_^Tr3Hy~g<7Fc>oNQk`*_G>qjDnj^e6G1$VzG5+u6{KN`|3LDwyF%uFRGdI zm)c9hy6&l{XbXf=7Zs@v3@qP}l7@RczBRYY@zsMH^+| zwk)cPpWGwLOMUwlMZ6jAd83wUJ=w0&^GCoWWhy0};fbjTVmrb2Ug`l0NhMdlK_SER zz0mWeA0{Zbfg(}JQMRx=kznwMA;R+(xryS)>GS;FAExD$!CjwlE*mf zwV}GTDL~?;*a9Sl%>IOeV7IgeIec9%-iyz*NYU0ij>{JfMpBDRVQ*eVb8@XUVnsC# zs_w&I_}2PgS?Tu`6uJjm;OQInKO(<=K1EEJhVeJ^kr4Ex9_3d4#;N|z_ME|thP;K@ zK6#ZhDc8A9#v4Gnd9jqkxUhZz>~U=8!<9q$;Q-oxF|6D#k$sga3}2iM%pTsCj4mC3 z8zpY0^@}GXO+L0_b4eLB%CV@62Xn0hh5TO!Sr!y{f=XItNR}8sdwBNmxBL)R0*T+h zBp8`4&l?{OmXiG4zTwDSU8W;N`M_aV26E+?O+ah3 zwxxhpU7Y$A%_T$Pxou}~m>^FhfIcnkBIn=h6%TMJ7cb~c|C?6qK=l@DdiL01n_3)z zXmisXmdggkLq{oSJ}bvexc?SwzzB_VsQYTG4dHJ+W<> zOk;tat*Dcw}a)z@H`AR>ij8zYal~I2fIYipr~ZDR z#t-d1r}4kvz3<>FIE2z!oP5C_HyY+n{=|ot+#X;hcz{R6EO5Ti($|%`wmwV(g2xF@ z=&nTSNI7J7{*Xr5c~LxS6(jM#^2FJf`r+3i$1e33CJmyd9bd+g-&vzRA`PH+X@^(b8|u)hWe3%z`P?Xy&;Pfz}u3`Ou10;+k-(mG>5X z8rqyWa=Kr?D>Ip^5{I~?9J@{&)Es=m_%kLD;+5bwdRja*cPx9W^=+V0hd9CQlc!dI|o@W+&^cuPh_fR-n3xXu@U9(^6c6nPDA-PrqMpo>4x zLm7AHuF%rNa_ketRjCK`)gPt}wT|h*KQL3G|sv z5!!goD(5VxOy}sCPm!=^I)zY^|IOw+{`Nj*fn4o^cQYOKmNZ`h7qX(`)rZ;HxCT)7 z>^b|;!wk;^`etTkkrRI*(GP&cHO`M(%$nAqkV^N<$@TjImO^NS1PhnG@w7W-6`x1b+)s+c!C z(j)ks1`X_E!7)6tuuJEe7lB4sKFfq&N!xvwwmPkRnW3aK2~gJWP{!eCQmQs>I}^*I=j>pE9Nmy`kaI0w^3kxwq1|D>7-3!3P&s{IprdT z@JeTKUO}On^m5FnVUrL<(0M#OPUq`&BpLk{R)`r^KD3Fj;37S(Fs(DKtskn{Wbb21kAl-j({ zR^w+MnI!Mmn5c2pY8Xdc2)Z0BR6`%^obq2j{0^}|GE3t&qUgVH`F|3 z-=EfDW&=u#6HRs0GirJ@4!y%qg_NdR>K)>2JHwu6x&b8Owl90X?@AHd#r<9|!DI1y z1uM`N<>h!LL2Ho)Ya#&= Date: Wed, 4 Sep 2019 14:06:52 +0200 Subject: [PATCH 101/281] Rename README to .md --- documentation/{README.html => README.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{README.html => README.md} (100%) diff --git a/documentation/README.html b/documentation/README.md similarity index 100% rename from documentation/README.html rename to documentation/README.md From 1cf831939ae0d2a43df04e739c6e29a29444012a Mon Sep 17 00:00:00 2001 From: Niamh Dougan Date: Wed, 4 Sep 2019 14:22:10 +0200 Subject: [PATCH 102/281] Convert HTML in README.md to Github Markdown --- documentation/README.md | 543 ++++++++++++++++++++-------------------- 1 file changed, 268 insertions(+), 275 deletions(-) diff --git a/documentation/README.md b/documentation/README.md index 982079e01..149b8fae9 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -1,152 +1,153 @@ - - - - -README - EPICS Base Installation Instructions - - -
-

Installation Instructions

-

EPICS Base Release 3.15.6


-
-
-

Table of Contents

- -
+# Installation Instructions -

What is EPICS base?

-
The Experimental Physics and Industrial Control Systems - (EPICS) is an extensible set of software components and tools with - which application developers can create a control system. This control - system can be used to control accelerators, detectors, telescopes, or - other scientific experimental equipment. EPICS base is the set of core - software, i.e. the components of EPICS without which EPICS would not - function. EPICS base allows an arbitrary number of target systems, IOCs - (input/output controllers), and host systems, OPIs (operator - interfaces) of various types.
+## EPICS Base Release 3.15.6 -

What is new in this release?

-
Please check the RELEASE_NOTES file in the distribution for - description of changes and release migration details.
+ -

Copyright

-
Please review the LICENSE file included in the - distribution for legal terms of usage.
+----- -

Supported platforms

+### Table of Contents -
The list of platforms supported by this version of EPICS base - is given in the configure/CONFIG_SITE file. If you are trying to build - EPICS Base on an unlisted host or for a different target machine you - must have the proper host/target cross compiler and header files, and - you will have to create and add the appropriate new configure files to - the base/configure/os/directory. You can start by copying existing - configuration files in the configure/os directory and then make changes - for your new platforms.
+ - [What is EPICS base?](#0_0_1) + - [What is new in this release?](#0_0_2) + - [Copyright](#0_0_3) + - [Supported platforms](#0_0_4) + - [Supported compilers](#0_0_5) + - [Software requirements](#0_0_6) + - [Host system storage requirements](#0_0_7) + - [Documentation](#0_0_8) + - [Directory Structure](#0_0_10) + - [Build related components](#0_0_11) + - [Building EPICS base (Unix and Win32)](#0_0_12) + - [Example application and extension](#0_0_13) + - [Multiple host platforms](#0_0_14) -

Supported compilers

+----- -
This version of EPICS base has been built and tested using the host - vendor's C and C++ compilers, as well as the GNU gcc and g++ compilers. The GNU - cross-compilers work for all cross-compiled targets. You may need the C and C++ - compilers to be in your search path to do EPICS builds; check the definitions - of CC and CCC in base/configure/os/CONFIG.<host>.<host> if you have - problems.
+### What is EPICS base? -

Software requirements

+The Experimental Physics and Industrial Control Systems (EPICS) is an +extensible set of software components and tools with which application +developers can create a control system. This control system can be +used to control accelerators, detectors, telescopes, or other +scientific experimental equipment. EPICS base is the set of core +software, i.e. the components of EPICS without which EPICS would not +function. EPICS base allows an arbitrary number of target systems, +IOCs (input/output controllers), and host systems, OPIs (operator +interfaces) of various types. -
GNU make
- You must use GNU make, gnumake, for any EPICS builds. Set your path - so that a gnumake version 3.81 or later is available. +### What is new in this release? -

Perl
- You must have Perl version 5.8.1 or later installed. The EPICS configuration - files do not specify the perl full pathname, so the perl executable must - be found through your normal search path.

+Please check the RELEASE\_NOTES file in the distribution for +description of changes and release migration details. -

Unzip and tar (Winzip on WIN32 systems)
- You must have tools available to unzip and untar the EPICS base - distribution file.

+### Copyright -

Target systems
- EPICS supports IOCs running on embedded platforms such as VxWorks - and RTEMS built using a cross-compiler, and also supports soft IOCs running - as processes on the host platform.

+Please review the LICENSE file included in the distribution for legal +terms of usage. -

vxWorks
- You must have vxWorks 5.5.x or 6.x installed if any of your target systems are - vxWorks systems; the C++ compiler for vxWorks 5.4 is now too old to support. - The vxWorks installation provides the cross-compiler and header files needed to - build for these targets. The absolute path to and the version number of the - vxWorks installation must be set in the - base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its - target-specific overrides.

+### Supported platforms -

Consult the vxWorks - 5.x or vxWorks - 6.x EPICS web pages about and the vxWorks documentation for information - about configuring your vxWorks operating system for use with EPICS.

+The list of platforms supported by this version of EPICS base is given +in the configure/CONFIG\_SITE file. If you are trying to build EPICS +Base on an unlisted host or for a different target machine you must +have the proper host/target cross compiler and header files, and you +will have to create and add the appropriate new configure files to the +base/configure/os/directory. You can start by copying existing +configuration files in the configure/os directory and then make +changes for your new platforms. -

RTEMS
- For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or later.

+### Supported compilers -

GNU readline or Tecla library
- GNU readline and Tecla libraries can be used by the IOC shell to - provide command line editing and command line history recall and edit. - GNU readline (or Tecla library) must be installed on your target system - when COMMANDLINE_LIBRARY is set to READLINE (or TECLA) for that target. - EPICS (EPICS shell) is the default specified in CONFIG_COMMON. A - READLINE override is defined for linux-x86 in the EPICS distribution. - Comment out COMMANDLINE_LIBRARY=READLINE in - configure/os/CONFIG_SITE.Common.linux-x86 if readline is not installed - on linux-x86. Command-line editing and history will then be those - supplied by the os. On vxWorks the ledLib command-line input library is - used instead.

-
+This version of EPICS base has been built and tested using the host +vendor's C and C++ compilers, as well as the GNU gcc and g++ +compilers. The GNU cross-compilers work for all cross-compiled +targets. You may need the C and C++ compilers to be in your search +path to do EPICS builds; check the definitions of CC and CCC in +base/configure/os/CONFIG.<host>.<host> if you have problems. -

Host system storage requirements

+### Software requirements -
The compressed tar file is approximately 1.6 MB in size. The - distribution source tree takes up approximately 12 MB. Each host target will - need around 40 MB for build files, and each cross-compiled target around 20 - MB.
+**GNU make** +You must use GNU make, gnumake, for any EPICS builds. Set your path so +that a gnumake version 3.81 or later is available. -

Documentation

-
EPICS documentation is available through the - EPICS website at Argonne. -

Release specific documentation can also be found in the base/documentation - directory of the distribution.

+**Perl** +You must have Perl version 5.8.1 or later installed. The EPICS +configuration files do not specify the perl full pathname, so the perl +executable must be found through your normal search path. -

Directory Structure

-

Distribution directory structure:

+**Unzip and tar (Winzip on WIN32 systems)** +You must have tools available to unzip and untar the EPICS base +distribution file. -
+**Target systems**  
+EPICS supports IOCs running on embedded platforms such as VxWorks and
+RTEMS built using a cross-compiler, and also supports soft IOCs
+running as processes on the host platform.
+
+**vxWorks**  
+You must have vxWorks 5.5.x or 6.x installed if any of your target
+systems are vxWorks systems; the C++ compiler for vxWorks 5.4 is now
+too old to support. The vxWorks installation provides the
+cross-compiler and header files needed to build for these targets. The
+absolute path to and the version number of the vxWorks installation
+must be set in the base/configure/os/CONFIG\_SITE.Common.vxWorksCommon
+file or in one of its target-specific overrides.
+
+Consult the [vxWorks 5.x](https://epics.anl.gov/base/tornado.php) or
+[vxWorks 6.x](https://epics.anl.gov/base/vxWorks6.php) EPICS web pages
+about and the vxWorks documentation for information about configuring
+your vxWorks operating system for use with EPICS.
+
+**RTEMS**  
+For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or
+later.
+
+**GNU readline or Tecla library**  
+GNU readline and Tecla libraries can be used by the IOC shell to
+provide command line editing and command line history recall and edit.
+GNU readline (or Tecla library) must be installed on your target
+system when COMMANDLINE\_LIBRARY is set to READLINE (or TECLA) for
+that target. EPICS (EPICS shell) is the default specified in
+CONFIG\_COMMON. A READLINE override is defined for linux-x86 in the
+EPICS distribution. Comment out COMMANDLINE\_LIBRARY=READLINE in
+configure/os/CONFIG\_SITE.Common.linux-x86 if readline is not
+installed on linux-x86. Command-line editing and history will then be
+those supplied by the os. On vxWorks the ledLib command-line input
+library is used instead.
+
+### Host system storage requirements
+
+The compressed tar file is approximately 1.6 MB in size. The
+distribution source tree takes up approximately 12 MB. Each host
+target will need around 40 MB for build files, and each cross-compiled
+target around 20 MB.
+
+### Documentation
+
+EPICS documentation is available through the [EPICS
+website](https://epics.anl.gov/) at Argonne.
+
+Release specific documentation can also be found in the
+base/documentation directory of the distribution.
+
+### Directory Structure
+
+#### Distribution directory structure:
+
+``` 
         base                    Root directory of the base distribution
         base/configure          Operating system independent build config files
         base/configure/os       Operating system dependent build config files
         base/documentation      Distribution documentation
         base/src                Source code in various subdirectories
         base/startup            Scripts for setting up path and environment
-
+``` -

Install directories created by the build:

-
+#### Install directories created by the build:
+
+``` 
         bin                     Installed scripts and executables in subdirs
         cfg                     Installed build configuration files
         db                      Installed data bases
@@ -159,37 +160,37 @@
         lib                     Installed libraries in arch subdirectories
         lib/perl                Installed perl modules
         templates               Installed templates
-
-
+``` -

Build related components

-
+### Build related components -

base/documentation directory - contains setup, build, and install - documents

-
+#### base/documentation directory - contains setup, build, and install documents
+
+``` 
         README.1st           Instructions for setup and building epics base
         README.html          html version of README.1st
         README.darwin.html   Installation notes for Mac OS X (Darwin)
         RELEASE_NOTES.html   Notes on release changes
         KnownProblems.html   List of known problems and workarounds
-
+``` -

base/startup directory - contains scripts to set environment and path

-
+#### base/startup directory - contains scripts to set environment and path
+
+``` 
         EpicsHostArch       Shell script to set EPICS_HOST_ARCH env variable
         unix.csh            C shell script to set path and env variables
         unix.sh             Bourne shell script to set path and env variables
         win32.bat           Bat file example to configure win32-x86 target
         windows.bat         Bat file example to configure windows-x64 target
-
+``` -

base/configure directory - contains build definitions and rules

-
+#### base/configure directory - contains build definitions and rules
+
+``` 
         CONFIG                Includes configure files and allows variable overrides
         CONFIG.CrossCommon    Cross build definitions
         CONFIG.gnuCommon      Gnu compiler build definitions for all archs
-        CONFIG_ADDONS         Definitions for <osclass> and DEFAULT options
+        CONFIG_ADDONS         Definitions for <osclass> and DEFAULT options
         CONFIG_APP_INCLUDE    
         CONFIG_BASE           EPICS base tool and location definitions
         CONFIG_BASE_VERSION   Definitions for EPICS base version number
@@ -209,175 +210,167 @@
         RULES_EXPAND          
         RULES_FILE_TYPE       
         RULES_TARGET          
-        RULES_TOP             Rules specific to a <top> dir (uninstall and tar)
+        RULES_TOP             Rules specific to a <top> dir (uninstall and tar)
         Sample.Makefile       Sample makefile with comments
-
+``` -

base/configure/os directory - contains os-arch specific definitions

-
-        CONFIG.<host>.<target>      Specific host-target build definitions
-        CONFIG.Common.<target>      Specific target definitions for all hosts
-        CONFIG.<host>.Common        Specific host definitions for all targets
+#### base/configure/os directory - contains os-arch specific definitions
+
+``` 
+        CONFIG.<host>.<target>      Specific host-target build definitions
+        CONFIG.Common.<target>      Specific target definitions for all hosts
+        CONFIG.<host>.Common        Specific host definitions for all targets
         CONFIG.UnixCommon.Common    Definitions for Unix hosts and all targets
         CONFIG.Common.UnixCommon    Definitions for Unix targets and all hosts
         CONFIG.Common.vxWorksCommon Specific host definitions for all vx targets
-        CONFIG_SITE.<host>.<target> Site specific host-target definitions
-        CONFIG_SITE.Common.<target> Site specific target defs for all hosts
-        CONFIG_SITE.<host>.Common   Site specific host defs for all targets
-
+ CONFIG_SITE.<host>.<target> Site specific host-target definitions + CONFIG_SITE.Common.<target> Site specific target defs for all hosts + CONFIG_SITE.<host>.Common Site specific host defs for all targets +``` -
+### Building EPICS base (Unix and Win32) -

Building EPICS base (Unix and Win32)

-
+#### Unpack file -

Unpack file

-
Unzip and untar the distribution file. Use WinZip on Windows - systems. -
+systems. -

Set environment variables

-
-Files in the base/startup directory have been provided to - help set required path and other environment variables. +#### Set environment variables -

EPICS_HOST_ARCH
- Before you can build or use EPICS R3.15, the environment variable - EPICS_HOST_ARCH must be defined. A perl script EpicsHostArch.pl in the - base/startup directory has been provided to help set EPICS_HOST_ARCH. - You should have EPICS_HOST_ARCH set to your host operating system - followed by a dash and then your host architecture, e.g. solaris-sparc. - If you are not using the OS vendor's c/c++ compiler for host builds, - you will need another dash followed by the alternate compiler name - (e.g. "-gnu" for GNU c/c++ compilers on a solaris host or "-mingw" - for MinGW c/c++ compilers on a WIN32 host). See configure/CONFIG_SITE - for a list of supported EPICS_HOST_ARCH values.

+Files in the base/startup directory have been provided to help set +required path and other environment variables. -

PERLLIB
- On WIN32, some versions of Perl require that the environment - variable PERLLIB be set to <perl directory location>.

+**EPICS\_HOST\_ARCH** +Before you can build or use EPICS R3.15, the environment variable +EPICS\_HOST\_ARCH must be defined. A perl script EpicsHostArch.pl in +the base/startup directory has been provided to help set +EPICS\_HOST\_ARCH. You should have EPICS\_HOST\_ARCH set to your +host operating system followed by a dash and then your host +architecture, e.g. solaris-sparc. If you are not using the OS +vendor's c/c++ compiler for host builds, you will need another dash +followed by the alternate compiler name (e.g. "-gnu" for GNU c/c++ +compilers on a solaris host or "-mingw" for MinGW c/c++ compilers on +a WIN32 host). See configure/CONFIG\_SITE for a list of supported +EPICS\_HOST\_ARCH values. -

PATH
- As already mentioned, you must have the perl executable and you may - need C and C++ compilers in your search path. For building base you - also must have echo in your search path. For Unix host builds you also - need ln, cpp, cp, rm, mv, and mkdir in your search path and /bin/chmod - must exist. On some Unix systems you may also need ar and ranlib in - your path, and the C compiler may require as and ld in your path. On - solaris systems you need uname in your path.

+**PERLLIB** +On WIN32, some versions of Perl require that the environment +variable PERLLIB be set to <perl directory location>. -

LD_LIBRARY_PATH
+**PATH** +As already mentioned, you must have the perl executable and you may +need C and C++ compilers in your search path. For building base you +also must have echo in your search path. For Unix host builds you +also need ln, cpp, cp, rm, mv, and mkdir in your search path and +/bin/chmod must exist. On some Unix systems you may also need ar and +ranlib in your path, and the C compiler may require as and ld in +your path. On solaris systems you need uname in your path. - R3.15 shared libraries and executables normally contain the full path - to any libraries they require. - However, if you move the EPICS files or directories from their build-time - location then in order for the shared libraries to be found at runtime - LD_LIBRARY_PATH must include the full pathname to - $(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH) when invoking executables, or - some equivalent OS-specific mechanism (such as /etc/ld.so.conf on Linux) - must be used. - Shared libraries are now built by default on all Unix type hosts.

-
+**LD\_LIBRARY\_PATH** +R3.15 shared libraries and executables normally contain the full +path to any libraries they require. However, if you move the EPICS +files or directories from their build-time location then in order +for the shared libraries to be found at runtime LD\_LIBRARY\_PATH +must include the full pathname to +$(INSTALL\_LOCATION)/lib/$(EPICS\_HOST\_ARCH) when invoking +executables, or some equivalent OS-specific mechanism (such as +/etc/ld.so.conf on Linux) must be used. Shared libraries are now +built by default on all Unix type hosts. -

Do site-specific build configuration

-
+#### Do site-specific build configuration -Site configuration
- To configure EPICS, you may want to modify the default definitions - in the following files: -
+**Site configuration**  
+To configure EPICS, you may want to modify the default definitions
+in the following files:
+
+``` 
         configure/CONFIG_SITE      Build choices. Specify target archs.
         configure/CONFIG_SITE_ENV  Environment variable defaults
         configure/RELEASE          TORNADO2 full path location
-
+``` - Host configuration
- To configure each host system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - changed to CONFIG_SITE. +**Host configuration** +To configure each host system, you may override the default +definitions by adding a new file in the configure/os directory with +override definitions. The new file should have the same name as the +distribution file to be overridden except with CONFIG in the name +changed to CONFIG\_SITE. -
-        configure/os/CONFIG.<host>.<host>      Host build settings
-        configure/os/CONFIG.<host>.Common      Host common build settings
-
+``` + configure/os/CONFIG.<host>.<host> Host build settings + configure/os/CONFIG.<host>.Common Host common build settings +``` -Target configuration
- To configure each target system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - replaced by CONFIG_SITE. This step is necessary even if the host system - is the only target system. -
-        configure/os/CONFIG.Common.<target>     Target common settings
-        configure/os/CONFIG.<host>.<target>     Host-target settings
-
-
+**Target configuration** +To configure each target system, you may override the default +definitions by adding a new file in the configure/os directory with +override definitions. The new file should have the same name as the +distribution file to be overridden except with CONFIG in the name +replaced by CONFIG\_SITE. This step is necessary even if the host +system is the only target system. -

Build EPICS base

-
After configuring the build you should be able to build - EPICS base by issuing the following commands in the distribution's root - directory (base): -
+``` 
+        configure/os/CONFIG.Common.<target>     Target common settings
+        configure/os/CONFIG.<host>.<target>     Host-target settings
+```
+
+#### Build EPICS base
+
+After configuring the build you should be able to build EPICS base
+by issuing the following commands in the distribution's root
+directory (base):
+
+``` 
         gnumake clean uninstall
         gnumake
-
+``` - The command "gnumake clean uninstall" - will remove all files and directories generated by a previous build. - The command "gnumake" will build and install everything for the - configured host and targets. +The command "gnumake clean uninstall" will remove all files and +directories generated by a previous build. The command "gnumake" +will build and install everything for the configured host and +targets. -

It is recommended that you do a "gnumake clean uninstall" at the - root directory of an EPICS directory structure before each complete - rebuild to ensure that all components will be rebuilt. -

-
+It is recommended that you do a "gnumake clean uninstall" at the +root directory of an EPICS directory structure before each complete +rebuild to ensure that all components will be rebuilt. -

Example application and extension

-
A perl tool, makeBaseApp.pl is included in the distribution - file. This script will create a sample application that can be built - and then executed to try out this release of base. +### Example application and extension -

- Instructions for building and executing the 3.15 example application - can be found in the section "Example Application" of Chapter 2, - "Getting Started", in the "IOC Application Developer's Guide" for this - release. The "Example IOC Application" section briefly explains how to - create and build an example application in a user created <top> - directory. It also explains how to run the example application on a - vxWorks ioc or as a process on the host system. - By running the example application as a host-based IOC, you will be - able to quickly implement a complete EPICS system and be able to run channel - access clients on the host system. +A perl tool, makeBaseApp.pl is included in the distribution file. This +script will create a sample application that can be built and then +executed to try out this release of base. -

- A perl script, - makeBaseExt.pl, is included in the distribution file. This script will - create a sample extension that can be built and executed. The - makeBaseApp.pl and makeBaseExt.pl scripts are installed into the - install location bin/<hostarch> directory during the base build. -

+Instructions for building and executing the 3.15 example application +can be found in the section "Example Application" of Chapter 2, +"Getting Started", in the "IOC Application Developer's Guide" for this +release. The "Example IOC Application" section briefly explains how to +create and build an example application in a user created <top> +directory. It also explains how to run the example application on a +vxWorks ioc or as a process on the host system. By running the example +application as a host-based IOC, you will be able to quickly implement +a complete EPICS system and be able to run channel access clients on +the host system. -

Multiple host platforms

-
You can build using a single EPICS directory structure on - multiple host systems and for multiple cross target systems. The - intermediate and binary files generated by the build will be created in - separate subdirectories and installed into the appropriate separate - host/target install directories. EPICS executables and perl scripts are - installed into the $(INSTALL_LOCATION)/bin/<arch> directories. - Libraries are installed into $(INSTALL_LOCATION)/lib/<arch>. - The default definition for $(INSTALL_LOCATION) is $(TOP) - which is the root directory in the distribution directory structure, - base. Created object files are stored in O.<arch> source - subdirectories, This allows objects for multiple cross target - architectures to be maintained at the same time. To build EPICS base - for a specific host/target combination you must have the proper - host/target C/C++ cross compiler and target header files and the - base/configure/os directory must have the appropriate configure files. -
- - +A perl script, makeBaseExt.pl, is included in the distribution file. +This script will create a sample extension that can be built and +executed. The makeBaseApp.pl and makeBaseExt.pl scripts are installed +into the install location bin/<hostarch> directory during the base +build. + +### Multiple host platforms + +You can build using a single EPICS directory structure on multiple +host systems and for multiple cross target systems. The intermediate +and binary files generated by the build will be created in separate +subdirectories and installed into the appropriate separate host/target +install directories. EPICS executables and perl scripts are installed +into the `$(INSTALL_LOCATION)/bin/` directories. Libraries are +installed into $`(INSTALL_LOCATION)/lib/`. The default +definition for `$(INSTALL_LOCATION)` is `$(TOP)` which is the root +directory in the distribution directory structure, base. Created +object files are stored in O.<arch> source subdirectories, This +allows objects for multiple cross target architectures to be +maintained at the same time. To build EPICS base for a specific +host/target combination you must have the proper host/target C/C++ +cross compiler and target header files and the base/configure/os +directory must have the appropriate configure files. From 177c377b816887c0e050494bac48ed0a06b2dff2 Mon Sep 17 00:00:00 2001 From: Niamh Dougan Date: Wed, 4 Sep 2019 15:08:32 +0200 Subject: [PATCH 103/281] Amend documentation filenames in README Also deleted old README.1st --- documentation/README.1st | 346 --------------------------------------- documentation/README.md | 3 +- 2 files changed, 1 insertion(+), 348 deletions(-) delete mode 100644 documentation/README.1st diff --git a/documentation/README.1st b/documentation/README.1st deleted file mode 100644 index 807ba2ade..000000000 --- a/documentation/README.1st +++ /dev/null @@ -1,346 +0,0 @@ - Installation Instructions - - EPICS Base Release 3.15.6 - - -------------------------------------------------------------------------- - - Table of Contents - - * What is EPICS base? - * What is new in this release? - * Copyright - * Supported platforms - * Supported compilers - * Software requirements - * Host system storage requirements - * Documentation - * Directory Structure - * Build related components - * Building EPICS base (Unix and Win32) - * Example application and extension - * Multiple host platforms - - -------------------------------------------------------------------------- - - What is EPICS base? - - The Experimental Physics and Industrial Control Systems (EPICS) is an - extensible set of software components and tools with which application - developers can create a control system. This control system can be used - to control accelerators, detectors, telescopes, or other scientific - experimental equipment. EPICS base is the set of core software, i.e. the - components of EPICS without which EPICS would not function. EPICS base - allows an arbitrary number of target systems, IOCs (input/output - controllers), and host systems, OPIs (operator interfaces) of various - types. - - What is new in this release? - - Please check the RELEASE_NOTES file in the distribution for description - of changes and release migration details. - - Copyright - - Please review the LICENSE file included in the distribution for legal - terms of usage. - - Supported platforms - - The list of platforms supported by this version of EPICS base is given - in the configure/CONFIG_SITE file. If you are trying to build EPICS Base - on an unlisted host or for a different target machine you must have the - proper host/target cross compiler and header files, and you will have to - create and add the appropriate new configure files to the - base/configure/os/directory. You can start by copying existing - configuration files in the configure/os directory and then make changes - for your new platforms. - - Supported compilers - - This version of EPICS base has been built and tested using the host - vendor's C and C++ compilers, as well as the GNU gcc and g++ compilers. - The GNU cross-compilers work for all cross-compiled targets. You may - need the C and C++ compilers to be in your search path to do EPICS - builds; check the definitions of CC and CCC in - base/configure/os/CONFIG.. if you have problems. - - Software requirements - - GNU make - You must use GNU make, gnumake, for any EPICS builds. Set your path so - that a gnumake version 3.81 or later is available. - - Perl - You must have Perl version 5.8.1 or later installed. The EPICS - configuration files do not specify the perl full pathname, so the perl - executable must be found through your normal search path. - - Unzip and tar (Winzip on WIN32 systems) - You must have tools available to unzip and untar the EPICS base - distribution file. - - Target systems - EPICS supports IOCs running on embedded platforms such as VxWorks and - RTEMS built using a cross-compiler, and also supports soft IOCs running - as processes on the host platform. - - vxWorks - You must have vxWorks 5.5.x or 6.x installed if any of your target - systems are vxWorks systems; the C++ compiler for vxWorks 5.4 is now too - old to support. The vxWorks installation provides the cross-compiler and - header files needed to build for these targets. The absolute path to and - the version number of the vxWorks installation must be set in the - base/configure/os/CONFIG_SITE.Common.vxWorksCommon file or in one of its - target-specific overrides. - - Consult the vxWorks 5.x or vxWorks 6.x EPICS web pages about and the - vxWorks documentation for information about configuring your vxWorks - operating system for use with EPICS. - - RTEMS - For RTEMS targets, you need RTEMS core and toolset version 4.9.2 or - later. - - GNU readline or Tecla library - GNU readline and Tecla libraries can be used by the IOC shell to provide - command line editing and command line history recall and edit. GNU - readline (or Tecla library) must be installed on your target system when - COMMANDLINE_LIBRARY is set to READLINE (or TECLA) for that target. EPICS - (EPICS shell) is the default specified in CONFIG_COMMON. A READLINE - override is defined for linux-x86 in the EPICS distribution. Comment out - COMMANDLINE_LIBRARY=READLINE in - configure/os/CONFIG_SITE.Common.linux-x86 if readline is not installed - on linux-x86. Command-line editing and history will then be those - supplied by the os. On vxWorks the ledLib command-line input library is - used instead. - - Host system storage requirements - - The compressed tar file is approximately 1.6 MB in size. The - distribution source tree takes up approximately 12 MB. Each host target - will need around 40 MB for build files, and each cross-compiled target - around 20 MB. - - Documentation - - EPICS documentation is available through the EPICS website at Argonne. - - Release specific documentation can also be found in the - base/documentation directory of the distribution. - - Directory Structure - - Distribution directory structure: - - base Root directory of the base distribution - base/configure Operating system independent build config files - base/configure/os Operating system dependent build config files - base/documentation Distribution documentation - base/src Source code in various subdirectories - base/startup Scripts for setting up path and environment - - Install directories created by the build: - - bin Installed scripts and executables in subdirs - cfg Installed build configuration files - db Installed data bases - dbd Installed data base definitions - doc Installed documentation files - html Installed html documentation - include Installed header files - include/os Installed os specific header files in subdirs - include/compiler Installed compiler-specific header files - lib Installed libraries in arch subdirectories - lib/perl Installed perl modules - templates Installed templates - - Build related components - - base/documentation directory - contains setup, build, and install documents - - README.1st Instructions for setup and building epics base - README.html html version of README.1st - README.darwin.html Installation notes for Mac OS X (Darwin) - RELEASE_NOTES.html Notes on release changes - KnownProblems.html List of known problems and workarounds - - base/startup directory - contains scripts to set environment and path - - EpicsHostArch Shell script to set EPICS_HOST_ARCH env variable - unix.csh C shell script to set path and env variables - unix.sh Bourne shell script to set path and env variables - win32.bat Bat file example to configure win32-x86 target - windows.bat Bat file example to configure windows-x64 target - - base/configure directory - contains build definitions and rules - - CONFIG Includes configure files and allows variable overrides - CONFIG.CrossCommon Cross build definitions - CONFIG.gnuCommon Gnu compiler build definitions for all archs - CONFIG_ADDONS Definitions for and DEFAULT options - CONFIG_APP_INCLUDE - CONFIG_BASE EPICS base tool and location definitions - CONFIG_BASE_VERSION Definitions for EPICS base version number - CONFIG_COMMON Definitions common to all builds - CONFIG_ENV Definitions of EPICS environment variables - CONFIG_FILE_TYPE - CONFIG_SITE Site specific make definitions - CONFIG_SITE_ENV Site defaults for EPICS environment variables - MAKEFILE Installs CONFIG* RULES* creates - RELEASE Location of external products - RULES Includes appropriate rules file - RULES.Db Rules for database and database definition files - RULES.ioc Rules for application iocBoot/ioc* directory - RULES_ARCHS Definitions and rules for building architectures - RULES_BUILD Build and install rules and definitions - RULES_DIRS Definitions and rules for building subdirectories - RULES_EXPAND - RULES_FILE_TYPE - RULES_TARGET - RULES_TOP Rules specific to a dir (uninstall and tar) - Sample.Makefile Sample makefile with comments - - base/configure/os directory - contains os-arch specific definitions - - CONFIG.. Specific host-target build definitions - CONFIG.Common. Specific target definitions for all hosts - CONFIG..Common Specific host definitions for all targets - CONFIG.UnixCommon.Common Definitions for Unix hosts and all targets - CONFIG.Common.UnixCommon Definitions for Unix targets and all hosts - CONFIG.Common.vxWorksCommon Specific host definitions for all vx targets - CONFIG_SITE.. Site specific host-target definitions - CONFIG_SITE.Common. Site specific target defs for all hosts - CONFIG_SITE..Common Site specific host defs for all targets - - Building EPICS base (Unix and Win32) - - Unpack file - - Unzip and untar the distribution file. Use WinZip on Windows systems. - - Set environment variables - - Files in the base/startup directory have been provided to help set - required path and other environment variables. - - EPICS_HOST_ARCH - Before you can build or use EPICS R3.15, the environment variable - EPICS_HOST_ARCH must be defined. A perl script EpicsHostArch.pl in the - base/startup directory has been provided to help set EPICS_HOST_ARCH. - You should have EPICS_HOST_ARCH set to your host operating system - followed by a dash and then your host architecture, e.g. - solaris-sparc. If you are not using the OS vendor's c/c++ compiler for - host builds, you will need another dash followed by the alternate - compiler name (e.g. "-gnu" for GNU c/c++ compilers on a solaris host - or "-mingw" for MinGW c/c++ compilers on a WIN32 host). See - configure/CONFIG_SITE for a list of supported EPICS_HOST_ARCH values. - - PERLLIB - On WIN32, some versions of Perl require that the environment variable - PERLLIB be set to . - - PATH - As already mentioned, you must have the perl executable and you may - need C and C++ compilers in your search path. For building base you - also must have echo in your search path. For Unix host builds you also - need ln, cpp, cp, rm, mv, and mkdir in your search path and /bin/chmod - must exist. On some Unix systems you may also need ar and ranlib in - your path, and the C compiler may require as and ld in your path. On - solaris systems you need uname in your path. - - LD_LIBRARY_PATH - R3.15 shared libraries and executables normally contain the full path - to any libraries they require. However, if you move the EPICS files or - directories from their build-time location then in order for the - shared libraries to be found at runtime LD_LIBRARY_PATH must include - the full pathname to $(INSTALL_LOCATION)/lib/$(EPICS_HOST_ARCH) when - invoking executables, or some equivalent OS-specific mechanism (such - as /etc/ld.so.conf on Linux) must be used. Shared libraries are now - built by default on all Unix type hosts. - - Do site-specific build configuration - - Site configuration - To configure EPICS, you may want to modify the default definitions in - the following files: - - configure/CONFIG_SITE Build choices. Specify target archs. - configure/CONFIG_SITE_ENV Environment variable defaults - configure/RELEASE TORNADO2 full path location - - Host configuration - To configure each host system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - changed to CONFIG_SITE. - - configure/os/CONFIG.. Host build settings - configure/os/CONFIG..Common Host common build settings - - Target configuration - To configure each target system, you may override the default - definitions by adding a new file in the configure/os directory with - override definitions. The new file should have the same name as the - distribution file to be overridden except with CONFIG in the name - replaced by CONFIG_SITE. This step is necessary even if the host - system is the only target system. - - configure/os/CONFIG.Common. Target common settings - configure/os/CONFIG.. Host-target settings - - Build EPICS base - - After configuring the build you should be able to build EPICS base by - issuing the following commands in the distribution's root directory - (base): - - gnumake clean uninstall - gnumake - - The command "gnumake clean uninstall" will remove all files and - directories generated by a previous build. The command "gnumake" will - build and install everything for the configured host and targets. - - It is recommended that you do a "gnumake clean uninstall" at the root - directory of an EPICS directory structure before each complete rebuild - to ensure that all components will be rebuilt. - - Example application and extension - - A perl tool, makeBaseApp.pl is included in the distribution file. This - script will create a sample application that can be built and then - executed to try out this release of base. - - Instructions for building and executing the 3.15 example application can - be found in the section "Example Application" of Chapter 2, "Getting - Started", in the "IOC Application Developer's Guide" for this release. - The "Example IOC Application" section briefly explains how to create and - build an example application in a user created directory. It also - explains how to run the example application on a vxWorks ioc or as a - process on the host system. By running the example application as a - host-based IOC, you will be able to quickly implement a complete EPICS - system and be able to run channel access clients on the host system. - - A perl script, makeBaseExt.pl, is included in the distribution file. - This script will create a sample extension that can be built and - executed. The makeBaseApp.pl and makeBaseExt.pl scripts are installed - into the install location bin/ directory during the base - build. - - Multiple host platforms - - You can build using a single EPICS directory structure on multiple host - systems and for multiple cross target systems. The intermediate and - binary files generated by the build will be created in separate - subdirectories and installed into the appropriate separate host/target - install directories. EPICS executables and perl scripts are installed - into the $(INSTALL_LOCATION)/bin/ directories. Libraries are - installed into $(INSTALL_LOCATION)/lib/. The default definition - for $(INSTALL_LOCATION) is $(TOP) which is the root directory in the - distribution directory structure, base. Created object files are stored - in O. source subdirectories, This allows objects for multiple - cross target architectures to be maintained at the same time. To build - EPICS base for a specific host/target combination you must have the - proper host/target C/C++ cross compiler and target header files and the - base/configure/os directory must have the appropriate configure files. diff --git a/documentation/README.md b/documentation/README.md index 149b8fae9..444dd44cc 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -167,8 +167,7 @@ base/documentation directory of the distribution. #### base/documentation directory - contains setup, build, and install documents ``` - README.1st Instructions for setup and building epics base - README.html html version of README.1st + README.md Instructions for setup and building epics base README.darwin.html Installation notes for Mac OS X (Darwin) RELEASE_NOTES.html Notes on release changes KnownProblems.html List of known problems and workarounds From 03e613cec0f4090ad98c6cf0dd0cc5de77b5ad6a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 21 Jan 2019 17:38:31 -0600 Subject: [PATCH 104/281] Adding POD to event and fanout records --- src/std/rec/{eventRecord.dbd => eventRecord.dbd.pod} | 0 src/std/rec/{fanoutRecord.dbd => fanoutRecord.dbd.pod} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{eventRecord.dbd => eventRecord.dbd.pod} (100%) rename src/std/rec/{fanoutRecord.dbd => fanoutRecord.dbd.pod} (100%) diff --git a/src/std/rec/eventRecord.dbd b/src/std/rec/eventRecord.dbd.pod similarity index 100% rename from src/std/rec/eventRecord.dbd rename to src/std/rec/eventRecord.dbd.pod diff --git a/src/std/rec/fanoutRecord.dbd b/src/std/rec/fanoutRecord.dbd.pod similarity index 100% rename from src/std/rec/fanoutRecord.dbd rename to src/std/rec/fanoutRecord.dbd.pod From 86b188218687ccb147ba367ce4a148e17790ecec Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 29 Aug 2019 12:54:21 -0500 Subject: [PATCH 105/281] Updates to existing .dbd.pod texts, add event and fanout from wiki --- src/std/rec/aoRecord.dbd.pod | 14 +- src/std/rec/biRecord.dbd.pod | 66 +++++---- src/std/rec/boRecord.dbd.pod | 51 ++++--- src/std/rec/calcRecord.dbd.pod | 50 +++---- src/std/rec/calcoutRecord.dbd.pod | 82 +++++++---- src/std/rec/dfanoutRecord.dbd.pod | 5 - src/std/rec/eventRecord.dbd.pod | 225 +++++++++++++++++++++++++++++- src/std/rec/fanoutRecord.dbd.pod | 187 ++++++++++++++++++++++++- 8 files changed, 556 insertions(+), 124 deletions(-) diff --git a/src/std/rec/aoRecord.dbd.pod b/src/std/rec/aoRecord.dbd.pod index 41467dcd3..6aaf7d4b7 100644 --- a/src/std/rec/aoRecord.dbd.pod +++ b/src/std/rec/aoRecord.dbd.pod @@ -70,7 +70,7 @@ output value PVAL is added to it. =head4 Drive Limits The output value is now clipped to the range DRVL to DRVH inclusive, provided -that DRVH > DRVL. +that DRVH E DRVL. The result is copied into both the VAL and PVAL fields. =head4 Limit Rate of Change @@ -164,9 +164,7 @@ OUT field must specify the address of the I/O card. In addition, the DTYP field must contain the name of the device support module. Be aware that the address format differs according to the I/O bus used. See Address Specification for information on the format of hardware -addresses. The user can see a list of the device support modules -currently supported at the user's local site by using the dbst utility -in R3.13. +addresses. For soft records the output link can be a database link, a channel access link, or a constant value. If the link is a constant, no output @@ -593,7 +591,7 @@ terminated. For compatibility with old device supports that don't know EOFF, if both EOFF and ESLO have their default value, EOFF is set to EGUL. -If device support includes init_record, it is called. +If device support includes C, it is called. INIT is set TRUE. This causes PBRK, LBRK, and smoothing to be re-initialized. If "backwards" linear conversion is requested, then VAL @@ -620,10 +618,6 @@ called. INIT is set TRUE. This causes PBRK, LBRK, and smoothing to be re-initialized. -=item get_value - -Fills in the values of struct valueDes so that they refer to VAL. - =item get_alarm_double Sets the following values: @@ -903,7 +897,7 @@ OUT link type must be either a CONSTANT, DB_LINK, or CA_LINK. This module writes the current value of OVAL. If the OUT link type is PV_LINK, then dbCaAddInlink is called by -init_record. init_record always returns a value of 2, which means that +C. C always returns a value of 2, which means that no conversion will ever be attempted. write_ao calls recGblPutLinkValue to write the current value of VAL. diff --git a/src/std/rec/biRecord.dbd.pod b/src/std/rec/biRecord.dbd.pod index a711435ba..2d4cc0c51 100644 --- a/src/std/rec/biRecord.dbd.pod +++ b/src/std/rec/biRecord.dbd.pod @@ -69,9 +69,7 @@ If the binary input record gets its value from hardware, the address of the card must be entered in the INP field, and the name of the device support module must be entered in the DTYP field. See L
for information on the format of the hardware address. Be aware that the format -differs between types of cards. You can see a list of device support -modules currently supported at the user's local site by using C -utility (R3.13). +differs between types of cards. For records that specify C or C device support routines, the INP field can be a channel or a database link, or a @@ -94,18 +92,18 @@ the device support module reads a value directly into VAL or the C device support is used. The value can also be fetched as one of the strings specified in the ZNAM or ONAM fields. The ZNAM field has a string that corresponds to the 0 state, so when the value is fetched as -this string, C will return a 0. The ONAM field hold the +this string, C will return a 0. The ONAM field hold the string that corresponds to the 1 state, so when the value is fetched as -this string, C returns a 1. +this string, C returns a 1. =fields ZNAM, ONAM =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator. The -C record support routine can retrieve the state string -corresponding to the VAL's state. If the value is 1, C will -return the string in the ONAM field; and if 0, C will return +C record support routine can retrieve the state string +corresponding to the VAL's state. If the value is 1, C will +return the string in the ONAM field; and if 0, C will return the ZNAM string. See L for more on the record name (NAME) @@ -149,7 +147,7 @@ The LALM fields holds the value of the last occurence of the change of state alarm. It is used to implement the change of state alarm, and thus only has meaning if COSV is MAJOR or MINOR. -The MSLT field is used by the C record support routine to +The MSLT field is used by the C record support routine to determine if archive and value change monitors are invoked. They are if MSLT is not equal to VAL. @@ -276,16 +274,12 @@ This routine next checks to see that device support is available and a device support routine is defined. If neither exist, an error is issued and processing is terminated. -If device support includes C, it is called. +If device support includes C, it is called. =head2 C See next section. -=head2 C - -Fills in the values of struct valueDes so that they refer to VAL. - =head2 C Retrieves ASCII string corresponding to VAL. @@ -311,7 +305,7 @@ the PACT field still set to TRUE. This ensures that processes will no longer be called for this record. Thus error storms will not occur. =item 2. -C is called. See L for details. +C is called. See L for details. =item 3. If PACT has been changed to TRUE, the device support read routine has @@ -332,7 +326,7 @@ status = read_bi PACT = TRUE =item * -TIME = tslocaltime +C is called. =item * if status is 0, then set VAL=(0,1) if RVAL is (0, not 0) and UDF = False. @@ -383,7 +377,7 @@ Scan forward link if necessary, set PACT FALSE, and return. Each binary input record must have an associated set of device support routines. The primary resposibility of the device support routines is to -obtain a new raw input value whenever C is called. The device +obtain a new raw input value whenever C is called. The device support routines are primarily interested in the following fields: =fields PACT, DPVT, UDF, NSEV, NSTA, VAL, INP, RVAL, MASK @@ -392,22 +386,32 @@ support routines are primarily interested in the following fields: Device support consists of the following routines: -=head2 C +=head4 long report(int level) -Not currently used. +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. -=head2 C +=head4 long init(int after) -This routine is called once during IOC initialization. +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. =head2 C This routine is optional. If provided, it is called by the record support -C routine. +C routine. =head2 C -This routine is called by the C system each time the record is +This routine is called by the ioEventScan system each time the record is added or deleted from an I/O event scan list. C has the value (0,1) if the record is being (added to, deleted from) and I/O event list. It must be provided for any device type that can use the ioEvent scanner. @@ -439,25 +443,25 @@ link type must be either CONSTANT, DB_LINK, or CA_LINK. =head3 Soft Channel -C always returns a value of 2, which means that no conversion is +C always returns a value of 2, which means that no conversion is performed. If the INP link type is CONSTANT, then the constant value is stored in VAL -by C, and the UDF is set to FALSE. VAL can be changed via -C requests. If the INP link type is PV_LINK, the C is -called by C. +by C, and the UDF is set to FALSE. VAL can be changed via +C requests. If the INP link type is PV_LINK, the C is +called by C. -C calls C to read the current value of VAL. +C calls C to read the current value of VAL. See L for details. -If the return status of C is zero, then C sets -UDF to FALSE. The status of C is returned. +If the return status of C is zero, then C sets +UDF to FALSE. The status of C is returned. =head3 Raw Soft Channel This module is like the previous except that values are read into RVAL. -C returns a value of 0. Thus the record processing routine will +C returns a value of 0. Thus the record processing routine will force VAL to be 0 or 1. =cut diff --git a/src/std/rec/boRecord.dbd.pod b/src/std/rec/boRecord.dbd.pod index cbeee1abf..8d29bcf92 100644 --- a/src/std/rec/boRecord.dbd.pod +++ b/src/std/rec/boRecord.dbd.pod @@ -130,8 +130,7 @@ It must specify the address of an I/O card if the record sends its output to hardware, and the DTYP field must contain the corresponding device support module. Be aware that the address format differs according to the I/O bus used. See L
for information on the format of -hardware addresses. You can see a list of device support modules currently -supported at the user's local site by using the C utility in R3.13. +hardware addresses. Otherwise, if the record is configured to use the soft device support modules, then it can be either a database link, a channel access link, or a @@ -143,9 +142,9 @@ this chapter for more on output to other records. =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator, The -C record support routine can retrieve the state string -corresponding to the VAL's state. So, if the value is 1, C -will return the string in the ONAM field: and if 0, C will +C record support routine can retrieve the state string +corresponding to the VAL's state. So, if the value is 1, C +will return the string in the ONAM field: and if 0, C will return the ZNAM string. See L for more on the record name (NAME) @@ -194,7 +193,7 @@ The LALM field holds the value of the last occurrence of the change of state alarm. It is used to implement the change of state alarm, and thus only has meaning if COSV is MINOR or MAJOR. -The MLST is used by the C record support routine to determine if +The MLST is used by the C record support routine to determine if archive and value change monitors are invoked. They are if MLST is not equal to VAL. @@ -373,17 +372,13 @@ exist, and error message is issued and processing is terminated. If DOL is a constant, then VAL is initialized to 1 if its value is nonzero or initialzed to 0 if DOL is zero, and UDF is set to FALSE. -If device support includes C, it is called. VAL is set using +If device support includes C, it is called. VAL is set using RVAL, and UDF is set to FALSE. =head2 C See next section. -=head2 C - -Fills in the values of struct valueDes so that they refer to VAL. - =head2 C Retrieves ASCII string corresponding to VAL. @@ -416,7 +411,7 @@ If PACT is FALSE =over =item * -If DOL is DB_LINK and OMSL is CLOSED_LOOP +If DOL holds a link and OMSL is C =over @@ -500,27 +495,37 @@ Scan forward link if necessary, set PACT FALSE, and return Each binary output record must have an associated set of device support routines. The primary responsibility of the device support routines is to -write a new value whenever C is called. The device support routines +write a new value whenever C is called. The device support routines are primarily interested in the following fields: =fields PACT, DPVT, NSEV, NSTA, VAL, OUT, RVAL, MASK, RBV -=head3 Decive Support Routines +=head3 Device Support Routines Device support consists of the following routines: -=head2 C +=head4 long report(int level) -Not currently used. +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. -=head2 C +=head4 long init(int after) -This routine is called once during IOC initialization. +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. =head2 C This routine is optional. If provided, it is called by record support -C routine. It should determine MASK if it is needed. +C routine. It should determine MASK if it is needed. =over @@ -566,10 +571,10 @@ link type must be either CONSTANT, DB_LINK, or CA_LINK. This module writes the current value of VAL. -If the OUT link type is PV_LINK, then C is called by -C. C always returns a value of 2, which means -that no conversion will ever be attempted. C calls -C to write the current value of VAL. See L +If the OUT link type is PV_LINK, then C is called by +C. C always returns a value of 2, which means +that no conversion will ever be attempted. C calls +C to write the current value of VAL. See L for details. =head3 Raw Soft Channel diff --git a/src/std/rec/calcRecord.dbd.pod b/src/std/rec/calcRecord.dbd.pod index c50667fb3..243c81eee 100644 --- a/src/std/rec/calcRecord.dbd.pod +++ b/src/std/rec/calcRecord.dbd.pod @@ -261,22 +261,22 @@ ATAN: Arc tangent =over 1 =item * ->= : Greater than or equal to +C<<< >= >>> : Greater than or equal to =item * -> : Greater than +C<<< > >>> : Greater than =item * -<= : Less than or equal to +C<<< <= >>> : Less than or equal to =item * -< : Less than +C<<< < >>> : Less than =item * -# : Not equal to +C<<< # >>> : Not equal to =item * -= : Equal to +C<<< = >>> : Equal to =back @@ -285,13 +285,13 @@ ATAN: Arc tangent =over 1 =item * -&& : And +C<&&> : And =item * -|| : Or +C<||> : Or =item * -! : Not +C : Not =back @@ -300,10 +300,10 @@ ATAN: Arc tangent =over 1 =item * -| : Bitwise Or +C<|> : Bitwise Or =item * -& : Bitwise And +C<&> : Bitwise And =item * OR : Bitwise Or @@ -315,13 +315,13 @@ AND : Bitwise And XOR : Bitwise Exclusive Or =item * -~ : One's Complement +C<~> : One's Complement =item * -<< : Left shift +C<<< << >>> : Left shift =item * ->> : Right shift +C<<< >> >>> : Right shift =back @@ -330,7 +330,7 @@ XOR : Bitwise Exclusive Or =over 1 =item * -:= : assigns a value (right hand side) to a variable (i.e. field) +C<:=> : assigns a value (right hand side) to a variable (i.e. field) =back @@ -360,35 +360,35 @@ C =over 1 =item * -Result is A + B + 10 +Result is C =back =head3 Relational -C<(A + B) < (C + D)> +C<<< (A + B) < (C + D) >>> =over 1 =item * -Result is 1 if (A + B) < (C + D) +Result is 1 if C<<< (A + B) < (C + D) >>> =item * -Result is 0 if (A + B) >= (C + D) +Result is 0 if C<<< (A + B) >= (C + D) >>> =back =head3 Question Mark -C<(A + B) < (C + D) ? E : F + L + 10> +C<<< (A + B) < (C + D) ? E : F + L + 10 >>> =over 1 =item * -Result is E if (A + B) < (C + D) +Result is C if C<<< (A + B) < (C + D) >>> =item * -Result is F + L + 10 if (A + B) >= (C + D) +Result is C if C<<< (A + B) >= (C + D) >>> =back @@ -412,7 +412,7 @@ C<(A + B) < (C + D) ? E : VAL> =head3 Logical -C +C =over 1 @@ -851,10 +851,6 @@ See next section. This is called if CALC is changed. C calls postfix. -=head2 C - -Fills in the values of struct valueDes so that the refer to VAL. - =head2 C Retrieves EGU. diff --git a/src/std/rec/calcoutRecord.dbd.pod b/src/std/rec/calcoutRecord.dbd.pod index 6289f9043..176f1d25f 100644 --- a/src/std/rec/calcoutRecord.dbd.pod +++ b/src/std/rec/calcoutRecord.dbd.pod @@ -293,22 +293,22 @@ ATAN: Arc tangent =over 1 =item * ->= : Greater than or equal to +C<<< >= >>> : Greater than or equal to =item * -> : Greater than +C<<< > >>> : Greater than =item * -<= : Less than or equal to +C<<< <= >>> : Less than or equal to =item * -< : Less than +C<<< < >>> : Less than =item * -# : Not equal to +C<<< # >>> : Not equal to =item * -= : Equal to +C<<< = >>> : Equal to =back @@ -332,10 +332,10 @@ ATAN: Arc tangent =over 1 =item * -| : Bitwise Or +C<|> : Bitwise Or =item * -& : Bitwise And +C<&> : Bitwise And =item * OR : Bitwise Or @@ -347,13 +347,13 @@ AND : Bitwise And XOR : Bitwise Exclusive Or =item * -~ : One's Complement +C<~> : One's Complement =item * -<< : Left shift +C<<< << >>> : Left shift =item * ->> : Right shift +C<<< >> >>> : Right shift =back @@ -362,11 +362,11 @@ XOR : Bitwise Exclusive Or =over 1 =item * -:= : assigns a value (right hand side) to a variable (i.e. field) +C<:=> : assigns a value (right hand side) to a variable (i.e. field) =back -=head3 Parentheses and Comma +=head3 Parantheses, Comma, and Semicolon The open and close parentheses are supported. Nested parentheses are supported. @@ -374,6 +374,10 @@ supported. The comma is supported when used to separate the arguments of a binary function. +The semicolon is used to separate expressions. Although only one +traditional calculation expression is allowed, multiple assignment +expressions are allowed. + =head3 Conditional Expression The C language's question mark operator is supported. The format is: @@ -388,41 +392,59 @@ C =over 1 =item * -Result is A + B + 10 +Result is C =back =head3 Relational -C<(A + B) < (C + D)> +C<<< (A + B) < (C + D) >>> =over 1 =item * -Result is 1 if (A + B) < (C + D) +Result is 1 if C<<< (A + B) < (C + D) >>> =item * -Result is 0 if (A + B) >= (C + D) +Result is 0 if C<<< (A + B) >= (C + D) >>> =back =head3 Question Mark -C<(A + B) < (C + D) ? E : F + L + 10> +C<<< (A + B) < (C + D) ? E : F + L + 10 >>> =over 1 =item * -Result is E if (A + B) < (C + D) +Result is C if C<<< (A + B) < (C + D) >>> =item * -Result is F + L + 10 if (A + B) >= (C + D) +Result is C if C<<< (A + B) >= (C + D) >>> + +=back + +Prior to Base 3.14.9 it was legal to omit the : and the second (else) part +of the conditional, like this: + +C<(A + B)<(C + D) ? E> + +=over 1 + +=item +Result is E if (A + B)<(C + D) + +=item +Result is unchanged if (A + B)>=(C + D) + +From 3.14.9 onwards, this expresion must be written as +C<(A + B) < (C + D) ? E : VAL> =back =head3 Logical -C +C =over 1 @@ -447,6 +469,18 @@ Convert result to floating point =back +=head3 Assignment + +C + +=over 1 + +=item * +Causes the Calc record to output the successive values of a sine curve in +1 degree intervals. + +=back + =head3 Output Parameters These parameters specify and control the output capabilities of the Calcout @@ -529,7 +563,7 @@ are also meant to represent the status of the record at run-time. The EGU field contains a string of up to 16 characters which is supplied by the user and which describes the values being operated upon. The string is -retrieved whenever the routine C is called. The EGU string is +retrieved whenever the routine C is called. The EGU string is solely for an operator's sake and does not have to be used. The HOPR and LOPR fields on;y refer to the limits if the VAL, HIHI, HIGH, @@ -1146,10 +1180,6 @@ See next section. This is called id CALC or OCAL is changed. C calls postfix. -=head2 C - -Fills in the values of struct valueDes so that they refer to VAL. - =head2 C Retrieves EGU. diff --git a/src/std/rec/dfanoutRecord.dbd.pod b/src/std/rec/dfanoutRecord.dbd.pod index 0d0487666..790abdffe 100644 --- a/src/std/rec/dfanoutRecord.dbd.pod +++ b/src/std/rec/dfanoutRecord.dbd.pod @@ -379,11 +379,6 @@ and the DOL link, a non-zero value is returned if an error occurs. See next section. -=head2 C - -This routine fills in the members of C with the VAL fields -value and characteristics. - =head2 C The routine copies the string specified in the EGU field to the location diff --git a/src/std/rec/eventRecord.dbd.pod b/src/std/rec/eventRecord.dbd.pod index 348902e4b..0d512da22 100644 --- a/src/std/rec/eventRecord.dbd.pod +++ b/src/std/rec/eventRecord.dbd.pod @@ -6,8 +6,63 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=title Event Record (event) + +The normal use for this record type is to post an event and/or process a +forward link. Device support for this record can provide a hardware interrupt +handler routine for I/O Event-scanned records. + +=head2 Parameter Fields + +The records in this field fall into the following groups of parameters: + +=over + +=item * + +scan parameters + +=item * + +read parameters + +=item * + +event number parameters + +=item * + +simulation mode parameters + +=back + +=recordtype event + +=cut + recordtype(event) { - include "dbCommon.dbd" + include "dbCommon.dbd" + +=head3 Scan Parameters + +The event record has the standard fields for specifying under what circumstances +it will be processed. If the SCAN field specifies C, then device +support will provide an interrupt handler, posting an event number when an I/O +interrupt occurs. These fields are listed in L. In addition, +L explains how the scanning fields work. Note that I/O +event scanning is only supported for those card types that interrupt. + +=head3 Event Number Parameters + +The VAL field contains the event number read by the device support routines. It +is this number which is posted. For records that use C device +support, it can be configured before run-time or set via dbPuts. + +=fields VAL + +=cut + field(VAL,DBF_STRING) { prompt("Event Name To Post") promptgroup("40 - Input") @@ -22,11 +77,52 @@ recordtype(event) { interest(4) extra("EVENTPVT epvt") } + +=head3 Input Specification + +The device support routines use the address in this record to obtain input. For +records that provide an interrupt handler, the INP field should specify the +address of the I/O card, and the DTYP field should specify a valid device +support module. Be aware that the address format differs according to the card +type used. See L
for information on the format of +hardware addresses and specifying links. + +For soft records, the INP field can be a constant, a database link, or a channel +access link. For soft records, the DTYP field should specify C. + +=fields INP, DTYP + +=cut + field(INP,DBF_INLINK) { prompt("Input Specification") promptgroup("40 - Input") interest(1) } + +=head3 Operator Display Parameters + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The Event record has the alarm parameters common to all record types. L lists other fields related to alarms that are common to all record +types. + +=head3 Simulation Mode Parameters + +The following fields are used to operate the event record in the simulation +mode. See L for more information on these +fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS + +=cut + field(SIOL,DBF_INLINK) { prompt("Sim Input Specifctn") promptgroup("90 - Simulate") @@ -52,4 +148,131 @@ recordtype(event) { interest(2) menu(menuAlarmSevr) } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is a CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +If device support includes C, it is called. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +readValue is called. See L for more information. + +=item 2. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 3. + +If VAL E 0, post event number VAL. + +=item 4. + +Check to see if monitors should be invoked. Alarm monitors are invoked if the +alarm status or severity has chanet to 0. + +=item 5. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=head2 Device Support + +=head3 Fields of Interest To Device Support + +Each record must have an associated set of device support routines. The device +support routines are primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, INP, PRIO + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the record is +being (added to, deleted from) an I/O event list. It must be provided for any +device type that can use the ioEvent scanner. + +=head4 read_event + + read_event(precord) + +This routine returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C device support module is available. The INP link type must +be either CONSTANT, DB_LINK, or CA_LINK. + +If the INP link type is CONSTANT, then the constant value is stored into VAL by +C, and UDF is set to FALSE. If the INP link type is PV_LINK, then +dbCaAddInlink is called by C. + +C calls recGblGetLinkValue to read the current value of VAL. See +L for details on soft input. + +=cut + } diff --git a/src/std/rec/fanoutRecord.dbd.pod b/src/std/rec/fanoutRecord.dbd.pod index 251d63a11..11a9ad32e 100644 --- a/src/std/rec/fanoutRecord.dbd.pod +++ b/src/std/rec/fanoutRecord.dbd.pod @@ -6,13 +6,121 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=title Fanout Record (fanout) + +The fanout record uses several forward processing links to force multiple +passive records to scan. When more than one record needs to be scanned as the +result of a record being processed, the forward link of that record can specify +a fanout record. The fanout record can specify up to sixteen other records to +process. If more than sixteen are needed, one of the forward links in the fanout +record (or its FLNK field) can point to another fanout record. + +B The dfanout or +data fanout record can, on the other hand, send data to other records. + +=head2 Parameter Fields + +The fanout record's fields fall into the following categories: + +=over + +=item * + +scan parameters + +=item * + +operator display parameters + +=item * + +run-time parameters. + +=back + +=recordtype fanout + +=cut + menu(fanoutSELM) { choice(fanoutSELM_All,"All") choice(fanoutSELM_Specified,"Specified") choice(fanoutSELM_Mask,"Mask") } + recordtype(fanout) { - include "dbCommon.dbd" + include "dbCommon.dbd" + +=head3 Scan Parameters + +The forward link fields of the fanout record (LNK0-LNK9, LNKA-LNKF) specify +records to be scanned. The records to be processed must specify C in +their SCAN fields; otherwise the forward link will not cause them to process. +Also when specifying database links for the fanout record, the user needs only +to specify the record name. As no value is being sent or retrieved, a field name +is only required when the link will be over Channel Access, in which case the +field PROC must be named. + +The SELM, SELN, and SELL fields specify the order of processing for the forward +links. The select mechanism menu field (SELM) has three choices: + +=menu fanoutSELM + +How the SELM value affects which links to process and in which order is as +follows: + +=over + +=item * + +B +Links are processed in numerical order - LNK0, LNK1, etc. + +=item * + +B The sum of the values in the SELN and OFFS fields is used as the +specifier of which link to process. For instance, with OFFS=0 and SELN=1, the +record targeted by LNK1 will be processed. + +=item * + +B The individual bits in SELN are shifted by SHFT bits (negative means +shift left) and the result used to select which links to process as follows: + +=over + +=item * + +If bit 0 (LSB) is set, LNK0 is processed. + +=item * + +If bit 1 is set, LNK2 is processed. + +=item * + +If bit 2 is set, LNK3 is processed, etc. + +=back + +=back + +SELN reads its value from SELL. SELL can be a constant, a database link, or a +channel access link. If a constant, SELN is initialized with the constant value +and can be changed via dbPuts. For database/channel access links, SELN is +retrieved from SELL each time the record is processed and can also be changed +via dbPuts. + +The Fanout record also has the standard scanning fields common to all records. +These fields are listed in L. In addition, +L explains in more detail how forward links and the +scanning algorithms work. + +=fields SELM, SELN, SELL, OFFS, SHFT, LNK0, LNK1, LNK2, LNK3, LNK4, LNK5, LNK6, LNK7, LNK8, LNK9, LNKA, LNKB, LNKC, LNKD, LNKE, LNKF + +=cut + field(VAL,DBF_LONG) { prompt("Used to trigger") asl(ASL0) @@ -126,4 +234,81 @@ recordtype(fanout) { promptgroup("52 - Output 8-F") interest(1) } + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. See +L for more on these fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The Fanout record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time Parameters + +The VAL field performs no specific function, but a Channel Access put to it will +cause the record to process. + +=fields VAL + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SELN with the value of SELL, if SELL type is CONSTANT +link, or creates a channel access link if SELL type is PV_LINK. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +PACT is set to TRUE. + +=item 2. + +The link selection SELN is fetched. + +=item 3. + +Depending on the selection mechanism, the link selection forward links are +processed, and UDF is set to FALSE. + +=item 4. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 5. + +Scan forward link field FLNK if used, set PACT FALSE, and return. + +=back + +=cut + } From 937379892a0f866a9612440996ef84043e6ddbd4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2019 10:38:37 -0700 Subject: [PATCH 106/281] epicsMutex automatically capture file+line with gcc >=4.8 gcc >=4.8 allows __builtin_FILE() to expand at the call site when used given as the default for a c++ function argument. --- modules/libcom/src/osi/epicsMutex.cpp | 2 ++ modules/libcom/src/osi/epicsMutex.h | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/modules/libcom/src/osi/epicsMutex.cpp b/modules/libcom/src/osi/epicsMutex.cpp index 7c8d05056..035431145 100644 --- a/modules/libcom/src/osi/epicsMutex.cpp +++ b/modules/libcom/src/osi/epicsMutex.cpp @@ -247,6 +247,7 @@ void epicsShareAPI epicsMutexShowAll(int onlyLocked,unsigned int level) epicsMutexOsdUnlock(epicsMutexGlobalLock); } +#if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8) epicsMutex :: epicsMutex () : id ( epicsMutexCreate () ) { @@ -254,6 +255,7 @@ epicsMutex :: epicsMutex () : throw mutexCreateFailed (); } } +#endif epicsMutex :: epicsMutex ( const char *pFileName, int lineno ) : id ( epicsMutexOsiCreate (pFileName, lineno) ) diff --git a/modules/libcom/src/osi/epicsMutex.h b/modules/libcom/src/osi/epicsMutex.h index 6d74f9599..070efd0e4 100644 --- a/modules/libcom/src/osi/epicsMutex.h +++ b/modules/libcom/src/osi/epicsMutex.h @@ -32,8 +32,12 @@ public: typedef epicsGuard release_t; class mutexCreateFailed; /* exception payload */ class invalidMutex; /* exception payload */ +#if !defined(__GNUC__) || __GNUC__<4 || (__GNUC__==4 && __GNUC_MINOR__<8) epicsMutex (); epicsMutex ( const char *pFileName, int lineno ); +#else + epicsMutex ( const char *pFileName = __builtin_FILE(), int lineno = __builtin_LINE() ); +#endif ~epicsMutex (); void show ( unsigned level ) const; void lock (); /* blocks until success */ From 299aed026fd40b792f40b08386f208d17166fc40 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 1 Sep 2019 19:18:09 -0700 Subject: [PATCH 107/281] drop unneeded includes Avoid pulling in CALLBACK unnecessarily, which can aggravating MSVC. --- modules/database/src/ioc/db/dbNotify.h | 2 -- modules/database/src/ioc/db/db_test.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/database/src/ioc/db/dbNotify.h b/modules/database/src/ioc/db/dbNotify.h index 4b7c3e4dd..5641cff0f 100644 --- a/modules/database/src/ioc/db/dbNotify.h +++ b/modules/database/src/ioc/db/dbNotify.h @@ -13,8 +13,6 @@ #include "shareLib.h" #include "ellLib.h" -#include "epicsEvent.h" -#include "callback.h" #ifdef __cplusplus extern "C" { diff --git a/modules/database/src/ioc/db/db_test.c b/modules/database/src/ioc/db/db_test.c index 3d536f080..544cfdde2 100644 --- a/modules/database/src/ioc/db/db_test.c +++ b/modules/database/src/ioc/db/db_test.c @@ -21,6 +21,7 @@ #include "epicsStdlib.h" #include "epicsString.h" #include "errlog.h" +#include "epicsEvent.h" #define epicsExportSharedSymbols #include "db_access_routines.h" From 623539c3e8be539f8dc2a1dfa65b97768f72cac1 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 6 Sep 2019 10:14:39 +0200 Subject: [PATCH 108/281] Add redefinition guard to menu-generated typedefs --- src/tools/DBD/Menu.pm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/tools/DBD/Menu.pm b/src/tools/DBD/Menu.pm index 9c93c6d50..959536eaa 100644 --- a/src/tools/DBD/Menu.pm +++ b/src/tools/DBD/Menu.pm @@ -59,14 +59,17 @@ sub equals { sub toDeclaration { my $this = shift; my $name = $this->name; + my $macro_name = "${name}_NUM_CHOICES"; my @choices = map { sprintf " %-31s /* %s */", @{$_}[0], escapeCcomment(@{$_}[1]); } $this->choices; my $num = scalar @choices; - return "typedef enum {\n" . + return "#ifndef $macro_name\n" . + "typedef enum {\n" . join(",\n", @choices) . "\n} $name;\n" . - "#define ${name}_NUM_CHOICES $num\n\n"; + "#define $macro_name $num\n" . + "#endif\n\n"; } sub toDefinition { From 89e3c582b5f8579f4550db0def54fc07af10c8df Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 6 Sep 2019 10:44:02 +0200 Subject: [PATCH 109/281] Fix menu declaration test too --- src/tools/test/Menu.plt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/test/Menu.plt b/src/tools/test/Menu.plt index c68ba9a85..0dd3a5c79 100644 --- a/src/tools/test/Menu.plt +++ b/src/tools/test/Menu.plt @@ -24,9 +24,11 @@ ok !$menu->legal_choice('Choice 3'), 'Third choice not legal'; is_deeply $menu->choice(2), undef, 'Third choice undefined'; like $menu->toDeclaration, qr/ ^ + \s* \# \s* ifndef \s+ test_NUM_CHOICES \s* \n \s* typedef \s+ enum \s+ \{ \s* \n \s* ch1 \s+ \/\* [^*]* \*\/, \s* \n \s* ch2 \s+ \/\* [^*]* \*\/ \s* \n \s* \} \s* test \s* ; \s* \n \s* \# \s* define \s+ test_NUM_CHOICES \s+ 2 \s* \n + \s* \# \s* endif \s* \n \s* $ /x, 'C declaration'; From 83458421aaab1405e16b514c573330a138291580 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 11:20:11 +0200 Subject: [PATCH 110/281] Rename seqRecord.dbd seqRecord.dbd.pod --- src/std/rec/{seqRecord.dbd => seqRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{seqRecord.dbd => seqRecord.dbd.pod} (100%) diff --git a/src/std/rec/seqRecord.dbd b/src/std/rec/seqRecord.dbd.pod similarity index 100% rename from src/std/rec/seqRecord.dbd rename to src/std/rec/seqRecord.dbd.pod From b93f92c8432756a12aa5c716ea143b220c260cb4 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 11:26:39 +0200 Subject: [PATCH 111/281] Add POD annotations to seqRecord from Wiki --- src/std/rec/seqRecord.dbd.pod | 282 ++++++++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) diff --git a/src/std/rec/seqRecord.dbd.pod b/src/std/rec/seqRecord.dbd.pod index 826f3ecf6..077d36107 100644 --- a/src/std/rec/seqRecord.dbd.pod +++ b/src/std/rec/seqRecord.dbd.pod @@ -6,12 +6,294 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=title Sequence Record (seq) + +The Sequence record is used to trigger the processing of up to ten other records +and send values to those records. It is similar to the fanout record, except +that it will fetch an input value and write an output value instead of simply +processing a collection of forward links. It can also specify one of several +selection algorithms that determine which values to write. It has no associated +device support. + +=recordtype seq + +=cut + menu(seqSELM) { choice(seqSELM_All,"All") choice(seqSELM_Specified,"Specified") choice(seqSELM_Mask,"Mask") } + recordtype(seq) { + +=pod + +=head1 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=back + +=begin html + +


+ +=end html + +=head2 Parameter Fields + +The fields fall into the following categories: + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=head3 Scan Parameters + +The sequence record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. + +=head3 Desired Output Parameters + +These fields determine where the record retrieves the values it is to write to +other records. All of these values are not necessarily used, depending on the +selection algorithm. + +The sequence record can retrieve up to 16 values from 16 locations. The user +specifies the locations in the Desired Output Link fields (DOL0-DOLF), which can +be either constants, database links, or channel access links. If a Desired +Output Link is a constant, the corresponding value field for that link is +initialized to the constant value and ''cannot'' be changed via dbputs. +Otherwise, if the Desired Output Link is a database or channel access link, a +value is fetched from the link each time the record is processed (provided that +the output link is part of the record's selection algorithm). See L
for information on how to specify database links. + +The value fetched from the Desired Output Links are stored in the corresponding +Desired Output Value fields (DO0-DOF). These fields can be initialized to a +constant value, but they cannot be changed via dbPuts. + +=head4 Desired Output Link Fields + +=fields DOL0, DOL1, DOL2, DOL3, DOL4, DOL5, DOL6, DOL7, DOL8, DOL9, DOLA, DOLB, DOLC, DOLD, DOLE, DOLF + +=head4 Desired Output Value Fields + +=fields DO0, DO1, DO2, DO3, DO4, DO5, DO6, DO7, DO8, DO9, DOA, DOB, DOC, DOD, DOE, DOF + +=head3 Output Parameters + +When the record is processed, the desired output values are retrieved for the +links in the record's selection algorithm and are written to the corresponding +output link (LNK0-LNKF). These output links can be database links or channel +access links; they cannot be device addresses. There are sixteen output links, one +for each desired output link. Only those that are defined are used. + +=fields LNK0, LNK1, LNK2, LNK3, LNK4, LNK5, LNK6, LNK7, LNK8, LNK9, LNKA, LNKB, LNKC, LNKD, LNKE, LNKF + +=head3 Selection Algorithm Parameters + +When the sequence record is processed, it uses a selection algorithm similar to +that of the selection record to decide which links to process.The select +mechanism field (SELM) has three algorithms to choose from: C<<< All >>>, +C<<>> or C<<< Mask >>>. + +=head4 Record fields related to the Selection Algorithm + +=fields SELM, SELN, SELL, SHFT, OFFS + +=head4 Fields Description + +B + +=menu seqSELM + +See L below; + +B + +This field can be initialized as a CONSTANT or as a LINK to any other record. SELN will fetch its value from this field when the seq record is processed. +Thus, when using I or I modes, the links that seq will process can be dinamically changed by the record pointed by SELL. + +B + +When B> this is the index number of the link that will be processed, used in combination with the C field: + + SELN = SELN + OFFS + + +I<(By default, the OFFS is initalized to ZERO)> + +When B> this field is the bitmask that will be used to determine which links will be processed by the seq record, +in combination with the C field: + + if (SHFT >= 0) + SELN = SELN << -SHFT + else + SELN = SELN >> SHFT + +I<(By default, the SHFT is initalized to -1)> + +=head4 B + +The first versions of seq record had DO, DOL, LNK and DLY fields starting with index ONE (DO1, DOL1, LNK1 and DLY1). +New version of the seq record now supports 16 links, starting by index ZERO (DO0, DOL0, LNK0 and DLY0). The SHFT and OFFS fields +were introduced to keep compatibility of old databases that used seq record with its links indexed from one onwards. + +B + +=head4 Selection Algorithms Description + +B + +The C<<< All >>> algorithm causes the record to process each input and output +link each time the record is processed, in order from 0 to 15. So when SELM is +C<<< All >>>, the desired output value from DOL0 will fetched and sent to LNK0, +then the desired output value from DOL1 will be fetched and sent to the location +in LNK1, and so on until the last input and output link DOF and LNKF. (Note that +undefined links are not used.) If DOLI is a constant, the current value +field is simply used and the desired output link is ignored. The SELN field is +not used when C<<< All >>> is the algorithm. + +B + +When the C<<< Specified >>> algorithm is chosen, each time the record is +processed it gets the integer value in the Link Selection (SELN) field and uses +that as the index of the link to process. For instance, if SELN is 4, the +desired output value from DO4 will be retrieved and sent to LNK4. If DOLI is +a constant, DOI is simply used without the value being fetched from the +input link. + +B + +When C<<< Mask >>> is chosen, the record uses the individual bits of the SELN +field to determine the links to process. When bit 0 of SELN is set, the value +from DO0 will be written to the location in LNK0; when bit 1 is set, the valud +from DO1 will be written to the location in LNK1 etc. Thus for example if SELN +is 3, the record will retrieve the values from DO0 and DO1 and write them to the +locations in LNK0 and LNK1, respectively. If SELN is 63, DO0...DO5 will be +written to LNK0...LNK5. + + +=head3 Delay Parameters + +The delay parameters consist of 16 fields, one for each I/O link discussed +above. These fields can be configured to cause the record to delay processing +the link. For instance, if the user gives the DLY1 field a value of 3.0, each +time the record is processed at run-time, the record will delay processing the +DOL1, DOV1, and LNK1 fields for three seconds. That is, the desired output value +will not be fetched and written to the output link until three seconds have +lapsed. + +=fields DLY0, DLY1, DLY2, DLY3, DLY4, DLY5, DLY6, DLY7, DLY8, DLY9, DLYA, DLYB, DLYC, DLYD, DLYE, DLYF + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. The +Precision field (PREC) determines the decimal precision for the VAL field when +it is displayed. It is used when the C<<< get_precision >>> record routine is +called. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields PREC, NAME, DESC + +=head3 Alarm Parameters + +The sequence record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head2 Record Support + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +First, PACT is set to TRUE, and the link selection is fetched. Depending on the +selection mechanism, the link selection output links are processed in order from +LNK0 to LNKF. When LNKI is processed, the corresponding DLYI value is +used to generate a delay via watchdog timer. + +=item 2. + +After DLYI seconds have expired, the input value is fetched from DOI (if +DOLI is constant) or DOLI (if DOLI is a database link or channel +access link) and written to LNKI. + +=item 3. + +When all links are completed, an asynchronous completion call back to dbProcess +is made (see the Application Developer's Guide for more information on +asynchronous processing.) + +=item 4. + +Then UDF is set to FALSE. + +=item 5. + +Monitors are checked. + +=item 6. + +The forward link is scanned, PACT is set FALSE, and the process routine returns. + +=back + +For the delay mechanism to operate properly, the record is processed +asynchronously. The only time the record will not be processed asynchronously is +when there are no non-NULL output links selected (i.e. when it has nothing to +do.) The processing of the links is done via callback tasks at the priority set +in the PRIO field in dbCommon (see the Application Developer's Guide for more +information on call + +=cut + include "dbCommon.dbd" field(VAL,DBF_LONG) { prompt("Used to trigger") From 90d9be1c00ebff5dee4341ab95a57bb92850b2c6 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 11:53:28 +0200 Subject: [PATCH 112/281] Renaming mbbiRecord.dbd with POD file extension --- src/std/rec/{mbbiRecord.dbd => mbbiRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{mbbiRecord.dbd => mbbiRecord.dbd.pod} (100%) diff --git a/src/std/rec/mbbiRecord.dbd b/src/std/rec/mbbiRecord.dbd.pod similarity index 100% rename from src/std/rec/mbbiRecord.dbd rename to src/std/rec/mbbiRecord.dbd.pod From 4f31205188c9ebf3604ad151c5f05bd1386c877b Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 11:56:46 +0200 Subject: [PATCH 113/281] Rename stringinRecord.dbd -> stringinRecord.dbd.pod --- src/std/rec/{stringinRecord.dbd => stringinRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{stringinRecord.dbd => stringinRecord.dbd.pod} (100%) diff --git a/src/std/rec/stringinRecord.dbd b/src/std/rec/stringinRecord.dbd.pod similarity index 100% rename from src/std/rec/stringinRecord.dbd rename to src/std/rec/stringinRecord.dbd.pod From 6905ded0d059d56a3b346956102ac2d9c532c340 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 12:14:55 +0200 Subject: [PATCH 114/281] First version of mbbi POD file --- src/std/rec/mbbiRecord.dbd.pod | 507 +++++++++++++++++++++++++++++++++ 1 file changed, 507 insertions(+) diff --git a/src/std/rec/mbbiRecord.dbd.pod b/src/std/rec/mbbiRecord.dbd.pod index 1f5724c92..2bbda6686 100644 --- a/src/std/rec/mbbiRecord.dbd.pod +++ b/src/std/rec/mbbiRecord.dbd.pod @@ -6,7 +6,186 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 B + +The normal use for the multi-bit binary input record is to read contiguous, +multiple bit inputs from hardware. The binary value represents a state from a +range of up to 16 states. The multi-bit input record interfaces with devices +that use more than one bit. + +Most device support modules obtain values from hardware and place the value in +RVAL. For these device support modules record processing uses RVAL to determine +the current state (VAL is given a value between 0 and 15). Device support +modules may optionally read a value directly into VAL. + +Soft device modules are provided to obtain input via database or channel access +links or via dbPutField or dbPutLink requests. Two soft device support modules +are provided: C<<< Soft Channel >>> allows VAL to be an arbitrary unsigned short +integer. C<<< Raw Soft Channel >>> reads the value into RVAL just like normal +device support modules. + +=head1 L + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +


+ +=end html + +=recordtype mbbi + +=cut + recordtype(mbbi) { + +=head2 Parameter Fields + +The multi-bit binary input fields fall into the following categories: + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=head3 Scan Parameters + +The multi-bit binary input record has the standard fields for specifying under +what circumstances it will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Read and Convert Parameters + +The device support routines obtain the record's input from the device or link +specified in the INP field. For records that obtain their input from devices, +the INP field must contain the address of the I/O card, and the DTYP field must +specify the proper device support module. Be aware that the address format +differs according to the I/O bus used. See L
for +information on the format of hardware addresses. + +Two soft device support modules can be specified in DTYP C and +C<<< Raw Soft Channel >>>. + +C<<< Raw Soft Channel >>> reads the value into RVAL, +upon which the normal conversion process is undergone. C<<< Soft Channel >>> +reads any unsigned integer directly into VAL. For a soft mbbi record, the INP +field can be a constant, a database, or a channel access link. If INP is a +constant, then the VAL is initialized to the constant value but can be changed +at run-time via dbPutField or dbPutLink. See L
for +information on the format of database addresses. + +MASK is used by the raw soft channel read routine, and by typical device support +read routines, to select only the desired bits when reading the hardware +register. It is initialized to ((1 EE NOBT) - 1) by record +initialization. The user can configure the NOBT field, but the device support +routines may set it, in which case the value given to it by the user is simply +overridden. The device support routines may also override MASK or shift it +left by SHFT bits. If MASK is non-zero, only the bits specified by MASK will +appear in RVAL. + +Unless the device support routine specifies no conversion, RVAL is used to +determine VAL as follows: + +=over + +=item 1. + +RVAL is assigned to a temporary variable -- rval = RVAL + +=item 2. + +rval is shifted right SHFT number of bits. + +=item 3. + +A match is sought between rval and one of the state value fields, ZRVL-FFVL. + +=back + +Each of the fields, ZRVL-FFVL, represents one of the possible sixteen states +(not all sixteen have to be used). + +Alternatively, the input value can be read as a string, in which case, a match +is sought with one of the strings specified in the ZRST-FFST fields. Then RVAL +is set equal to the corresponding value for that string, and the conversion +process occurs. + +=fields VAL, INP, MASK, NOBT, RVAL, SHFT, ZRVL, ONVL, TWVL, THVL, FRVL, FVVL, SXVL, SVVL, EIVL, NIVL, TEVL, ELVL, TVVL, TTVL, FTVL, FFVL + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the mbbi record either textually or +graphically. The ZRST-FFST fields contain strings describing one of the possible +states of the record. The C<<< get_enum_str >>> and C<<< get_enum_strs >>> +record routines retrieve these strings for the operator. C<<< Get_enum_str >>> +gets the string corresponding to the value set in VAL, and C<<< get_enum_strs +>>> retrieves all the strings. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC, ZRST, ONST, TWST, THST, FRST, FVST, SXST, SVST, EIST, NIST, TEST, ELST, TVST, TTST, FTST, FFST + +=cut + include "dbCommon.dbd" field(VAL,DBF_ENUM) { prompt("Current Value") @@ -281,6 +460,30 @@ recordtype(mbbi) { interest(1) size(26) } + +=head3 Alarm Parameters + +The possible alarm conditions for multi-bit binary inputs are the SCAN, READ, +and state alarms. The state alarms are configured in the below severity fields. +These fields have the usual possible values for severity fields: NO_ALARM, +MINOR, and MAJOR. + +The unknown state severity (UNSV) field, if set to MINOR or MAJOR, triggers an +alarm when the record support routine cannot find a matching value in the state +value fields for C<<< rval >>>. + +The change of state severity (COSV) field triggers an alarm when any change of +state occurs, if set to MAJOR or MINOR. + +The other fields, when set to MAJOR or MINOR, trigger an alarm when VAL equals +the corresponding state. See the See L for a complete +explanation of discrete alarms and these fields. L lists other +fields related to a alarms that are common to all record types. + +=fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV + +=cut + field(ZRSV,DBF_MENU) { prompt("State Zero Severity") promptgroup("71 - Alarm 0-7") @@ -417,6 +620,26 @@ recordtype(mbbi) { interest(1) menu(menuAlarmSevr) } + +=head3 Run-time Parameters + +These parameters are used by the run-time code for processing the multi-bit +binary input. + +ORAW is used by record processing to hold the prior RVAL for use in determining +when to post a monitor event for the RVAL field. + +The LALM field implements the change of state alarm severity by holding the +value of VAL when the previous change of state alarm was issued. + +MLST holds the value when the last monitor for value change was triggered. + +SDEF is used by record support to save time if no states are defined. + +=fields ORAW, LALM, MLST, SDEF + +=cut + field(RVAL,DBF_ULONG) { prompt("Raw Value") pp(TRUE) @@ -451,6 +674,16 @@ recordtype(mbbi) { promptgroup("40 - Input") interest(1) } + +=head3 Simulation Mode Parameters + +The following fields are used to operate the mbbi record in the simulation mode. +See L for more information on these fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS + +=cut + field(SIOL,DBF_INLINK) { prompt("Sim Input Specifctn") promptgroup("90 - Simulate") @@ -475,4 +708,278 @@ recordtype(mbbi) { interest(2) menu(menuAlarmSevr) } + +=pod + +=begin html + +


+ +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +Clears MASK and then sets the NOBT low order bits. + +If device support includes C, it is called. + +init_common is then called to determine if any states are defined. If states are +defined, SDEF is set to TRUE. + +=head4 process + +See next section. + +=head4 special + +Calls init_common to compute SDEF when any of the fields ZRVL, ... FFVL change +value. + +=head4 get_enum_str + +Retrieves ASCII string corresponding to VAL. + +=head4 get_enum_strs + +Retrieves ASCII strings for ZRST,...FFST. + +=head4 put_enum_str + +Checks if string matches ZRST,...FFST and if it does, sets VAL. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See L for more information. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Convert: + +=over + +=item * status=read_mbbi + +=item * PACT = TRUE + +=item * C is called. + +=item * If status is 0, then determine VAL + +=over + +=item * Set rval = RVAL + +=item * Shift rval right SHFT bits + +=back + +=item * If at least one state value is defined + +=over + +=item * Set UDF to TRUE + +=back + +=item * If RVAL is ZRVL,...,FFVL then set + +=over + +=item * VAL equals index of state + +=item * UDF set to FALSE + +=back + +=item * Else set VAL = undefined + +=over + +=item * Else set VAL = RVAL + +=back + +=item * Set UDF to FALSE + +=over + +=item * If status is 1, return 0 + +=item * If status is 2, set status = 0 + +=back + +=back + +=item 5. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. + +=item 6. + +Check to see if monitors should be invoked. + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has changed. + +=item * Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * Monitors for RVAL are checked whenever other monitors are invoked. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 7. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each input record must have an associated set of device support routines. + +The primary responsibility of the device support routines is to obtain a new raw +input value whenever read_mbbi is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, VAL, INP, RVAL, MASK, SHFT + +=begin html + +


+ +=end html + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. If it uses MASK, it should shift it as necessary and +also give SHFT a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the record is +being (added to, deleted from) an I/O event list. It must be provided for any +device type that can use the I/O Event scanner. + +=head4 read_mbbi + + read_mbbi(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. A new raw value is placed in RVAL. The record support module +determines VAL from RVAL, SHFT, and ZEVL ... FFVL. + +=item * + +2: Success, but don't modify VAL. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +Two soft device support modules C<<< Soft Channel >>> and C<<< Raw Soft Channel +>>> are provided for multi-bit binary input records not related to actual +hardware devices. The INP link type must be either CONSTANT, DB_LINK, or +CA_LINK. + +=head4 Soft Channel + +read_mbbi always returns a value of 2, which means that no conversion is +performed. + +If the INP link type is constant, then the constant value is stored into VAL by +C, and UDF is set to FALSE. VAL can be changed via dbPut +requests. If the INP link type is PV_LINK, then dbCaAddInlink is called by +C. + +read_mbbi calls recGblGetLinkValue to read the current value of VAL. See L. + +If the return status of recGblGetLinkValue is zero, then read_mbbi sets UDF to +FALSE. The status of recGblGetLinkValue is returned. + +=head4 Raw Soft Channel + +This module is like the previous except that values are read into RVAL, VAL is +computed from RVAL, and read_mbbi returns a value of 0. Thus the record +processing routine will determine VAL in the normal way. + + +=cut + } From db6825f62ed90ac0cb83328a9992c661140e1afd Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 13:13:46 +0200 Subject: [PATCH 115/281] Rename selRecord.dbd selRecord.dbd.pod --- src/std/rec/{selRecord.dbd => selRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{selRecord.dbd => selRecord.dbd.pod} (100%) diff --git a/src/std/rec/selRecord.dbd b/src/std/rec/selRecord.dbd.pod similarity index 100% rename from src/std/rec/selRecord.dbd rename to src/std/rec/selRecord.dbd.pod From 44149c170e54999b32aa52109be26885c9173642 Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 13:14:48 +0200 Subject: [PATCH 116/281] Add POD annotations to selRecord from Wiki --- src/std/rec/selRecord.dbd.pod | 330 ++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) diff --git a/src/std/rec/selRecord.dbd.pod b/src/std/rec/selRecord.dbd.pod index 724482704..6eb88942b 100644 --- a/src/std/rec/selRecord.dbd.pod +++ b/src/std/rec/selRecord.dbd.pod @@ -6,6 +6,64 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=pod + +=head1 Select Record (sel) + +The select record computes a value based on input obtained from up to 12 +locations. The selection algorithm can be one of the following: C<<< Specified +>>>, C<<< High Signal >>>, C<<< Low Signal >>>, C<<< Median Signal >>>. Each +input can be a constant, a database link, or a channel access link. + +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L for more information. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. It also honors the +alarm hysteresis factor (HYST). Thus the value must change by more than HYST +before the alarm status and severity is lowered. + +=item 5. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if ADEL and MDEL conditions are +met. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each long input record must have an associated set of device support routines. +The primary responsibility of the device support routines is to obtain a new +input value whenever read_longin is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, VAL, INP + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 read_longin + + read_longin(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. A new value is placed in VAL. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C<<< Soft Channel >>> device support module places a value directly in VAL. + +If the INP link type is constant, then the constant value is stored into VAL by +C, and UDF is set to FALSE. If the INP link type is PV_LINK, then +dbCaAddInlink is called by C. + +C<<< read_longin >>> calls recGblGetLinkValue to read the current value of VAL. +See L for more information + +If the return status of C<<< recGblGetLinkValue >>> is zero then read_longin +sets UDF to FALSE. read_longin returns the status of C. + + +=cut + include "dbCommon.dbd" field(VAL,DBF_LONG) { prompt("Current value") From a3d0699b8490994260e115c9e79deefb89562624 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 13:59:31 +0200 Subject: [PATCH 121/281] Rename longoutRecord.dbd longoutRecord.dbd.pod --- src/std/rec/{longoutRecord.dbd => longoutRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{longoutRecord.dbd => longoutRecord.dbd.pod} (100%) diff --git a/src/std/rec/longoutRecord.dbd b/src/std/rec/longoutRecord.dbd.pod similarity index 100% rename from src/std/rec/longoutRecord.dbd rename to src/std/rec/longoutRecord.dbd.pod From eac3d2719b0697a6b03b275b7bea661843d8bcd5 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 14:00:17 +0200 Subject: [PATCH 122/281] Add POD annotations to longoutRecord from Wiki --- src/std/rec/longoutRecord.dbd.pod | 434 +++++++++++++++++++++++++++++- 1 file changed, 433 insertions(+), 1 deletion(-) diff --git a/src/std/rec/longoutRecord.dbd.pod b/src/std/rec/longoutRecord.dbd.pod index c3ba0b977..5d8dd9320 100644 --- a/src/std/rec/longoutRecord.dbd.pod +++ b/src/std/rec/longoutRecord.dbd.pod @@ -6,7 +6,149 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 B + +The normal use for the long output or "longout" record type is to store long +integer values of up to 32 bits and write them to hardware devices. The C<<< +Soft Channel >>> device support routine can also be used to write values to +other records via database or channel access links. The OUT field determines how +the record is used. The record supports alarm limits and graphics and control +limits. + +=head1 L + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +


+ +=end html + +=recordtype longout + +=cut + recordtype(longout) { + +=head2 Parameter Fields + +The fields in this record fall into the following categories: + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=head3 Scan Parameters + +The longout record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. Note +that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Desired Output Parameters + +The record must specify where the desired output originates, i.e., the 32 bit +integer value it is to write. The output mode select (OMSL) field determines +whether the output originates from another record or from database access. When +set to C<<< closed_loop >>>, the desired output is retrieved from the link +specified in the desired output (DOL) field (which can specify either a database +or channel access link) and placed into the VAL field. When set to C<<< +supervisory >>>, the desired output can be written into the VAL field via dpPuts +at run-time. + +A third type of value for the DOL field is a constant in which case, when the +record is initialized, the VAL field will be initialized with this constant +value. + +The VAL field's value will be clipped within limits specified in the fields DRVH +and DRVL if these have been configured by the database designer: + + DRVL <= VAL <= DRVH + +Note: These limits are only enforced as long as DRVH E DRVL. If they are not +set or DRVH E= DRVL they will not be used. + +=fields DOL, OMSL, DRVH, DRVL, VAL + +=head3 Write Parameters + +The OUT link field determines where the record is to send its output. For +records that write values to hardware devices, the OUT output link field must +specify the address of the I/O card, and the DTYP field must specify the +name of the corresponding device support module. + +For soft records, the OUT output link can be a constant, a database link, or a +channel access link. If the link is a constant, the result is no output. The +DTYP field must then specify the C<<< Soft Channel >>> device support routine. + +See L
for information on the format of hardware addresses +and database links. + +=fields OUT, DTYP + +=cut + include "dbCommon.dbd" field(VAL,DBF_LONG) { prompt("Desired Output") @@ -30,6 +172,27 @@ recordtype(longout) { interest(1) menu(menuOmsl) } + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the long output either textually or +graphically. + +EGU is a string of up to 16 characters describing the units that the long output +measures. It is retrieved by the C<<< get_units >>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for the VAL, +HIHI, HIGH, LOW, and LOLO fields. Both the C<<< get_graphic_double >>> and C<<< +get_control_double >>> record support routines retrieve these fields. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields EGU, HOPR, LOPR, NAME, DESC + +=cut + field(EGU,DBF_STRING) { prompt("Engineering Units") promptgroup("80 - Display") @@ -63,6 +226,29 @@ recordtype(longout) { interest(1) prop(YES) } + +=head3 Alarm Parameters + +The possible alarm conditions for long inputs are the SCAN, READ, INVALID, and +limit alarms. The SCAN and READ alarms are not configurable by the user because +their severity is always MAJOR. The INVALID alarm is called by the record +support routine when the record or device support routines cannot write the +record's output. The IVOA field specifies the action to take in this case. + +The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW +fields using floating-point values. For each of these fields, there is a +corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The +HYST field contains the alarm deadband around each limit alarm. + +See the See L for a complete explanation of alarms and +these fields. For an explanation of the IVOA and IVOV fields, see L. L lists other fields related to a alarms that are common +to all record types. + +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV + +=cut + field(HIHI,DBF_LONG) { prompt("Hihi Alarm Limit") promptgroup("70 - Alarm") @@ -124,6 +310,22 @@ recordtype(longout) { promptgroup("70 - Alarm") interest(1) } + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the value +field. The monitors are sent when the value field exceeds the last monitored +field by the appropriate delta. If these fields have a value of zero, everytime +the value changes, a monitor will be triggered; if they have a value of -1, +everytime the record is scanned, monitors are triggered. The ADEL field is the +delta for archive monitors, and the MDEL field is the delta for all other types +of monitors. See L for a complete explanation of +monitors. + +=fields ADEL, MDEL + +=cut + field(ADEL,DBF_LONG) { prompt("Archive Deadband") promptgroup("80 - Display") @@ -149,6 +351,25 @@ recordtype(longout) { special(SPC_NOMOD) interest(3) } + +=head3 Run-time and Simulation Mode Parameters + +The LALM, MLST, and ALST fields are used to implement the hysteresis factors for +monitor callbacks. Only if the difference between these fields and the +corresponding value field is greater than the appropriate delta (MDEL, ADEL, +HYST)--only then are monitors triggered. For instance, only if the difference +between VAL and MLST is greater than MDEL are the monitors triggered for VAL. + +=fields LALM, ALST, MLST + +The following fields are used to operate the long output in the simulation mode. +See L for more information on the simulation +mode fields + +=fields SIOL, SIML, SIMM, SIMS + +=cut + field(SIOL,DBF_OUTLINK) { prompt("Sim Output Specifctn") promptgroup("90 - Simulate") @@ -181,4 +402,215 @@ recordtype(longout) { promptgroup("50 - Output") interest(2) } -} + + +=begin html + +


+ +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available. The routine +next checks to see if the device support write routine is defined. + +If either device support or the device support write routine does not exist, an +error message is issued and processing is terminated. + +If DOL is a constant, then VAL is initialized to its value and UDF is set to +FALSE. If DOL type is a PV_LINK then dbCaAddInlink is called to create a channel +access link. + +If device support includes C, it is called. + +=head4 process + +See next section. + +=head4 get_units + +Retrieves EGU. + +=head4 get_graphic_double + +Sets the upper display and lower display limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_control_double + +Sets the upper control and the lower control limits for a field. If the field is +VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the +field has upper and lower limits defined they will be used, else the upper and +lower maximum values for the field type will be used. + +=head4 get_alarm_double + +Sets the following values: + + upper_alarm_limit = HIHI + upper_warning_limit = HIGH + lower_warning_limit = LOW + lower_alarm_limit = LOLO + + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE and OMSL is CLOSED_LOOP recGblGetLinkValue is called to read +the current value of VAL. See L for more information. If the +return status of recGblGetLinkValue is zero then UDF is set to FALSE. + +=item 3. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. It also honors the +alarm hysteresis factor (HYST). Thus the value must change by more than HYST +before the alarm status and severity is lowered. + +=item 4. + +Check severity and write the new value. See L for +information on how INVALID alarms affect output records. + +=item 5. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 6. + +Check to see if monitors should be invoked: + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if ADEL and MDEL conditions are +met. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 7. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each long output record must have an associated set of device support routines. +The primary responsibility of the device support routines is to output a new +value whenever write_longout is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, OUT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 write_longout + + write_longout(precord) + +This routine must output a new value. It returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +The C<<< Soft Channel >>> module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_longout calls recGblPutLinkValue to write the current value of VAL. + +See L for a further explanation. + +=cut + +} #end of the DBD file From d7d142650b8f218074c3bf067c1b566f0f3e8db3 Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 14:11:20 +0200 Subject: [PATCH 123/281] Adding POD to stringin record --- src/std/rec/stringinRecord.dbd.pod | 301 ++++++++++++++++++++++++++++- 1 file changed, 295 insertions(+), 6 deletions(-) diff --git a/src/std/rec/stringinRecord.dbd.pod b/src/std/rec/stringinRecord.dbd.pod index 5b0b76813..2dd305502 100644 --- a/src/std/rec/stringinRecord.dbd.pod +++ b/src/std/rec/stringinRecord.dbd.pod @@ -6,6 +6,72 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 String Input Record (stringin) + +The string input record retrieves an arbitrary ASCII string of up to 40 +characters. Several device support routines are available, all of which are soft +device support for retrieving values from other records or other software +components. + +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +
+
+
+ +=end html + +=recordtype stringin + +=cut + menu(stringinPOST) { choice(stringinPOST_OnChange,"On Change") choice(stringinPOST_Always,"Always") @@ -19,17 +85,56 @@ recordtype(stringin) { pp(TRUE) size(40) } - field(OVAL,DBF_STRING) { - prompt("Previous Value") - special(SPC_NOMOD) - interest(3) - size(40) - } + +=head2 Parameter Fields + +=head3 Scan Parameters + +The string input record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in +L. +In addition, +L +explains how these fields are used. + +=head3 Read Parameters + +The INP field determines where the string input record gets its string. It can +be a database or channel access link, or a constant. If constant, the VAL field +is initialized with the constant and can be changed via dbPuts. Otherwise, the +string is read from the specified location each time the record is processed and +placed in the VAL field. The maximum number of characters that the string in VAL +can be is 40. In addition, the appropriate device support module must be entered +into the DTYP field. + +See L
+for information on specifying links. + +=fields VAL, INP, DTYP + +=cut + field(INP,DBF_INLINK) { prompt("Input Specification") promptgroup("40 - Input") interest(1) } + +=head3 Monitor Parameters + +These parameters are used to specify when the monitor post should be sent by +C routine. There are two possible choices: + +=head4 Menu stringinPOST + +=menu stringinPOST + +APST is used for archiver monitors and MPST is for all other type of monitors. + +=fields MPST, APST + +=cut + field(MPST,DBF_MENU) { prompt("Post Value Monitors") promptgroup("80 - Display") @@ -42,6 +147,44 @@ recordtype(stringin) { interest(1) menu(stringinPOST) } + +=head3 Operator Display Parameters + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The string input record has the alarm parameters common to all record types. +L +lists other fields related to a alarms that are common to all record types. + +=head3 Run-time and Simulation Mode Parameters + +The old value field (OVAL) of the string input is used to implement value change +monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered. + +=fields OVAL + + + +The following fields are used to operate the string input in the simulation +mode. See +L +for more information on simulation mode fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS + +=cut + + field(OVAL,DBF_STRING) { + prompt("Previous Value") + special(SPC_NOMOD) + interest(3) + size(40) + } field(SIOL,DBF_INLINK) { prompt("Sim Input Specifctn") promptgroup("90 - Simulate") @@ -68,4 +211,150 @@ recordtype(stringin) { interest(2) menu(menuAlarmSevr) } + +=begin html + +
+
+
+ +=end html + +=head2 Record Support + +=head3 Record Support Routines (stringinRecord.c) + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a record +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +If device support includes an C routine it is called. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See +L +for more information on simulation mode fields and how they affect input. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +C is called. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if OVAL is not equal to VAL. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
+
+
+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each stringin input record must have an associated set of device support +routines. The primary responsibility of the device support routines is to obtain +a new ASCII string value whenever read_stringin is called. The device support +routines are primarily interested in the following fields: + +=fields PACT, DPVT, UDF, VAL, INP + +=head3 Device Support Routines (devSiSoft.c) + +=head4 init_record + + long init_record(stringinRecord *prec) + +This routine is optional. If provided, it is called by the record support +C routine. + +=head4 read_stringin + + long read_stringin(stringinRecord *prec) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * 0: Success. A new ASCII string is stored into VAL. + +=item * Other: Error. + +=back + +=head3 Device Support for Soft Records + +The C<<< Soft Channel >>> module places a value directly in VAL. + +If the INP link type is constant, the double constant, if non-zero, is converted +to a string and stored into VAL by C, and UDF is set to FALSE. If +the INP link type is PV_LINK, then dbCaAddInlink is called by C. + +read_stringin calls recGblGetLinkValue to read the current value of VAL. See +L. + +If the return status of recGblGetLinkValue is zero, then read_stringin sets UDF +to FALSE. The status of recGblGetLinkValue is returned. + +=cut + } From 4f63bf139f085522ce1ab7d629076fef0f67fa9c Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 14:36:36 +0200 Subject: [PATCH 124/281] Rename stateRecord.dbd -> stateRecord.dbd.pod --- src/std/rec/{stateRecord.dbd => stateRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{stateRecord.dbd => stateRecord.dbd.pod} (100%) diff --git a/src/std/rec/stateRecord.dbd b/src/std/rec/stateRecord.dbd.pod similarity index 100% rename from src/std/rec/stateRecord.dbd rename to src/std/rec/stateRecord.dbd.pod From e5f86831448ca1d34563db3d67d55c55b256e5f8 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 15:00:52 +0200 Subject: [PATCH 125/281] Renaming dbd file to dbd.pod --- src/std/rec/{mbboDirectRecord.dbd => mbboDirectRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{mbboDirectRecord.dbd => mbboDirectRecord.dbd.pod} (100%) diff --git a/src/std/rec/mbboDirectRecord.dbd b/src/std/rec/mbboDirectRecord.dbd.pod similarity index 100% rename from src/std/rec/mbboDirectRecord.dbd rename to src/std/rec/mbboDirectRecord.dbd.pod From 4685f7567b32b3d58ae8bf3026b2b5a332022e12 Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 15:13:25 +0200 Subject: [PATCH 126/281] Rename permissiveRecord.dbd -> permissiveRecord.dbd.pod --- src/std/rec/{permissiveRecord.dbd => permissiveRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{permissiveRecord.dbd => permissiveRecord.dbd.pod} (100%) diff --git a/src/std/rec/permissiveRecord.dbd b/src/std/rec/permissiveRecord.dbd.pod similarity index 100% rename from src/std/rec/permissiveRecord.dbd rename to src/std/rec/permissiveRecord.dbd.pod From 9255256f1524fd7cc9cf43639aae65d397ac9cf6 Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 15:48:46 +0200 Subject: [PATCH 127/281] Added POD to permissive record with a note that it is deprecated. --- src/std/rec/permissiveRecord.dbd.pod | 150 +++++++++++++++++++++++++-- 1 file changed, 139 insertions(+), 11 deletions(-) diff --git a/src/std/rec/permissiveRecord.dbd.pod b/src/std/rec/permissiveRecord.dbd.pod index 7eb04bf95..8e0747fe9 100644 --- a/src/std/rec/permissiveRecord.dbd.pod +++ b/src/std/rec/permissiveRecord.dbd.pod @@ -6,8 +6,114 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Permissive Record (permissive) + +The permissive record is for communication between a server and a client. An +example would be a sequence program server and an operator interface client. By +using multiple permissive records a sequence program can communicate its current +state to the client. + +B + +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=back + +=back + +=begin html + +
+
+
+ +=end html + +=recordtype permissive + +=cut + recordtype(permissive) { include "dbCommon.dbd" + +=head2 Parameter Fields + +=head3 Scan Parameters + +The permissive record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. +In addition, +L + explains how these fields are used. Since the permissive record supports + no direct interfaces to hardware, its SCAN field cannot be C<<< I/O Intr >>>. + +=head3 Client-server Parameters + +The client and server communicate through the VAL and watchdog flag (WFLG) +fields. At initialization, both fields are set equal to 0, which means OFF. The +server sets WFLG equal to ON when it is ready to accept a request. The client +monitors WFLG and when WFLG equals 1, the client-server action is performed (a +private matter between server and client). + +When WFLG is off--when the server is busy--the client program may turn the VAL +field from OFF to ON. After the server finishes its task, it will notice that +VAL is ON and will turn both WFLG and VAL OFF and performs the requested +service. + +Note that when WFLG is ON, the client program ''must not'' turn VAL to on. + +=fields VAL, WFLG + +=cut + + field(VAL,DBF_USHORT) { + prompt("Status") + promptgroup("40 - Input") + asl(ASL0) + pp(TRUE) + } + field(WFLG,DBF_USHORT) { + prompt("Wait Flag") + pp(TRUE) + } + +=head3 Operator Display Parameters + +The label field (LABL) contains a string given to it that should describe the +record in further detail. In addition to the DESC field. See +L +for more on the record name (NAME) and description (DESC) fields. + +=fields LABL, NAME, DESC + +=cut + field(LABL,DBF_STRING) { prompt("Button Label") promptgroup("80 - Display") @@ -15,24 +121,46 @@ recordtype(permissive) { interest(1) size(20) } - field(VAL,DBF_USHORT) { - prompt("Status") - promptgroup("40 - Input") - asl(ASL0) - pp(TRUE) - } + +=head3 Alarm Parameters + +The Permissive record has the alarm parameters common to all record types. +L +lists other fields related to a alarms that are common to all record types. + +=head3 Run-time Parameters + +These fields are used to trigger monitors for each field. Monitors for the VAL +field are triggered when OVAL, the old value field, does not equal VAL. +Likewise, OFLG causes monitors to be invoked for WFLG when WFLG does not equal +OLFG. + +=fields OVAL, OFLG + +=cut + field(OVAL,DBF_USHORT) { prompt("Old Status") special(SPC_NOMOD) interest(3) } - field(WFLG,DBF_USHORT) { - prompt("Wait Flag") - pp(TRUE) - } field(OFLG,DBF_USHORT) { prompt("Old Flag") special(SPC_NOMOD) interest(3) } -} + +=head2 Record Support + +=head3 Record Support Routines (permissiveRecord.c) + +=head4 process + + long (*process)(struct dbCommon *precord) + +process sets UDF to FALSE, triggers monitors on VAL and WFLG when they change, +and scans the forward link if necessary. + +=cut + +} \ No newline at end of file From 0d3cc5a20a41fc7af4004585a9555d01d482e211 Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 15:03:23 +0200 Subject: [PATCH 128/281] Added POD to state record with a note that it is deprecated --- src/std/rec/stateRecord.dbd.pod | 99 +++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/src/std/rec/stateRecord.dbd.pod b/src/std/rec/stateRecord.dbd.pod index 6e43ddbba..8734f01bd 100644 --- a/src/std/rec/stateRecord.dbd.pod +++ b/src/std/rec/stateRecord.dbd.pod @@ -6,8 +6,93 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 State Record (state) + +The state record is a means for a state program to communicate with the operator +interface. Its only function is to provide a place in the database through which +the state program can inform the operator interface of its state by storing an +arbitrary ASCII string in its VAL field. + +B + +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=back + +=back + +=begin html + +
+
+
+ +=end html + +=recordtype state + +=cut + recordtype(state) { include "dbCommon.dbd" + +=head2 Parameter Fields + +=head3 Scan Parameters + +The state record has the standard fields for specifying under what circumstances +it will be processed. These fields are listed in +L. +In addition, +L +explains how these fields are used. + +=head3 Operator Display Parameters + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The state record has the alarm parameters common to all record types. +L +lists other fields related to a alarms that are common to all record types. + +=head3 Run-time Parameters + +These parameters are used by the application code to convey the state of the +program to the operator interface. The VAL field holds the string retrieved from +the state program. The OVAL is used to implement monitors for the VAL field. +When the string in OVAL differs from the one in VAL, monitors are triggered. +They represent the current state of the sequence program. + +=fields VAL, OVAL + +=cut + field(VAL,DBF_STRING) { prompt("Value") promptgroup("40 - Input") @@ -21,4 +106,18 @@ recordtype(state) { interest(3) size(20) } + +=head2 Record Support + +=head3 Record Support Routines (stateRecord.c) + +=head4 process + + long (*process)(struct dbCommon *precord) + +process triggers monitors on VAL when it changes and scans the forward link if +necessary. + +=cut + } From 9d4b652c5e66145f7fac0bea5e2a90939dc8b6e2 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Fri, 6 Sep 2019 17:20:54 +0200 Subject: [PATCH 129/281] First version of mbbo POD file --- src/std/rec/mbboDirectRecord.dbd.pod | 380 +++++++++++++++++++++++++++ 1 file changed, 380 insertions(+) diff --git a/src/std/rec/mbboDirectRecord.dbd.pod b/src/std/rec/mbboDirectRecord.dbd.pod index 0b4285e32..e730bc854 100644 --- a/src/std/rec/mbboDirectRecord.dbd.pod +++ b/src/std/rec/mbboDirectRecord.dbd.pod @@ -6,7 +6,153 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 B + +The mbboDirect record performs the opposite function to that of the mbbiDirect +record. It accumulates bits (in the fields B0 - BF) as unsigned characters, and +converts them to a word which is then written out to hardware. If a bit field is +non-zero, it is interpreted as a binary 1. On the other hand, if it is zero, it +is interpreted as a binary 0. + +=head1 L + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +


+ +=end html + +=recordtype mbboDirect + +=cut + recordtype(mbboDirect) { + +=head2 Parameter Fields + +The mbboDirect record's fields fall into the following categories: + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=head3 Scan Parameters + +The mbboDirect record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. Note +that I/O event scanning is only supported for those card types that +interrupt. + +=head3 Desired Output Parameters + +The mbboDirect record, like all output records, must specify where its output +originates. The output mode select field (OMSL) determines whether the output +originates from another record or from database access. When set to C<<< +closed_loop >>>, the desired output is retrieved from the link specified in the +desired output (DOL) field--which can specify either a database or channel +access link--and placed into the VAL field. When set to C<<< supervisory >>>, +the DOL field is ignored and the current value of VAL is used. The desired +output can be written into the VAL field via dpPuts at run-time when the record +is in C<<< supervisory >>> mode. DOL can also be a constant, in which case VAL +is initialized to the constant value. Note that OMSL cannot be C<<< closed_loop +>>> when DOL is a constant. See L
for information on how +to specify database links. + +VAL is then converted to RVAL in the routine described in the next section. +However, the C<<< Soft Channel >>> device support module for the mbboDirect +record writes the VAL field's value without any conversion. + +=fields OMSL, DOL, VAL + +=head3 Convert and Write Parameters + +For records that are to write values to hardware devices, the OUT output link +must contain the address of the I/O card, and the DTYP field must specify +the proper device support module. Be aware that the address format differs +according to the I/O bus used. See L
for information +on the format of hardware addresses. + +If the mbboDirect record does not use the C<<< Soft Channel >>> device support +module, then VAL is converted to RVAL, and RVAL is the actual 16-bit word sent +out. RVAL is set equal to VAL and then shifted left by the number of bits +specified in the SHFT field (the SHFT value is set by device support and is not +configurable by the user). RVAL is then sent out to the location specified in +the OUT field. + +For mbboDirect records that specify a database link, a channel access link, or a +constant, the DTYP field must specify either one of two soft device support +routines--{Soft Channel} or C<<< Raw Soft Channel >>>. The difference between +the two is that C<<< Soft Channel >>> writes the desired output value from VAL +directly to the output link while C<<< Raw Soft Channel >>> writes the value +from RVAL to the output link after it has undergone the conversion described +above. See L
for information on how to specify database +links. + +=fields OUT, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF + +=head3 Operator Display Parameters + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=cut + include "dbCommon.dbd" field(VAL,DBF_USHORT) { prompt("Word") @@ -184,6 +330,49 @@ recordtype(mbboDirect) { promptgroup("50 - Output") interest(1) } + +=head3 Alarm Parameters + +The possible alarm conditions for mbboDirect records are the SCAN, READ, and +INVALID alarms. The SCAN and READ alarms are not configurable by the user since +they are always of MAJOR severity. See L for a complete +explanation of Scan and Read alarms. + +The IVOA field specifies an action to take when the INVALID alarm is triggered. +There are three possible actions: C<<< Continue normally >>>, C<<< Don't drive +outputs >>>, or C<<< Set output to IVOV >>>. When C<<< Set output to IVOV >>> is +specified and a INVALID alarm is triggered, the record will write the value in +the IVOV field to output. See L for more +information. L lists other fields related to a alarms that are +common to all record types. + +=fields IVOA, IVOV + +=head3 Run-time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the mbbo Direct +record. + +MASK is used by device support routine to read the hardware register. Record +support sets low order NOBT bits. Device support can shift this value. + +MLST holds the value when the last monitor for value change was triggered. + +=fields NOBT, ORAW, MASK, MLST + +The following fields are used to operate the mbboDirect record in the simulation +mode. See L for more information on the simulation mode fields. + +=fields SIOL, SIML, SIMM, SIMS + +=begin html + +


+ +=end html + +=cut + field(SIOL,DBF_OUTLINK) { prompt("Sim Output Specifctn") promptgroup("90 - Simulate") @@ -216,4 +405,195 @@ recordtype(mbboDirect) { promptgroup("50 - Output") interest(2) } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available.The routine +next checks to see if the device support write routine is defined. If either +device support or the device support write routine does not exist, an error +message is issued and processing is terminated. + +If DOL is a constant, then VAL is initialized to its value and UDF is set to +FALSE. + +MASK is cleared and then the NOBT low order bits are set. + +If device support includes C, it is called. + +If device support returns success, VAL is then set from RVAL and UDF is set to +FALSE. + +=head4 Process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE + +=over + +=item * If DOL is DB_LINK and OMSL is CLOSED_LOOP + +=over + +=item * Get value from DOL + +=item * Set PACT to FALSE + +=back + +=back + +=item 3. + +Convert + +=over + +=item * If PACT is FALSE, compute RVAL + +=over + +=item * Set RVAL = VAL + +=item * Shift RVAL left SHFT bits + +=back + +=item * Status=write_mbboDirect + +=back + +=item 4. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has changed. + +=item * Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * Monitors for RVAL and RBV are checked whenever other monitors are invoked. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each mbboDirect record must have an associated set of device support routines. +The primary responsibility of the device support routines is to obtain a new raw +mbbo value whenever write_mbboDirect is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, OUT, RVAL, RBV, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. If MASK is used, it should be shifted if necessary and +SHFT given a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 write_mbboDirect + + write_mbboDirect(precord) + +This routine must output a new value. It returns the following values: + +=over + +=item * 0: Success. + +=item * Other: Error. + +=back + +=head3 Device Support For Soft Records + +This C<<< SOft Channel >>> module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_mbboDirect calls recGblPutLinkValue to write the current value of VAL. + +See L. + +=cut + } From 96e3e678e94a8e53e33c327a79097a9bfbdfe6ba Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 18:02:39 +0200 Subject: [PATCH 130/281] Rename subArrayRecord.dbd and menuAlarmStat.dbd to .pod --- src/ioc/db/{menuAlarmStat.dbd => menuAlarmStat.dbd.pod} | 0 src/std/rec/{subArrayRecord.dbd => subArrayRecord.dbd.pod} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/ioc/db/{menuAlarmStat.dbd => menuAlarmStat.dbd.pod} (100%) rename src/std/rec/{subArrayRecord.dbd => subArrayRecord.dbd.pod} (100%) diff --git a/src/ioc/db/menuAlarmStat.dbd b/src/ioc/db/menuAlarmStat.dbd.pod similarity index 100% rename from src/ioc/db/menuAlarmStat.dbd rename to src/ioc/db/menuAlarmStat.dbd.pod diff --git a/src/std/rec/subArrayRecord.dbd b/src/std/rec/subArrayRecord.dbd.pod similarity index 100% rename from src/std/rec/subArrayRecord.dbd rename to src/std/rec/subArrayRecord.dbd.pod From f70c17ee69f495ff005bb674abcc1789e5736d7d Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 18:20:43 +0200 Subject: [PATCH 131/281] Add POD annotations from Wiki to subArrayRecord and menuAlarmStat --- src/ioc/db/menuAlarmStat.dbd.pod | 11 + src/std/rec/subArrayRecord.dbd.pod | 365 +++++++++++++++++++++++++++++ 2 files changed, 376 insertions(+) diff --git a/src/ioc/db/menuAlarmStat.dbd.pod b/src/ioc/db/menuAlarmStat.dbd.pod index e8d7f1ced..78debf8c5 100644 --- a/src/ioc/db/menuAlarmStat.dbd.pod +++ b/src/ioc/db/menuAlarmStat.dbd.pod @@ -7,6 +7,17 @@ # and higher are distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuAlarmStat + +This menu defines the possible alarm statuses that EPICS records can exhibit +which is used for C and C fields of all record types. +See L for more information. + +=menu menuAlarmStat + +=cut + menu(menuAlarmStat) { choice(menuAlarmStatNO_ALARM,"NO_ALARM") choice(menuAlarmStatREAD,"READ") diff --git a/src/std/rec/subArrayRecord.dbd.pod b/src/std/rec/subArrayRecord.dbd.pod index 7814a2e48..ac4454f6f 100644 --- a/src/std/rec/subArrayRecord.dbd.pod +++ b/src/std/rec/subArrayRecord.dbd.pod @@ -6,7 +6,372 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Sub-Array Record (subArray) + +The normal use for the subArray record type is to obtain sub-arrays from +waveform records. Setting either the number of elements (NELM) or index (INDX) +fields causes the record to be processed anew so that applications in which the +length and position of a sub-array in a waveform record vary dynamically can be +implemented using standard EPICS operator interface tools. + +The first element of the sub-array, that at location INDX in the referenced +waveform record, can be displayed as a scalar, or the entire subarray (of length +NELM) can be displayed in the same way as a waveform record. If there are fewer +than NELM elements in the referenced waveform after the INDX, only the number of +elements actually available are returned, and the number of elements read field +(NORD) is set to reflect this. This record type does not support writing new +values into waveform records. + +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +
+
+
+ +=end html + +=recordtype subArray + +=cut + recordtype(subArray) { + +=head2 Parameter Fields + +=head3 Scan Parameters + +The subArray record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in +L. +In addition, +L +explains how these fields are used. + +=head3 Read Parameters + +The subArray's input link (INP) should be configured to reference the Waveform +record. It should specify the VAL field of a Waveform record. The INP field can +be a channel access link, in addition to a database link. See +L
+for information on specifying links. + +In addition, the DTYP field must specify a device support module. Currently, the +only device support module is C<<< Soft Channel >>>. + +=fields INP, DTYP + +=head3 Array Parameters + +These parameters determine the number of array elements (the array length) and +the data type of those elements. The Field Type of Value (FTVL) field determines +the data type of the array. + +The user specifies the maximum number of elements allowed in the subarray in the +MALM field. Generally, the number should be equal to the number of elements of +the Waveform array (found in the Waveform's NELM field). The MALM field is used +to allocate memory. The subArray's Number of Elements (NELM) field is where the +user specifies the actual number of elements that the subArray will contain. It +should of course be no greater than MALM; if it is, the record processing +routine sets it equal to MALM. + +The INDX field determines the offset of the subArray record's array in relation +to the Waveform's. For instance, if INDX is 2, then the subArray will read NELM +elements starting with the third element of the Waveform's array. Thus, it +equals the index number of the Waveform's array. + +The actual sub-array is referenced by the VAL field. + +=fields FTVL, VAL, MALM, NELM, INDX + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. They +display the value and other parameters of the subarray record either textually +or graphically. + +EGU is a string of up to 16 characters describing the engineering units (if any) +of the values which the subArray holds. It is retrieved by the C<<< get_units +>>> record support routine. + +The HOPR and LOPR fields set the upper and lower display limits for the +sub-array elements. Both the C<<< get_graphic_double >>> and C<<< +get_control_double >>> record support routines retrieve these fields. + +The PREC field determines the floating point precision with which to display +VAL. It is used whenever the C<<< get_precision >>> record support routine is +called. + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields EGU, HOPR, LOPR, PREC, NAME, DESC + +=head3 Alarm Parameters + +The subarray record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. + +=head3 Run-time Parameters + +These fields are not configurable by the user. They are used for the record's +internal processing or to represent the current state of the record. + +The NORD field holds a counter of the number of elements read into the array. It +can be less than NELM even after the array is full if NELM exceeds the number of +existing elements in the referenced array, i.e., the Waveform's array. + +BPTR contains a pointer to the record's array. + +=fields NORD, BPTR + +=begin html + +
+
+
+ +=end html + +=head2 Record Support + +=head3 Record Support Routines (subArrayRecord.c) + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +Using MALM and FTVL, space for the array is allocated. The array address is +stored in BPTR. This routine checks to see that device support is available and +a device support read routine is defined. If either does not exist, an error +message is issued and processing is terminated. If device support includes +C, it is called. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head4 cvt_dbaddr + + long (*cvt_dbaddr)(struct dbAddr *paddr) + +This is called by dbNameToAddr. It makes the dbAddr structure refer to the +actual buffer holding the result. + +=head4 get_array_info + + long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset) + +Retrieves NELM. + +=head4 put_array_info + + long (*put_array_info)(struct dbAddr *paddr, long nNew) + +Sets NORD. + +=head4 get_graphic_double + + long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p) + +For the elements in the array, this routine routines HOPR and LOPR. For the INDX +field, this routine returns MALM - 1 and 0. For NELM, it returns MALM and 1. For +other fields, it calls C<<< recGblGetGraphicDouble() >>>. + +=head4 get_control_double + + long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p) + +For array elements, this routine retrieves HOPR and LOPR. Otherwise, C<<< +recGblGetControlDouble() >>> is called. + +=head4 get_units + + long (*get_units)(struct dbAddr *paddr, char *units) + +Retrieves EGU. + +=head4 get_precision + + long (*get_precision)(const struct dbAddr *paddr, long *precision) + +Retrieves PREC. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +Sanity check NELM and INDX. If NELM is greater than MALM it is set to MALM. If +INDX is greater than or equal to MALM it is set to MALM-1. + +=item 3. + +Call device support read routine. This routine is expected to place the desired +sub-array at the beginning of the buffer and set NORD to the number of elements +of the sub-array that were read. + +=item 4. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed writing the new value. In this case, the processing +routine merely returns, leaving PACT TRUE. Otherwise, process sets PACT TRUE at +this time. This asynchronous processing logic is not currently used but has been +left in place. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are always invoked. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
+
+
+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +The device support routines are primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, INP, FTVL, MALM, NELM, INDX, BPTR, NORD + +=head3 Device Support Routines (devSASoft.c) + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + long init_record(subArrayRecord *prec) + +This routine is called by the record support C routine. + +=head4 read_sa + + long read_sa(subArrayRecord *prec) + +Enough of the source waveform is read into BPTR, from the beginning of the +source, to include the requested sub-array. The sub-array is then copied to the +beginning of the buffer. NORD is set to indicate how many elements of the +sub-array were acquired. + +=head3 Device Support For Soft Records + +Only the device support module C<<< Soft Channel >>> is currently provided. The +INP link type must be either DB_LINK or CA_LINK. + +=head4 Soft Channel + +INP is expected to point to a waveform record. + +=cut + include "dbCommon.dbd" field(VAL,DBF_NOACCESS) { prompt("Value") From 704e6251e6ba1d7a8f860cb4c868f869514c541d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 6 Sep 2019 18:33:55 +0200 Subject: [PATCH 132/281] Remove links to wiki-ext --- src/std/rec/compressRecord.dbd.pod | 35 +++++++++++++-------------- src/std/rec/selRecord.dbd.pod | 38 +++++++++++++----------------- src/std/rec/subRecord.dbd.pod | 28 +++++++++------------- 3 files changed, 44 insertions(+), 57 deletions(-) diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index f0a586baa..209e8d1f8 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -78,10 +78,9 @@ recordtype(compress) { =head3 Scanning Parameters The compression record has the standard fields for specifying under what -circumstances the record will be processed. These fields are listed in -L. In addition, -L -explains how these fields are used. Since the compression record supports no +circumstances the record will be processed. These fields are listed in +L. In addition, L +explains how these fields are used. Since the compression record supports no direct interfaces to hardware, its SCAN field cannot specify C<<< I/O Intr >>>. =head3 Algorithms and Related Parameters @@ -99,18 +98,17 @@ The following fields determine what channel to read and how to compress the data As stated above, the ALG field specifies which algorithm to be performed on the data. -The INP should be a database or channel access link. Though INP can be a constant, -the data compression algorithms are supported only when INP is a database link. See -L
-for information on specifying links. +The INP should be a database or channel access link. Though INP can be a constant, +the data compression algorithms are supported only when INP is a database link. See +L
for information on specifying links. IHIL and ILIL can be set to provide an initial value filter on the input array. -If ILIL E IHIL, the input elements will be skipped until a value is found -that is in the range of ILIL to IHIL. Note that ILIL and IHIL are used only in +If ILIL E IHIL, the input elements will be skipped until a value is found +that is in the range of ILIL to IHIL. Note that ILIL and IHIL are used only in C<<< N to 1 >>> algorithms. -OFF provides the offset to the current beginning of the array data. +OFF provides the offset to the current beginning of the array data. Note that OFF is used only in C<<< N to 1 >>> algorithms. The RES field can be accessed at run time to cause the algorithm to reset @@ -120,7 +118,7 @@ itself before the maximum number of samples are reached. B algorithm keeps a circular buffer of length NSAM. Each time the record is processed, it gets the data referenced by INP and puts -it into the circular buffer referenced by VAL. The INP can refer to both scalar or +it into the circular buffer referenced by VAL. The INP can refer to both scalar or array data and VAL is just a time ordered circular buffer of values obtained from INP. Note that N, ILIL, IHIL and OFF are not used in C<<< Circular Buffer >>> algorithm. @@ -144,7 +142,7 @@ shows the equation: B If any of the C<<< N to 1 >>> algorithms are chosen, then VAL is a circular buffer of NSAM samples. -The actual algorithm depends on whether INP references a scalar or an array. +The actual algorithm depends on whether INP references a scalar or an array. If INP refers to a scalar, then N successive time ordered samples of INP are taken. After the Nth sample is obtained, a new value determined by the algorithm @@ -201,21 +199,21 @@ graphically. The EGU field should be given a string that describes the value of VAL, but is used whenever the C<<< get_units >>> record support routine is called. -The HOPR and LOPR fields only specify the upper and lower display limits for +The HOPR and LOPR fields only specify the upper and lower display limits for VAL, HIHI, HIGH, LOLO and LOW fields. PREC controls the floating-point precision whenever C<<< get_precision >>> is called, and the field being referenced is the VAL field (i.e., one of the values contained in the circular buffer). -See L +See L for more on the record name (NAME) and description (DESC) fields. =head3 Alarm Parameters -The compression record has the alarm parameters common to all record types described in -L. +The compression record has the alarm parameters common to all record types +described in L. =head3 Run-time Parameters @@ -247,7 +245,7 @@ WPTR is used by the dbGetlinks routines. =head3 Record Support Routines (compressRecord.c) =head4 init_record - + long (*init_record)(struct dbCommon *precord, int pass) Space for all necessary arrays is allocated. The addresses are stored in the @@ -517,3 +515,4 @@ Scan forward link if necessary, set PACT FALSE, and return. interest(3) } } + diff --git a/src/std/rec/selRecord.dbd.pod b/src/std/rec/selRecord.dbd.pod index 6eb88942b..9e49745cc 100644 --- a/src/std/rec/selRecord.dbd.pod +++ b/src/std/rec/selRecord.dbd.pod @@ -77,10 +77,8 @@ recordtype(sel) { =head3 Scan Parameters The select record has the standard fields for specifying under what -circumstances the record will be processed. These fields are listed in -L. -In addition, -L +circumstances the record will be processed. These fields are listed in +L. In addition, L explains how these fields work. =head3 Read Parameters @@ -91,8 +89,7 @@ links configured by the user to be either constants, channel access links, or database links. If channel access or database links, a value is retrieved for each link and placed in the corresponding value field, A-L. If any input link is a constant, the value field for that link will be initialized with the constant -value given to it and can be modified via dbPuts. See -L
+value given to it and can be modified via dbPuts. See L
for information on how to specify database links. Any links not defined are ignored by the selection record and its algorithm. An @@ -111,24 +108,24 @@ The selection algorithm is determined by three fields configurable by the user: the select mechanism (SELM) field, the select number (SELN) field, and the index value location (NVL) field. -The SELM field has four choices, i.e., four algorithms as follows: +The SELM field has four choices, i.e., four algorithms as follows: =head4 Menu selSELM =menu selSELM -The selection record's VAL field is determined differently for each algorithm. -For C<<< Specified >>>, the VAL field is set equal to the value field (A, B, C, -D, E, F, G, H, I, J, K, or L) specified by the SELN field. The SELN field contains a +The selection record's VAL field is determined differently for each algorithm. +For C<<< Specified >>>, the VAL field is set equal to the value field (A, B, C, +D, E, F, G, H, I, J, K, or L) specified by the SELN field. The SELN field +contains a number from 0-11 which corresponds to the value field to be used (0 means use A; 1 means use B, etc.). How the NVL field is configured determines, in turn, SELN's value. NVL is an input link from which a value for SELN can be retrieved, Like most other input links NVL can be a constant, or a channel access or database link. If NVL is a link, SELN is retrieved from the location in NVL. If a constant, SELN is initialized to the value given to the constant and can be -changed via dbPuts. See -L
-for information on how to specify database links. +changed via dbPuts. See L
for information on how to +specify database links. The C<<< High Signal >>>, C<<< Low Signal >>>, and C<<< Median Signal >>> algorithms do not use SELN or NVL. If C<<< High Signal >>> is chosen, VAL is set @@ -160,9 +157,8 @@ The PREC field determines the floating point precision with which to display VAL. It is used whenever the C<<< get_precision >>> record support routine is called. -See -L -for more on the record name (NAME) and description (DESC) fields. +See L for more on the record name (NAME) +and description (DESC) fields. =fields EGU, HOPR, LOPR, PREC, NAME, DESC @@ -173,10 +169,8 @@ alarms. The SCAN and READ alarms are called by the record or device support routines. The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW fields using numerical values. They specify conditions for the VAL field. For each of these fields, there is a corresponding severity field which -can be either NO_ALARM, MINOR, or MAJOR. See -L -for a complete explanation of alarms and these fields. -L +can be either NO_ALARM, MINOR, or MAJOR. See L +for a complete explanation of alarms and these fields. L lists other fields related to a alarms that are common to all record types. =fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST @@ -188,8 +182,7 @@ archiver and monitor calls for the VAL field. Unless, VAL changes by more than the value specified by each, then the respective monitors will not be called. If these fields have a value of zero, everytime the VAL changes, monitors are triggered; if they have a value of -1, everytime the record is processed, -monitors are triggered. -L +monitors are triggered. L gives a complete explanation of alarms and deadbands. =fields ADEL, MDEL @@ -651,3 +644,4 @@ Scan forward link if necessary, set PACT FALSE, and return. interest(3) } } + diff --git a/src/std/rec/subRecord.dbd.pod b/src/std/rec/subRecord.dbd.pod index c5027284c..1e2f25dde 100644 --- a/src/std/rec/subRecord.dbd.pod +++ b/src/std/rec/subRecord.dbd.pod @@ -10,7 +10,7 @@ =head1 Subroutine Record (sub) The subroutine record is used to call a C initialization routine and a recurring -scan routine. There is no device support for this record. +scan routine. There is no device support for this record. =head2 Contents @@ -71,10 +71,8 @@ recordtype(sub) { =head3 Scan Parameters The subroutine record has the standard fields for specifying under what -circumstances it will be processed. These fields are listed in -L. -In addition, -L +circumstances it will be processed. These fields are listed in +L. In addition, L explains how these fields are used. =head3 Read Parameters @@ -87,16 +85,14 @@ The input links can be either channel access or database links, or constants. When constants, the corresponding value field for the link is initialized with the constant value and the field's value can be changed at run-time via dbPuts. Otherwise, the values for (A-F) are fetched from the input links when the record -is processed. See -L
-for information on specifying links. +is processed. See L
for information on specifying links. =fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL, A, B, C, D, E, F, G, H, I, J, K, L =head3 Subroutine Connection These fields are used to connect to the C subroutine. The name of the subroutine -should be entered in the SNAM field. +should be entered in the SNAM field. =fields INAM, SNAM @@ -119,7 +115,7 @@ The PREC field determines the floating point precision with which to display VAL. It is used whenever the C<<< get_precision >>> record support routine is called. -See L +See L for more on the record name (NAME) and description (DESC) fields. =fields EGU, HOPR, LOPR, PREC, NAME, DESC @@ -135,10 +131,8 @@ these fields, there is a corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The BRSV field is where the user can set the alarm severity in case the -subroutine returns a negative value. See -L -for a complete explanation of alarms and these fields. -L +subroutine returns a negative value. See L +for a complete explanation of alarms and these fields. L lists other fields related to a alarms that are common to all record types. =fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, BRSV, HYST @@ -153,8 +147,7 @@ minimum delta which the change must surpass before the value-change monitors are invoked. If these fields have a value of zero, everytime the value changes, a monitor will be triggered; if they have a value of -1, everytime the record is processed, monitors are triggered. The ADEL field is used by archive monitors -and the MDEL field for all other types of monitors. See -L +and the MDEL field for all other types of monitors. See L for a complete explanation of monitors and deadbands. =fields ADEL, MDEL @@ -779,4 +772,5 @@ processing. special(SPC_NOMOD) interest(3) } -} \ No newline at end of file +} + From 2461dc357418638a24788cf2f0d2f4c803efe6aa Mon Sep 17 00:00:00 2001 From: krmpotic Date: Mon, 9 Sep 2019 11:42:04 +0200 Subject: [PATCH 133/281] Update dbTest.c Fix MAX define. --- src/ioc/db/dbTest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ioc/db/dbTest.c b/src/ioc/db/dbTest.c index 637f8277d..7f4f77b95 100644 --- a/src/ioc/db/dbTest.c +++ b/src/ioc/db/dbTest.c @@ -54,7 +54,7 @@ typedef struct msgBuff TAB_BUFFER; # define MIN(x,y) (((x) < (y)) ? (x) : (y)) #endif #ifndef MAX -# define MAX(x,y) (((x) < (y)) ? (x) : (y)) +# define MAX(x,y) (((x) > (y)) ? (x) : (y)) #endif /* Local Routines */ From 73fec88168da1f16d499516c969c8326599b3d9d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 5 Sep 2019 07:56:45 -0700 Subject: [PATCH 134/281] replace CALLBACK -> epicsCallback git grep -l -w CALLBACK -- src|xargs sed -i -e 's/\bCALLBACK\b/epicsCallback/g' with exceptions in callback.h --- src/ioc/as/asDbLib.h | 2 +- src/ioc/db/callback.c | 18 +++++++++--------- src/ioc/db/callback.h | 14 +++++++------- src/ioc/db/dbNotify.c | 6 +++--- src/ioc/db/dbScan.c | 12 ++++++------ src/ioc/db/test/callbackParallelTest.c | 8 ++++---- src/ioc/db/test/callbackTest.c | 8 ++++---- src/libCom/taskwd/taskwd.c | 2 +- src/std/dev/asSubRecordFunctions.c | 2 +- src/std/dev/devAiSoftCallback.c | 2 +- src/std/dev/devBiSoftCallback.c | 2 +- src/std/dev/devLiSoftCallback.c | 2 +- src/std/dev/devMbbiDirectSoftCallback.c | 2 +- src/std/dev/devMbbiSoftCallback.c | 2 +- src/std/dev/devSiSoftCallback.c | 2 +- src/std/rec/boRecord.c | 4 ++-- src/std/rec/calcoutRecord.c | 10 +++++----- src/std/rec/histogramRecord.c | 4 ++-- src/std/rec/seqRecord.c | 6 +++--- 19 files changed, 54 insertions(+), 54 deletions(-) diff --git a/src/ioc/as/asDbLib.h b/src/ioc/as/asDbLib.h index 65c4c6f59..1e0f6756e 100644 --- a/src/ioc/as/asDbLib.h +++ b/src/ioc/as/asDbLib.h @@ -16,7 +16,7 @@ #include "shareLib.h" typedef struct { - CALLBACK callback; + epicsCallback callback; long status; } ASDBCALLBACK; diff --git a/src/ioc/db/callback.c b/src/ioc/db/callback.c index b805c1c16..4c0f5eea6 100644 --- a/src/ioc/db/callback.c +++ b/src/ioc/db/callback.c @@ -168,7 +168,7 @@ static void callbackTask(void *arg) epicsEventMustWait(mySet->semWakeUp); while ((ptr = epicsRingPointerPop(mySet->queue))) { - CALLBACK *pcallback = (CALLBACK *)ptr; + epicsCallback *pcallback = (epicsCallback *)ptr; if(!epicsRingPointerIsEmpty(mySet->queue)) epicsEventMustTrigger(mySet->semWakeUp); mySet->queueOverflow = FALSE; @@ -268,7 +268,7 @@ void callbackInit(void) } /* This routine can be called from interrupt context */ -int callbackRequest(CALLBACK *pcallback) +int callbackRequest(epicsCallback *pcallback) { int priority; int pushOK; @@ -297,7 +297,7 @@ int callbackRequest(CALLBACK *pcallback) return 0; } -static void ProcessCallback(CALLBACK *pcallback) +static void ProcessCallback(epicsCallback *pcallback) { dbCommon *pRec; @@ -308,14 +308,14 @@ static void ProcessCallback(CALLBACK *pcallback) dbScanUnlock(pRec); } -void callbackSetProcess(CALLBACK *pcallback, int Priority, void *pRec) +void callbackSetProcess(epicsCallback *pcallback, int Priority, void *pRec) { callbackSetCallback(ProcessCallback, pcallback); callbackSetPriority(Priority, pcallback); callbackSetUser(pRec, pcallback); } -int callbackRequestProcessCallback(CALLBACK *pcallback, +int callbackRequestProcessCallback(epicsCallback *pcallback, int Priority, void *pRec) { callbackSetProcess(pcallback, Priority, pRec); @@ -324,11 +324,11 @@ int callbackRequestProcessCallback(CALLBACK *pcallback, static void notify(void *pPrivate) { - CALLBACK *pcallback = (CALLBACK *)pPrivate; + epicsCallback *pcallback = (epicsCallback *)pPrivate; callbackRequest(pcallback); } -void callbackRequestDelayed(CALLBACK *pcallback, double seconds) +void callbackRequestDelayed(epicsCallback *pcallback, double seconds) { epicsTimerId timer = (epicsTimerId)pcallback->timer; @@ -339,7 +339,7 @@ void callbackRequestDelayed(CALLBACK *pcallback, double seconds) epicsTimerStartDelay(timer, seconds); } -void callbackCancelDelayed(CALLBACK *pcallback) +void callbackCancelDelayed(epicsCallback *pcallback) { epicsTimerId timer = (epicsTimerId)pcallback->timer; @@ -348,7 +348,7 @@ void callbackCancelDelayed(CALLBACK *pcallback) } } -void callbackRequestProcessCallbackDelayed(CALLBACK *pcallback, +void callbackRequestProcessCallbackDelayed(epicsCallback *pcallback, int Priority, void *pRec, double seconds) { callbackSetProcess(pcallback, Priority, pRec); diff --git a/src/ioc/db/callback.h b/src/ioc/db/callback.h index 9011446dc..ca53fba11 100644 --- a/src/ioc/db/callback.h +++ b/src/ioc/db/callback.h @@ -55,21 +55,21 @@ typedef void (*CALLBACKFUNC)(struct callbackPvt*); #define callbackSetUser(USER,PCALLBACK)\ ( (PCALLBACK)->user = (void *)(USER) ) #define callbackGetUser(USER,PCALLBACK)\ -( (USER) = (void *)((CALLBACK *)(PCALLBACK))->user ) +( (USER) = (void *)((epicsCallback *)(PCALLBACK))->user ) epicsShareFunc void callbackInit(void); epicsShareFunc void callbackStop(void); epicsShareFunc void callbackCleanup(void); -epicsShareFunc int callbackRequest(CALLBACK *pCallback); +epicsShareFunc int callbackRequest(epicsCallback *pCallback); epicsShareFunc void callbackSetProcess( - CALLBACK *pcallback, int Priority, void *pRec); + epicsCallback *pcallback, int Priority, void *pRec); epicsShareFunc int callbackRequestProcessCallback( - CALLBACK *pCallback,int Priority, void *pRec); + epicsCallback *pCallback,int Priority, void *pRec); epicsShareFunc void callbackRequestDelayed( - CALLBACK *pCallback,double seconds); -epicsShareFunc void callbackCancelDelayed(CALLBACK *pcallback); + epicsCallback *pCallback,double seconds); +epicsShareFunc void callbackCancelDelayed(epicsCallback *pcallback); epicsShareFunc void callbackRequestProcessCallbackDelayed( - CALLBACK *pCallback, int Priority, void *pRec, double seconds); + epicsCallback *pCallback, int Priority, void *pRec, double seconds); epicsShareFunc int callbackSetQueueSize(int size); epicsShareFunc int callbackParallelThreads(int count, const char *prio); diff --git a/src/ioc/db/dbNotify.c b/src/ioc/db/dbNotify.c index 4727649b2..eaf254902 100644 --- a/src/ioc/db/dbNotify.c +++ b/src/ioc/db/dbNotify.c @@ -70,7 +70,7 @@ typedef struct notifyPvt { ELLNODE node; /*For free list*/ long magic; short state; - CALLBACK callback; + epicsCallback callback; ELLLIST waitList; /*list of records for current processNotify*/ short cancelWait; short userCallbackWait; @@ -93,7 +93,7 @@ static void notifyCleanup(processNotify *ppn); static void restartCheck(processNotifyRecord *ppnr); static void callDone(dbCommon *precord,processNotify *ppn); static void processNotifyCommon(processNotify *ppn,dbCommon *precord); -static void notifyCallback(CALLBACK *pcallback); +static void notifyCallback(epicsCallback *pcallback); #define ellSafeAdd(list,listnode) \ { \ @@ -265,7 +265,7 @@ static void processNotifyCommon(processNotify *ppn,dbCommon *precord) callDone(precord, ppn); } -static void notifyCallback(CALLBACK *pcallback) +static void notifyCallback(epicsCallback *pcallback) { processNotify *ppn = NULL; dbCommon *precord; diff --git a/src/ioc/db/dbScan.c b/src/ioc/db/dbScan.c index 311297441..dd283f7bf 100644 --- a/src/ioc/db/dbScan.c +++ b/src/ioc/db/dbScan.c @@ -109,7 +109,7 @@ static char *priorityName[NUM_CALLBACK_PRIORITIES] = { /* EVENT */ typedef struct event_list { - CALLBACK callback[NUM_CALLBACK_PRIORITIES]; + epicsCallback callback[NUM_CALLBACK_PRIORITIES]; scan_list scan_list[NUM_CALLBACK_PRIORITIES]; struct event_list *next; char eventname[1]; /* actually arbitrary size */ @@ -120,7 +120,7 @@ static epicsMutexId event_lock; /* IO_EVENT*/ typedef struct io_scan_list { - CALLBACK callback; + epicsCallback callback; scan_list scan_list; } io_scan_list; @@ -141,9 +141,9 @@ static void periodicTask(void *arg); static void initPeriodic(void); static void deletePeriodic(void); static void spawnPeriodic(int ind); -static void eventCallback(CALLBACK *pcallback); +static void eventCallback(epicsCallback *pcallback); static void ioscanInit(void); -static void ioscanCallback(CALLBACK *pcallback); +static void ioscanCallback(epicsCallback *pcallback); static void ioscanDestroy(void); static void printList(scan_list *psl, char *message); static void scanList(scan_list *psl); @@ -448,7 +448,7 @@ int scanpiol(void) /* print pioscan_list */ return 0; } -static void eventCallback(CALLBACK *pcallback) +static void eventCallback(epicsCallback *pcallback) { scan_list *psl; @@ -863,7 +863,7 @@ static void spawnPeriodic(int ind) epicsEventWait(startStopEvent); } -static void ioscanCallback(CALLBACK *pcallback) +static void ioscanCallback(epicsCallback *pcallback) { ioscan_head *piosh = (ioscan_head *) pcallback->user; int prio = pcallback->priority; diff --git a/src/ioc/db/test/callbackParallelTest.c b/src/ioc/db/test/callbackParallelTest.c index f8d0c3981..a985cd2d8 100644 --- a/src/ioc/db/test/callbackParallelTest.c +++ b/src/ioc/db/test/callbackParallelTest.c @@ -44,8 +44,8 @@ #define TEST_DELAY(i) ((i / NUM_CALLBACK_PRIORITIES) * DELAY_QUANTUM) typedef struct myPvt { - CALLBACK cb1; - CALLBACK cb2; + epicsCallback cb1; + epicsCallback cb2; epicsTimeStamp pass1Time; epicsTimeStamp pass2Time; double delay; @@ -55,7 +55,7 @@ typedef struct myPvt { epicsEventId finished; -static void myCallback(CALLBACK *pCallback) +static void myCallback(epicsCallback *pCallback) { myPvt *pmyPvt; @@ -74,7 +74,7 @@ static void myCallback(CALLBACK *pCallback) } } -static void finalCallback(CALLBACK *pCallback) +static void finalCallback(epicsCallback *pCallback) { myCallback(pCallback); epicsEventSignal(finished); diff --git a/src/ioc/db/test/callbackTest.c b/src/ioc/db/test/callbackTest.c index 3ccc2c2f3..4b7e24d78 100644 --- a/src/ioc/db/test/callbackTest.c +++ b/src/ioc/db/test/callbackTest.c @@ -44,8 +44,8 @@ #define TEST_DELAY(i) ((i / NUM_CALLBACK_PRIORITIES) * DELAY_QUANTUM) typedef struct myPvt { - CALLBACK cb1; - CALLBACK cb2; + epicsCallback cb1; + epicsCallback cb2; epicsTimeStamp pass1Time; epicsTimeStamp pass2Time; double delay; @@ -56,7 +56,7 @@ typedef struct myPvt { epicsEventId finished; -static void myCallback(CALLBACK *pCallback) +static void myCallback(epicsCallback *pCallback) { myPvt *pmyPvt; @@ -75,7 +75,7 @@ static void myCallback(CALLBACK *pCallback) } } -static void finalCallback(CALLBACK *pCallback) +static void finalCallback(epicsCallback *pCallback) { myCallback(pCallback); epicsEventSignal(finished); diff --git a/src/libCom/taskwd/taskwd.c b/src/libCom/taskwd/taskwd.c index f8a061c2c..03900b38b 100644 --- a/src/libCom/taskwd/taskwd.c +++ b/src/libCom/taskwd/taskwd.c @@ -367,7 +367,7 @@ epicsShareFunc void taskwdShow(int level) mCount, tCount, fCount); if (level) { printf("%16.16s %9s %12s %12s %12s\n", - "THREAD NAME", "STATE", "EPICS TID", "CALLBACK", "USR ARG"); + "THREAD NAME", "STATE", "EPICS TID", "epicsCallback", "USR ARG"); pt = (struct tNode *)ellFirst(&tList); while (pt != NULL) { epicsThreadGetName(pt->tid, tName, sizeof(tName)); diff --git a/src/std/dev/asSubRecordFunctions.c b/src/std/dev/asSubRecordFunctions.c index 957db300a..c42902a79 100644 --- a/src/std/dev/asSubRecordFunctions.c +++ b/src/std/dev/asSubRecordFunctions.c @@ -34,7 +34,7 @@ /* The following is provided for access security*/ /*It allows a CA client to force access security initialization*/ -static void myCallback(CALLBACK *pcallback) +static void myCallback(epicsCallback *pcallback) { ASDBCALLBACK *pasdbcallback = (ASDBCALLBACK *)pcallback; subRecord *precord; diff --git a/src/std/dev/devAiSoftCallback.c b/src/std/dev/devAiSoftCallback.c index 3744509ed..9eac0df93 100644 --- a/src/std/dev/devAiSoftCallback.c +++ b/src/std/dev/devAiSoftCallback.c @@ -36,7 +36,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; int smooth; diff --git a/src/std/dev/devBiSoftCallback.c b/src/std/dev/devBiSoftCallback.c index 02887ebe7..159145420 100644 --- a/src/std/dev/devBiSoftCallback.c +++ b/src/std/dev/devBiSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/src/std/dev/devLiSoftCallback.c b/src/std/dev/devLiSoftCallback.c index 90bbff311..d776b27bf 100644 --- a/src/std/dev/devLiSoftCallback.c +++ b/src/std/dev/devLiSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/src/std/dev/devMbbiDirectSoftCallback.c b/src/std/dev/devMbbiDirectSoftCallback.c index 6234a163b..bb9e88564 100644 --- a/src/std/dev/devMbbiDirectSoftCallback.c +++ b/src/std/dev/devMbbiDirectSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/src/std/dev/devMbbiSoftCallback.c b/src/std/dev/devMbbiSoftCallback.c index 5447b4b6e..957697c69 100644 --- a/src/std/dev/devMbbiSoftCallback.c +++ b/src/std/dev/devMbbiSoftCallback.c @@ -35,7 +35,7 @@ typedef struct devPvt { processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/src/std/dev/devSiSoftCallback.c b/src/std/dev/devSiSoftCallback.c index e2eff3213..ad7ceec7e 100644 --- a/src/std/dev/devSiSoftCallback.c +++ b/src/std/dev/devSiSoftCallback.c @@ -37,7 +37,7 @@ typedef struct devPvt { DBADDR dbaddr; processNotify pn; - CALLBACK callback; + epicsCallback callback; long options; int status; struct { diff --git a/src/std/rec/boRecord.c b/src/std/rec/boRecord.c index 48cc4846a..7dd0bec6f 100644 --- a/src/std/rec/boRecord.c +++ b/src/std/rec/boRecord.c @@ -98,7 +98,7 @@ struct bodset { /* binary output dset */ /* control block for callback*/ typedef struct myCallback { - CALLBACK callback; + epicsCallback callback; struct dbCommon *precord; }myCallback; @@ -106,7 +106,7 @@ static void checkAlarms(boRecord *); static void monitor(boRecord *); static long writeValue(boRecord *); -static void myCallbackFunc(CALLBACK *arg) +static void myCallbackFunc(epicsCallback *arg) { myCallback *pcallback; boRecord *prec; diff --git a/src/std/rec/calcoutRecord.c b/src/std/rec/calcoutRecord.c index c62b3f446..56bbdfd97 100644 --- a/src/std/rec/calcoutRecord.c +++ b/src/std/rec/calcoutRecord.c @@ -116,8 +116,8 @@ typedef struct calcoutDSET { #define CA_LINKS_NOT_OK 2 typedef struct rpvtStruct { - CALLBACK doOutCb; - CALLBACK checkLinkCb; + epicsCallback doOutCb; + epicsCallback checkLinkCb; short cbScheduled; short caLinkStat; /* NO_CA_LINKS, CA_LINKS_ALL_OK, CA_LINKS_NOT_OK */ } rpvtStruct; @@ -127,7 +127,7 @@ static void monitor(calcoutRecord *prec); static int fetch_values(calcoutRecord *prec); static void execOutput(calcoutRecord *prec); static void checkLinks(calcoutRecord *prec); -static void checkLinksCallback(CALLBACK *arg); +static void checkLinksCallback(epicsCallback *arg); static long writeValue(calcoutRecord *prec); int calcoutRecDebug; @@ -673,7 +673,7 @@ static int fetch_values(calcoutRecord *prec) return(status); } -static void checkLinksCallback(CALLBACK *arg) +static void checkLinksCallback(epicsCallback *arg) { calcoutRecord *prec; @@ -731,7 +731,7 @@ static void checkLinks(calcoutRecord *prec) prpvt->caLinkStat = NO_CA_LINKS; if (!prpvt->cbScheduled && caLinkNc) { - /* Schedule another CALLBACK */ + /* Schedule another epicsCallback */ prpvt->cbScheduled = 1; callbackRequestDelayed(&prpvt->checkLinkCb, .5); } diff --git a/src/std/rec/histogramRecord.c b/src/std/rec/histogramRecord.c index f24bba625..17730991b 100644 --- a/src/std/rec/histogramRecord.c +++ b/src/std/rec/histogramRecord.c @@ -100,7 +100,7 @@ struct histogramdset { /* histogram input dset */ /* control block for callback*/ typedef struct myCallback { - CALLBACK callback; + epicsCallback callback; histogramRecord *prec; } myCallback; @@ -110,7 +110,7 @@ static void monitor(histogramRecord *); static long readValue(histogramRecord *); -static void wdogCallback(CALLBACK *arg) +static void wdogCallback(epicsCallback *arg) { myCallback *pcallback; histogramRecord *prec; diff --git a/src/std/rec/seqRecord.c b/src/std/rec/seqRecord.c index 13d1cba1f..b143e0530 100644 --- a/src/std/rec/seqRecord.c +++ b/src/std/rec/seqRecord.c @@ -31,7 +31,7 @@ static void processNextLink(seqRecord *prec); static long asyncFinish(seqRecord *prec); -static void processCallback(CALLBACK *arg); +static void processCallback(epicsCallback *arg); /* Create RSET - Record Support Entry Table*/ #define report NULL @@ -94,7 +94,7 @@ typedef struct linkGrp { /* The list of link-groups for processing */ typedef struct seqRecPvt { - CALLBACK callback; + epicsCallback callback; seqRecord *prec; linkGrp *grps[NUM_LINKS + 1]; /* List of link-groups */ int index; /* Where we are now */ @@ -241,7 +241,7 @@ static long asyncFinish(seqRecord *prec) } -static void processCallback(CALLBACK *arg) +static void processCallback(epicsCallback *arg) { seqRecPvt *pcb; seqRecord *prec; From 75a1b82322e8cbaa5f3630f94e38728cfe774052 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 5 Sep 2019 10:28:27 -0700 Subject: [PATCH 135/281] add option EPICS_NO_CALLBACK Allow the CALLBACK definition to be hidden to prevent conflicts on WIN32. --- src/ioc/db/callback.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ioc/db/callback.h b/src/ioc/db/callback.h index ca53fba11..0a212ade5 100644 --- a/src/ioc/db/callback.h +++ b/src/ioc/db/callback.h @@ -26,7 +26,7 @@ extern "C" { /* * WINDOWS also has a "CALLBACK" type def */ -#ifdef _WIN32 +#if defined(_WIN32) && !defined(EPICS_NO_CALLBACK) # ifdef CALLBACK # undef CALLBACK # endif /*CALLBACK*/ @@ -44,7 +44,9 @@ typedef struct callbackPvt { void *timer; /*for use by callback itself*/ }epicsCallback; +#if !defined(EPICS_NO_CALLBACK) typedef epicsCallback CALLBACK; +#endif typedef void (*CALLBACKFUNC)(struct callbackPvt*); From 77574022a109d82edb52a959c11e09b4e89440db Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 9 Sep 2019 16:56:28 -0700 Subject: [PATCH 136/281] update RELEASE_NOTES --- documentation/RELEASE_NOTES.html | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 8ed4e04bf..6f2019379 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -16,6 +16,18 @@ +

Add option to avoid CALLBACK conflict

+ +

If a macro EPICS_NO_CALLBACK is defined, then callback.h will no longer (re)define CALLBACK. +The name 'CALLBACK' is used by the WIN32 API, and redefinition in callback.h cause errors +if some windows headers are later included. +

+ +

Code which defines EPICS_NO_CALLBACK, but still wishes to use callbacks, should use +the alternate name 'epicsCallback' introduced in 3.15.6, 3.16.2, and 7.0.2. +It is also possible, though not encouraged, to use 'struct callbackPvt' +which has been present since the callback API was introduced.

+

Cleaning up with Multiple CA contexts in a Process

Bruno Martins reported a problem with the CA client library at shutdown in a From d58996992de2699354a4a61dc2acb7126476392c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 10 Sep 2019 18:37:22 -0700 Subject: [PATCH 137/281] update PVA modules --- 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 ba33c7443..fbe1a1135 160000 --- a/modules/normativeTypes +++ b/modules/normativeTypes @@ -1 +1 @@ -Subproject commit ba33c7443c52689641c2a7377e39544d5dd326d2 +Subproject commit fbe1a1135f0503842452157d9e617966eaa4dca1 diff --git a/modules/pvAccess b/modules/pvAccess index c8c3cf4fd..710bcde7b 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit c8c3cf4fd8b3490221c1e231c354e73735ee3813 +Subproject commit 710bcde7be1a10c5ca3223c9657cc5892008d39d diff --git a/modules/pvData b/modules/pvData index b903df5d0..bff2dc9cd 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit b903df5d0daf08592368be2978efb2d828617a8c +Subproject commit bff2dc9cd28fcff57fde287b3305f5f9666ee48a diff --git a/modules/pvDatabase b/modules/pvDatabase index d7bd5628d..d33d03189 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit d7bd5628d47f82b2ad2cab2ea97dade98c2ee128 +Subproject commit d33d03189e905f25b26f5d4faddb9baec5ee851f diff --git a/modules/pva2pva b/modules/pva2pva index d70a2ff8c..c7a54de46 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit d70a2ff8c31bc042477b4997d733b77e6029e8f9 +Subproject commit c7a54de4697842049d3f79da6752afc3ea8d962c diff --git a/modules/pvaClient b/modules/pvaClient index 246cceae3..b92a3ddaa 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit 246cceae3e682ac99413673195fec07dffa77267 +Subproject commit b92a3ddaa45cea2f1cdbb061a5c62fb6f422a2b9 From 49bf8bb5ec900c503f4c5df7f5f73df203503e7e Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 17 Sep 2019 11:59:02 +0200 Subject: [PATCH 138/281] removed unneeded include --- modules/libcom/src/log/logClient.c | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 72a2e1364..723f5d4be 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -25,7 +25,6 @@ #include "dbDefs.h" #include "epicsEvent.h" #include "iocLog.h" -#include "errlog.h" #include "epicsMutex.h" #include "epicsThread.h" #include "epicsTime.h" From d162337b9a52a860e6c4e079f2f147163d3f7226 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 17 Sep 2019 14:39:03 +0200 Subject: [PATCH 139/281] improve logClientShow to show unsent bytes on level 2 (and fix level 1) --- modules/libcom/src/log/logClient.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 723f5d4be..9b9e039b1 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -507,14 +507,21 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level) printf ("log client: disconnected from log server at \"%s\"\n", pClient->name); } - if (level>1) { - printf ("log client: sock=%s, connect cycles = %u\n", + if (logClientPrefix) { + printf ("log client: prefix is \"%s\"\n", logClientPrefix); + } + + if (level>0) { + printf ("log client: sock %s, connect cycles = %u\n", pClient->sock==INVALID_SOCKET?"INVALID":"OK", pClient->connectCount); } - - if (logClientPrefix) { - printf ("log client: prefix is \"%s\"\n", logClientPrefix); + if (level>1) { + printf ("log client: %u bytes in buffer\n", pClient->nextMsgIndex); + if (pClient->nextMsgIndex) + printf("-------------------------\n" + "%.*s-------------------------\n", + (int)(pClient->nextMsgIndex), pClient->msgBuf); } } From 26f6f674be89f209606aeb447929e8146d43e230 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 17 Sep 2019 14:41:35 +0200 Subject: [PATCH 140/281] increase error message buffer size for long (Windows) error messges --- modules/libcom/src/log/logClient.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 9b9e039b1..3defa6baf 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -235,7 +235,7 @@ void epicsShareAPI logClientFlush ( logClientId id ) } else { if ( ! pClient->shutdown ) { - char sockErrBuf[64]; + char sockErrBuf[128]; if ( status ) { epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); } @@ -274,7 +274,7 @@ static void logClientMakeSock (logClient *pClient) */ pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 ); if ( pClient->sock == INVALID_SOCKET ) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf ( stderr, "log client: no socket error %s\n", @@ -326,7 +326,7 @@ static void logClientConnect (logClient *pClient) } else { if ( pClient->connFailStatus != errnoCpy && ! pClient->shutdown ) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, @@ -352,7 +352,7 @@ static void logClientConnect (logClient *pClient) optval = TRUE; status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval)); if (status<0) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf); @@ -364,7 +364,7 @@ static void logClientConnect (logClient *pClient) */ status = shutdown (pClient->sock, SHUT_RD); if (status < 0) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n", @@ -385,7 +385,7 @@ static void logClientConnect (logClient *pClient) lingerval.l_linger = 60*5; status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval)); if (status<0) { - char sockErrBuf[64]; + char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf); From f85454a8d66e42503ae5295144ed2da8147ef4bc Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 17 Sep 2019 17:06:55 +0200 Subject: [PATCH 141/281] use dynamic debug flag for logClient --- modules/database/src/ioc/misc/dbCore.dbd | 3 +++ modules/libcom/src/log/logClient.c | 22 +++++++++++----------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/modules/database/src/ioc/misc/dbCore.dbd b/modules/database/src/ioc/misc/dbCore.dbd index 51f9c9640..adde24e4f 100644 --- a/modules/database/src/ioc/misc/dbCore.dbd +++ b/modules/database/src/ioc/misc/dbCore.dbd @@ -33,3 +33,6 @@ variable(callbackParallelThreadsDefault,int) # Real-time operation variable(dbThreadRealtimeLock,int) + +# show logClient network activity +variable(logClientDebug,int) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 3defa6baf..19d79b617 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -21,7 +21,6 @@ #include #include -#define epicsExportSharedSymbols #include "dbDefs.h" #include "epicsEvent.h" #include "iocLog.h" @@ -32,9 +31,13 @@ #include "epicsAssert.h" #include "epicsExit.h" #include "epicsSignal.h" +#include "epicsExport.h" #include "logClient.h" +int logClientDebug = 0; +epicsExportAddress (int, logClientDebug); + typedef struct { char msgBuf[0x4000]; struct sockaddr_in addr; @@ -65,10 +68,10 @@ static char* logClientPrefix = NULL; */ static void logClientClose ( logClient *pClient ) { -# ifdef DEBUG + if (logClientDebug) { fprintf (stderr, "log client: lingering for connection close..."); fflush (stderr); -# endif + } /* * mutex on @@ -90,9 +93,8 @@ static void logClientClose ( logClient *pClient ) */ epicsMutexUnlock (pClient->mutex); -# ifdef DEBUG + if (logClientDebug) fprintf (stderr, "done\n"); -# endif } /* @@ -262,10 +264,10 @@ void epicsShareAPI logClientFlush ( logClientId id ) */ static void logClientMakeSock (logClient *pClient) { - -# ifdef DEBUG + if (logClientDebug) { fprintf (stderr, "log client: creating socket..."); -# endif + fflush (stderr); + } epicsMutexMustLock (pClient->mutex); @@ -283,10 +285,8 @@ static void logClientMakeSock (logClient *pClient) epicsMutexUnlock (pClient->mutex); -# ifdef DEBUG + if (logClientDebug) fprintf (stderr, "done\n"); -# endif - } /* From 6ffc9e17dacf7af450cdee2e3915cb73f317ef96 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 17 Sep 2019 17:34:16 +0200 Subject: [PATCH 142/281] ask logClient socket how many bytes are still in the send queue and don't discard them in case the connection turns out broken. --- modules/libcom/src/log/logClient.c | 83 +++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 19d79b617..44eaf7dab 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -49,6 +49,7 @@ typedef struct { epicsEventId shutdownNotify; unsigned connectCount; unsigned nextMsgIndex; + unsigned backlog; unsigned connected; unsigned shutdown; unsigned shutdownConfirm; @@ -194,6 +195,39 @@ static void sendMessageChunk(logClient * pClient, const char * message) { } } +/* + * epicsSockCountUnsentBytes () + * Should go to osd socket support + */ +#if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 +#include +#endif + +static int epicsSockCountUnsentBytes(SOCKET sock) { +#if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 +/* Windows 10 Version 1703 / Server 2016 */ +/* https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0 */ + DWORD infoVersion = 0, bytesReturned; + TCP_INFO_v0 tcpInfo; + int status; + if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion), + &tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0) + return tcpInfo.BytesInFlight; +#elif defined (SO_NWRITE) +/* macOS / iOS */ +/* https://www.unix.com/man-page/osx/2/setsockopt/ */ + int unsent; + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent) == 0) + return unsent; +#elif defined (TIOCOUTQ) +/* Linux */ +/* https://linux.die.net/man/7/tcp */ + int unsent; + if (ioctl(sock, TIOCOUTQ, &unsent) == 0) + return unsent; +#endif + return 0; +} /* * logClientSend () @@ -219,7 +253,8 @@ void epicsShareAPI logClientSend ( logClientId id, const char * message ) void epicsShareAPI logClientFlush ( logClientId id ) { - unsigned nSent = 0u; + unsigned nSent; + int status = 0; logClient * pClient = ( logClient * ) id; @@ -229,32 +264,32 @@ void epicsShareAPI logClientFlush ( logClientId id ) epicsMutexMustLock ( pClient->mutex ); + nSent = pClient->backlog; while ( nSent < pClient->nextMsgIndex && pClient->connected ) { - int status = send ( pClient->sock, pClient->msgBuf + nSent, + status = send ( pClient->sock, pClient->msgBuf + nSent, pClient->nextMsgIndex - nSent, 0 ); - if ( status > 0 ) { - nSent += (unsigned) status; - } - else { - if ( ! pClient->shutdown ) { - char sockErrBuf[128]; - if ( status ) { - epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - } - else { - strcpy ( sockErrBuf, "server initiated disconnect" ); - } - fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", - pClient->name, sockErrBuf ); - } - logClientClose ( pClient ); - break; - } + if ( status < 0 ) break; + nSent += status; } - pClient->nextMsgIndex -= nSent; - if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { - memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], - pClient->nextMsgIndex ); + + if ( status < 0 ) { + if ( ! pClient->shutdown ) { + char sockErrBuf[128]; + epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); + fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n", + pClient->name, sockErrBuf ); + } + pClient->backlog = 0; + logClientClose ( pClient ); + } + else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { + pClient->backlog = epicsSockCountUnsentBytes ( pClient->sock ); + nSent -= pClient->backlog; + if ( nSent > 0 ) { + memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], + pClient->nextMsgIndex ); + pClient->nextMsgIndex -= nSent; + } } epicsMutexUnlock ( pClient->mutex ); } From 931054d4fd96d0896bb74c2765c731bbbcef7295 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Tue, 17 Sep 2019 17:45:33 +0200 Subject: [PATCH 143/281] cannot print sockets with %d in Windows, they are not small ints but maybe pointers. --- modules/libcom/src/log/logClient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 44eaf7dab..762703417 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -402,8 +402,8 @@ static void logClientConnect (logClient *pClient) char sockErrBuf[128]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - fprintf (stderr, "%s:%d shutdown(%d,SHUT_RD) error was \"%s\"\n", - __FILE__, __LINE__, pClient->sock, sockErrBuf); + fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was \"%s\"\n", + __FILE__, __LINE__, sockErrBuf); /* not fatal (although it shouldn't happen) */ } From c9b670977d590fb95455c358ed5597599804d66a Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Wed, 18 Sep 2019 09:58:28 +0200 Subject: [PATCH 144/281] sending 0 bytes helps to detect broken connections on some systems (but is undefined behavior on Linux, fails on vxWorks and is a documented no-op on Windows) --- modules/libcom/src/log/logClient.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 762703417..6671d2785 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -272,6 +272,15 @@ void epicsShareAPI logClientFlush ( logClientId id ) nSent += status; } + if ( pClient->backlog > 0 && status >= 0 ) + { + /* On Linux send 0 bytes can detect EPIPE */ + /* NOOP on Windows, fails on vxWorks */ + errno = 0; + status = send ( pClient->sock, NULL, 0, 0 ); + if (!(errno == ECONNRESET || errno == EPIPE)) status = 0; + } + if ( status < 0 ) { if ( ! pClient->shutdown ) { char sockErrBuf[128]; From f08b412a189678f3c63f6ff3216d2cc605a39d19 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 18 Sep 2019 14:43:08 -0500 Subject: [PATCH 145/281] Have CA Repeater cd to / before running to avoid holding the CWD open unnecessarily. --- src/ca/client/caRepeater.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ca/client/caRepeater.cpp b/src/ca/client/caRepeater.cpp index 9879af2b4..03cb8957d 100644 --- a/src/ca/client/caRepeater.cpp +++ b/src/ca/client/caRepeater.cpp @@ -32,10 +32,12 @@ #define epicsAssertAuthor "Jeff Hill johill@lanl.gov" #include "epicsAssert.h" +#include "osiUnistd.h" #include "udpiiu.h" int main() { + chdir ( "/" ); ca_repeater (); return ( 0 ); } From db3b160f4ec7eeb988aa585078740b1c2aa7f8a7 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Thu, 19 Sep 2019 08:54:19 +0200 Subject: [PATCH 146/281] fix wrong function name in comment --- modules/libcom/src/log/iocLog.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/log/iocLog.c b/modules/libcom/src/log/iocLog.c index 8cb1349a1..c0fa33fa6 100644 --- a/modules/libcom/src/log/iocLog.c +++ b/modules/libcom/src/log/iocLog.c @@ -77,7 +77,7 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void) } /* - * logClientDestroy() + * iocLogClientDestroy() */ static void iocLogClientDestroy (logClientId id) { From 64f540a64ffc3282d05b3a6b7274e63639f1116c Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Thu, 19 Sep 2019 10:44:36 +0200 Subject: [PATCH 147/281] moved logClientSendMessage and made it static --- modules/libcom/src/log/iocLog.c | 11 +++++++++++ modules/libcom/src/log/logClient.c | 10 ---------- modules/libcom/src/log/logClient.h | 1 - 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/libcom/src/log/iocLog.c b/modules/libcom/src/log/iocLog.c index c0fa33fa6..ba78041c8 100644 --- a/modules/libcom/src/log/iocLog.c +++ b/modules/libcom/src/log/iocLog.c @@ -76,6 +76,16 @@ void epicsShareAPI epicsShareAPI iocLogFlush (void) } } +/* + * logClientSendMessage () + */ +static void logClientSendMessage ( logClientId id, const char * message ) +{ + if ( !iocLogDisable ) { + logClientSend (id, message); + } +} + /* * iocLogClientDestroy() */ @@ -149,3 +159,4 @@ logClientId epicsShareAPI logClientInit (void) { return iocLogClientInit (); } + diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 6671d2785..cd832b60c 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -569,16 +569,6 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level) } } -/* - * logClientSendMessage (); deprecated - */ -void logClientSendMessage ( logClientId id, const char * message ) -{ - if ( !iocLogDisable ) { - logClientSend (id, message); - } -} - /* * iocLogPrefix() */ diff --git a/modules/libcom/src/log/logClient.h b/modules/libcom/src/log/logClient.h index 1797bbb20..3b3f63add 100644 --- a/modules/libcom/src/log/logClient.h +++ b/modules/libcom/src/log/logClient.h @@ -38,7 +38,6 @@ epicsShareFunc void epicsShareAPI iocLogPrefix(const char* prefix); /* deprecated interface; retained for backward compatibility */ /* note: implementations are in iocLog.c, not logClient.c */ epicsShareFunc logClientId epicsShareAPI logClientInit (void); -epicsShareFunc void logClientSendMessage (logClientId id, const char *message); #ifdef __cplusplus } From e28bb3b0e20fe0c18db5c7b9e36da19e95877dcd Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Thu, 19 Sep 2019 10:48:14 +0200 Subject: [PATCH 148/281] epicsSockCountUnsentBytes renamed to epicsSocketCountUnsentBytes --- modules/libcom/src/log/logClient.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index cd832b60c..28b933e02 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -196,14 +196,14 @@ static void sendMessageChunk(logClient * pClient, const char * message) { } /* - * epicsSockCountUnsentBytes () + * epicsSocketCountUnsentBytes () * Should go to osd socket support */ #if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 #include #endif -static int epicsSockCountUnsentBytes(SOCKET sock) { +static int epicsSocketCountUnsentBytes(SOCKET sock) { #if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 /* Windows 10 Version 1703 / Server 2016 */ /* https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0 */ @@ -292,7 +292,7 @@ void epicsShareAPI logClientFlush ( logClientId id ) logClientClose ( pClient ); } else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { - pClient->backlog = epicsSockCountUnsentBytes ( pClient->sock ); + pClient->backlog = epicsSocketCountUnsentBytes ( pClient->sock ); nSent -= pClient->backlog; if ( nSent > 0 ) { memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], From 752ec12261cf10155754534c3de8ea7bdfda5e54 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Thu, 19 Sep 2019 11:42:04 +0200 Subject: [PATCH 149/281] bugfix: memmove'ed to much --- modules/libcom/src/log/logClient.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 28b933e02..4e647bd83 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -294,10 +294,10 @@ void epicsShareAPI logClientFlush ( logClientId id ) else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { pClient->backlog = epicsSocketCountUnsentBytes ( pClient->sock ); nSent -= pClient->backlog; - if ( nSent > 0 ) { + pClient->nextMsgIndex -= nSent; + if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], pClient->nextMsgIndex ); - pClient->nextMsgIndex -= nSent; } } epicsMutexUnlock ( pClient->mutex ); From 1718647121799f44d0a2c9a624635d2d8f2077fa Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Thu, 19 Sep 2019 12:08:45 +0200 Subject: [PATCH 150/281] epicsSocketCountUnsentBytes returns -1 on failure --- modules/libcom/src/log/logClient.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 4e647bd83..476634c5f 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -226,7 +226,7 @@ static int epicsSocketCountUnsentBytes(SOCKET sock) { if (ioctl(sock, TIOCOUTQ, &unsent) == 0) return unsent; #endif - return 0; + return -1; } /* @@ -292,8 +292,11 @@ void epicsShareAPI logClientFlush ( logClientId id ) logClientClose ( pClient ); } else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { - pClient->backlog = epicsSocketCountUnsentBytes ( pClient->sock ); - nSent -= pClient->backlog; + int backlog = epicsSocketCountUnsentBytes ( pClient->sock ); + if (backlog >= 0) { + pClient->backlog = backlog; + nSent -= backlog; + } pClient->nextMsgIndex -= nSent; if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { memmove ( pClient->msgBuf, & pClient->msgBuf[nSent], From cf121f1c14a96b9a3171e5fd46d991cbffa7386b Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 23 Sep 2019 10:54:17 +0200 Subject: [PATCH 151/281] fix bug from commit f85454. Apparently epicsExportSharedSymbols is needed even though epicsExport.h is included --- modules/libcom/src/log/logClient.c | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 476634c5f..ee92c27c4 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -21,6 +21,7 @@ #include #include +#define epicsExportSharedSymbols #include "dbDefs.h" #include "epicsEvent.h" #include "iocLog.h" From 46912d55166f1664c947e14e3efdd71f6058880e Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 23 Sep 2019 11:10:32 +0200 Subject: [PATCH 152/281] renamed epicsSocketCountUnsentBytes to epicsSocketUnsentCount and moved it to osi/os/ --- modules/libcom/src/log/logClient.c | 36 +------------------ modules/libcom/src/osi/Makefile | 1 + .../src/osi/os/Darwin/osdSockUnsentCount.c | 17 +++++++++ .../src/osi/os/Linux/osdSockUnsentCount.c | 18 ++++++++++ .../src/osi/os/WIN32/osdSockUnsentCount.c | 25 +++++++++++++ .../src/osi/os/default/osdSockUnsentCount.c | 14 ++++++++ .../src/osi/os/iOS/osdSockUnsentCount.c | 17 +++++++++ modules/libcom/src/osi/osiSock.h | 6 ++++ 8 files changed, 99 insertions(+), 35 deletions(-) create mode 100644 modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c create mode 100644 modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c create mode 100644 modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c create mode 100644 modules/libcom/src/osi/os/default/osdSockUnsentCount.c create mode 100644 modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index ee92c27c4..73664ff76 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -196,40 +196,6 @@ static void sendMessageChunk(logClient * pClient, const char * message) { } } -/* - * epicsSocketCountUnsentBytes () - * Should go to osd socket support - */ -#if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 -#include -#endif - -static int epicsSocketCountUnsentBytes(SOCKET sock) { -#if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 -/* Windows 10 Version 1703 / Server 2016 */ -/* https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0 */ - DWORD infoVersion = 0, bytesReturned; - TCP_INFO_v0 tcpInfo; - int status; - if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion), - &tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0) - return tcpInfo.BytesInFlight; -#elif defined (SO_NWRITE) -/* macOS / iOS */ -/* https://www.unix.com/man-page/osx/2/setsockopt/ */ - int unsent; - if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent) == 0) - return unsent; -#elif defined (TIOCOUTQ) -/* Linux */ -/* https://linux.die.net/man/7/tcp */ - int unsent; - if (ioctl(sock, TIOCOUTQ, &unsent) == 0) - return unsent; -#endif - return -1; -} - /* * logClientSend () */ @@ -293,7 +259,7 @@ void epicsShareAPI logClientFlush ( logClientId id ) logClientClose ( pClient ); } else if ( nSent > 0 && pClient->nextMsgIndex > 0 ) { - int backlog = epicsSocketCountUnsentBytes ( pClient->sock ); + int backlog = epicsSocketUnsentCount ( pClient->sock ); if (backlog >= 0) { pClient->backlog = backlog; nSent -= backlog; diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile index ecbf4c23b..71d8c3d73 100644 --- a/modules/libcom/src/osi/Makefile +++ b/modules/libcom/src/osi/Makefile @@ -86,6 +86,7 @@ endif Com_SRCS += osdSock.c Com_SRCS += osdSockAddrReuse.cpp +Com_SRCS += osdSockUnsentCount.c Com_SRCS += osiSock.c Com_SRCS += systemCallIntMech.cpp Com_SRCS += epicsSocketConvertErrnoToString.cpp diff --git a/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c b/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c new file mode 100644 index 000000000..00ef550bd --- /dev/null +++ b/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c @@ -0,0 +1,17 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + * See https://www.unix.com/man-page/osx/2/setsockopt + */ +int epicsSocketUnsentCount(SOCKET sock) { + int unsent; + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent) == 0) + return unsent; + return -1; +} diff --git a/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c b/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c new file mode 100644 index 000000000..6f6cbf0fe --- /dev/null +++ b/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c @@ -0,0 +1,18 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + * See https://linux.die.net/man/7/tcp + */ +int epicsSocketUnsentCount(SOCKET sock) { + int unsent; + if (ioctl(sock, SIOCOUTQ, &unsent) == 0) + return unsent; + return -1; +} diff --git a/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c b/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c new file mode 100644 index 000000000..c2045bc79 --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c @@ -0,0 +1,25 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#define epicsExportSharedSymbols +#include "osiSock.h" +#include + +/* + * epicsSocketUnsentCount () + * See https://docs.microsoft.com/en-us/windows/win32/api/mstcpip/ns-mstcpip-tcp_info_v0 + */ +int epicsSocketUnsentCount(SOCKET sock) { +#if defined (_WIN32) && WINVER >= _WIN32_WINNT_WIN10 +/* Windows 10 Version 1703 / Server 2016 */ + DWORD infoVersion = 0, bytesReturned; + TCP_INFO_v0 tcpInfo; + int status; + if ((status = WSAIoctl(sock, SIO_TCP_INFO, &infoVersion, sizeof(infoVersion), + &tcpInfo, sizeof(tcpInfo), &bytesReturned, NULL, NULL)) == 0) + return tcpInfo.BytesInFlight; +#endif + return -1; +} diff --git a/modules/libcom/src/osi/os/default/osdSockUnsentCount.c b/modules/libcom/src/osi/os/default/osdSockUnsentCount.c new file mode 100644 index 000000000..61094c710 --- /dev/null +++ b/modules/libcom/src/osi/os/default/osdSockUnsentCount.c @@ -0,0 +1,14 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + */ +int epicsSocketUnsentCount(SOCKET sock) { + /* not implemented */ + return -1; +} diff --git a/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c b/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c new file mode 100644 index 000000000..00ef550bd --- /dev/null +++ b/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c @@ -0,0 +1,17 @@ +/*************************************************************************\ +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include "osiSock.h" + +/* + * epicsSocketUnsentCount () + * See https://www.unix.com/man-page/osx/2/setsockopt + */ +int epicsSocketUnsentCount(SOCKET sock) { + int unsent; + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent) == 0) + return unsent; + return -1; +} diff --git a/modules/libcom/src/osi/osiSock.h b/modules/libcom/src/osi/osiSock.h index 061619e89..e1c2de881 100644 --- a/modules/libcom/src/osi/osiSock.h +++ b/modules/libcom/src/osi/osiSock.h @@ -52,6 +52,12 @@ enum epicsSocketSystemCallInterruptMechanismQueryInfo { epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo epicsSocketSystemCallInterruptMechanismQuery (); +/* + * Some systems (e.g Linux and Windows 10) allow to check the amount + * of unsent data in the output queue. + * Returns -1 if the information is not available. + */ +epicsShareFunc int epicsSocketUnsentCount(SOCKET sock); /* * convert socket address to ASCII in this order From ee1eac3f4c2a6ecdc38ed01ef6b7f6935038a131 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 23 Sep 2019 18:55:51 -0700 Subject: [PATCH 153/281] iocshRegisterVariable() takes an array --- modules/libcom/src/iocsh/libComRegister.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/iocsh/libComRegister.c b/modules/libcom/src/iocsh/libComRegister.c index 8fd5e7924..04628bb53 100644 --- a/modules/libcom/src/iocsh/libComRegister.c +++ b/modules/libcom/src/iocsh/libComRegister.c @@ -394,7 +394,7 @@ static void installLastResortEventProviderCallFunc(const iocshArgBuf *args) installLastResortEventProvider(); } -static iocshVarDef asCheckClientIPDef = {"asCheckClientIP", iocshArgInt, 0}; +static iocshVarDef asCheckClientIPDef[] = { { "asCheckClientIP", iocshArgInt, 0 }, { NULL, iocshArgInt, NULL } }; void epicsShareAPI libComRegister(void) { @@ -429,6 +429,6 @@ void epicsShareAPI libComRegister(void) iocshRegister(&generalTimeReportFuncDef,generalTimeReportCallFunc); iocshRegister(&installLastResortEventProviderFuncDef, installLastResortEventProviderCallFunc); - asCheckClientIPDef.pval = &asCheckClientIP; - iocshRegisterVariable(&asCheckClientIPDef); + asCheckClientIPDef[0].pval = &asCheckClientIP; + iocshRegisterVariable(asCheckClientIPDef); } From f134abb84e9f6a475cae9cbed302d2e0fdf255bb Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Jul 2019 10:34:53 -0700 Subject: [PATCH 154/281] epicsThread avoid possible data race on joined --- modules/libcom/src/osi/epicsThread.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 92f833847..cf4fd4df7 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -153,11 +153,13 @@ bool epicsThread::exitWait ( const double delay ) throw () if ( this->pThreadDestroyed ) { *this->pThreadDestroyed = true; } - if(!joined) { - { - epicsGuard < epicsMutex > guard ( this->mutex ); - joined = true; - } + bool j; + { + epicsGuard < epicsMutex > guard ( this->mutex ); + j = joined; + joined = true; + } + if(!j) { epicsThreadMustJoin(this->id); } return true; From b68f47927ca9be0a59dab157a733480aabd67f6c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Sep 2019 20:21:56 -0700 Subject: [PATCH 155/281] WIN32 remove atexit cleanup of TLS Force cleanup of resource for threads which may still be running opens the possibility of strange race conditions. Like threads be erroneously detected as non-epics. Doing this cleanup at process exit serves no real purpose. This code might be valid to re-add in a DLL exit handler. --- modules/libcom/src/osi/os/WIN32/osdThread.c | 29 --------------------- 1 file changed, 29 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 1cfa1ec5c..f86c5e8ac 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -37,7 +37,6 @@ epicsShareFunc void osdThreadHooksRun(epicsThreadId id); void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName ); -static void threadCleanupWIN32 ( void ); typedef struct win32ThreadGlobal { CRITICAL_SECTION mutex; @@ -218,15 +217,6 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) return 0; } - crtlStatus = atexit ( threadCleanupWIN32 ); - if ( crtlStatus ) { - TlsFree ( pWin32ThreadGlobal->tlsIndexThreadLibraryEPICS ); - DeleteCriticalSection ( & pWin32ThreadGlobal->mutex ); - free ( pWin32ThreadGlobal ); - pWin32ThreadGlobal = 0; - return 0; - } - InterlockedExchange ( & initCompleted, 1 ); return pWin32ThreadGlobal; @@ -254,25 +244,6 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) } } -/* - * threadCleanupWIN32 () - */ -static void threadCleanupWIN32 ( void ) -{ - win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); - win32ThreadParam * pParm; - - if ( ! pGbl ) { - fprintf ( stderr, "threadCleanupWIN32: unable to find ctx\n" ); - return; - } - - while ( ( pParm = ( win32ThreadParam * ) - ellFirst ( & pGbl->threadList ) ) ) { - epicsParmCleanupWIN32 ( pParm ); - } -} - /* * epicsThreadExitMain () */ From 17aaf50136288c9e5900aaab0153cc9c792341d6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 24 Sep 2019 20:36:18 -0700 Subject: [PATCH 156/281] WIN32 must clean TLS from correct thread epicsParmCleanupWIN32() may be called from threads other than the one being cleaned up. --- modules/libcom/src/osi/os/WIN32/osdThread.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index f86c5e8ac..980d5b563 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -240,7 +240,6 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) CloseHandle ( pParm->handle ); free ( pParm ); - TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, 0 ); } } @@ -488,6 +487,7 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) /* * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!! */ + TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, 0 ); epicsParmCleanupWIN32 ( pParm ); return retStat; /* this indirectly closes the thread handle */ From 03268bc68397bf6982481c7971eb85f0a04c59a9 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Wed, 11 Sep 2019 00:24:19 -0700 Subject: [PATCH 157/281] Shared lib rpath should not depend on whether or not static libs are also being built. --- configure/os/CONFIG.Common.linuxCommon | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index 965de09b8..487d7f74b 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -23,10 +23,10 @@ STATIC_LDFLAGS_YES= -Wl,-Bstatic STATIC_LDFLAGS_NO= STATIC_LDLIBS_YES= -Wl,-Bdynamic -# Set runtime path for shared libraries if USE_RPATH=YES and STATIC_BUILD=NO -SHRLIBDIR_RPATH_LDFLAGS_YES_NO = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) +# Set runtime path for shared libraries if USE_RPATH=YES +SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) SHRLIBDIR_LDFLAGS += \ - $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD)) + $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) # Set runtime path for products if USE_RPATH=YES and STATIC_BUILD=NO PRODDIR_RPATH_LDFLAGS_YES_NO = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) From 8c5d93d0442b643c0ec940556b2b8f936fc2f4da Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 26 Sep 2019 16:13:49 -0700 Subject: [PATCH 158/281] Also apply rpath change to PRODDIR_RPATH_LDFLAGS --- configure/os/CONFIG.Common.linuxCommon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index 487d7f74b..eefd5a340 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -29,9 +29,9 @@ SHRLIBDIR_LDFLAGS += \ $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) # Set runtime path for products if USE_RPATH=YES and STATIC_BUILD=NO -PRODDIR_RPATH_LDFLAGS_YES_NO = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) +PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) PRODDIR_LDFLAGS += \ - $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)_$(STATIC_BUILD)) + $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) # Link libraries controlled by COMMANDLINE_LIBRARY # The newest Linux versions only need readline, older ones need both From feb44624a1557eab363d2fb80a31cbdadf3d3d48 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 26 Sep 2019 16:32:08 -0700 Subject: [PATCH 159/281] Fix comment as well --- configure/os/CONFIG.Common.linuxCommon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index eefd5a340..d7f5b414b 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -28,7 +28,7 @@ SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) SHRLIBDIR_LDFLAGS += \ $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) -# Set runtime path for products if USE_RPATH=YES and STATIC_BUILD=NO +# Set runtime path for products if USE_RPATH=YES PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) PRODDIR_LDFLAGS += \ $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) From 4f0c9c97c6265f2a37ace54824ad4cf3bc453203 Mon Sep 17 00:00:00 2001 From: Bruce Hill Date: Thu, 26 Sep 2019 16:34:21 -0700 Subject: [PATCH 160/281] Another comment fix --- configure/os/CONFIG.Common.linuxCommon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure/os/CONFIG.Common.linuxCommon b/configure/os/CONFIG.Common.linuxCommon index d7f5b414b..5405be723 100644 --- a/configure/os/CONFIG.Common.linuxCommon +++ b/configure/os/CONFIG.Common.linuxCommon @@ -23,12 +23,12 @@ STATIC_LDFLAGS_YES= -Wl,-Bstatic STATIC_LDFLAGS_NO= STATIC_LDLIBS_YES= -Wl,-Bdynamic -# Set runtime path for shared libraries if USE_RPATH=YES +# Set runtime path for shared libraries if LINKER_USE_RPATH=YES SHRLIBDIR_RPATH_LDFLAGS_YES = $(SHRLIB_DEPLIB_DIRS:%=-Wl,-rpath,%) SHRLIBDIR_LDFLAGS += \ $(SHRLIBDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) -# Set runtime path for products if USE_RPATH=YES +# Set runtime path for products if LINKER_USE_RPATH=YES PRODDIR_RPATH_LDFLAGS_YES = $(PROD_DEPLIB_DIRS:%=-Wl,-rpath,%) PRODDIR_LDFLAGS += \ $(PRODDIR_RPATH_LDFLAGS_$(LINKER_USE_RPATH)) From 1d5bb93a1f151b1848feeb84e80e5170b2feaf62 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sun, 29 Sep 2019 18:31:49 +0100 Subject: [PATCH 161/281] Enable VS 2019 and debug builds on Appveyor * Add VS2019 build target * Install Strawberry perl when building VS2019 (this image is missing perl) * Build debug configuration with MSVC (previously just mingw and cygwin) * allow static-debug on MSVC by setting -static and modifying CONFIG_SITE --- .appveyor.yml | 16 +++++++++++ .ci/appveyor-make.bat | 21 +++++++++++--- .ci/appveyor-prepare.bat | 59 ++++++++++++++++++++-------------------- 3 files changed, 63 insertions(+), 33 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3d0b49f1b..b3ae1fa99 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -46,6 +46,8 @@ environment: - TOOLCHAIN: 14.0 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 TOOLCHAIN: 2017 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLCHAIN: 2019 - TOOLCHAIN: cygwin - TOOLCHAIN: mingw APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -83,6 +85,20 @@ build_script: test_script: - cmd: .ci/appveyor-make.bat runtests + +#---------------------------------# +# debugging # +#---------------------------------# + +## if you want to connect by remote desktop to a failed build, uncomment these lines +## note that you will need to connect within the usual build timeout limit (60 minutes) +## so you may want to adjust the build matrix above to just build the one of interest + +#on_failure: +# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + + #---------------------------------# # notifications # #---------------------------------# diff --git a/.ci/appveyor-make.bat b/.ci/appveyor-make.bat index 9cd8fe684..d74c8758d 100644 --- a/.ci/appveyor-make.bat +++ b/.ci/appveyor-make.bat @@ -1,6 +1,6 @@ :: Universal build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/cygwin/mingw] +:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/2019/cygwin/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static] :: PLATFORM - architecture [x86/x64] :: @@ -8,8 +8,16 @@ Setlocal EnableDelayedExpansion +:: we do not currently have a combined static and debug EPICS_HOST_ARCH target +:: So a combined debug and static target will appear to be just static +:: but debug will have been specified in CONFIG_SITE by appveyor-prepare.bat set "ST=" -if /i "%CONFIGURATION%"=="static" set ST=-static +echo.%CONFIGURATION% | findstr /C:"debug">nul && ( + set "ST=-debug" +) +echo.%CONFIGURATION% | findstr /C:"static">nul && ( + set "ST=-static" +) set OS=64BIT if "%PLATFORM%"=="x86" set OS=32BIT @@ -56,6 +64,11 @@ if "%TOOLCHAIN%"=="mingw" ( goto Finish ) +if "%TOOLCHAIN%"=="2019" ( + echo [INFO] Setting strawberry perl path + set "PATH=c:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH%" +) + set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio %TOOLCHAIN%" if not exist "%VSINSTALL%\" set "VSINSTALL=C:\Program Files (x86)\Microsoft Visual Studio\%TOOLCHAIN%\Community" if not exist "%VSINSTALL%\" goto MSMissing @@ -66,7 +79,7 @@ echo [INFO] APPVEYOR_BUILD_WORKER_IMAGE=%APPVEYOR_BUILD_WORKER_IMAGE% if "%OS%"=="64BIT" ( set EPICS_HOST_ARCH=windows-x64%ST% - :: VS 2017 + :: VS 2017/2019 if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" ( call "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" where cl @@ -91,7 +104,7 @@ if "%OS%"=="64BIT" ( ) ) else ( set EPICS_HOST_ARCH=win32-x86%ST% - :: VS 2017 + :: VS 2017/2019 if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat" ( call "%VSINSTALL%\VC\Auxiliary\Build\vcvars32.bat" where cl diff --git a/.ci/appveyor-prepare.bat b/.ci/appveyor-prepare.bat index 9f105ee96..95a6a07c8 100644 --- a/.ci/appveyor-prepare.bat +++ b/.ci/appveyor-prepare.bat @@ -16,20 +16,26 @@ if "%PLATFORM%"=="x86" set OS=32BIT echo [INFO] Platform: %OS% +:: with MSVC either static or debug can be handled as part +:: of EPICS_HOST_ARCH but not both. So we set the appropriate +:: options in CONFIG_SITE. For mingw and cygwin they are missing +:: some static and debug targets so set things here too +echo.%CONFIGURATION% | findstr /C:"static">nul && ( + echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE + echo STATIC_BUILD=YES>> configure\CONFIG_SITE + echo [INFO] EPICS set up for static build +) || ( + echo [INFO] EPICS set up for dynamic build +) + +echo.%CONFIGURATION% | findstr /C:"debug">nul && ( + echo HOST_OPT=NO>> configure\CONFIG_SITE + echo [INFO] EPICS set up for debug build +) || ( + echo [INFO] EPICS set up for optimized build +) + if "%TOOLCHAIN%"=="cygwin" ( - echo.%CONFIGURATION% | findstr /C:"static">nul && ( - echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE - echo STATIC_BUILD=YES>> configure\CONFIG_SITE - echo [INFO] EPICS set up for static build - ) || ( - echo [INFO] EPICS set up for dynamic build - ) - echo.%CONFIGURATION% | findstr /C:"debug">nul && ( - echo HOST_OPT=NO>> configure\CONFIG_SITE - echo [INFO] EPICS set up for debug build - ) || ( - echo [INFO] EPICS set up for optimized build - ) if "%OS%"=="64BIT" ( echo [INFO] Installing Cygwin 64bit and dependencies @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86_64.exe', 'C:\cygwin64\setup-x86_64.exe')" @@ -41,23 +47,18 @@ if "%TOOLCHAIN%"=="cygwin" ( ) ) -if "%TOOLCHAIN%"=="mingw" ( - echo.%CONFIGURATION% | findstr /C:"static">nul && ( - echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE - echo STATIC_BUILD=YES>> configure\CONFIG_SITE - echo [INFO] EPICS set up for static build - ) || ( - echo [INFO] EPICS set up for dynamic build - ) - echo.%CONFIGURATION% | findstr /C:"debug">nul && ( - echo HOST_OPT=NO>> configure\CONFIG_SITE - echo [INFO] EPICS set up for debug build - ) || ( - echo [INFO] EPICS set up for optimized build - ) -) - echo [INFO] Installing Make 4.2.1 from ANL web site curl -fsS --retry 3 -o C:\tools\make-4.2.1.zip https://epics.anl.gov/download/tools/make-4.2.1-win64.zip cd \tools "C:\Program Files\7-Zip\7z" e make-4.2.1.zip + +if "%TOOLCHAIN%"=="2019" ( + set "PERLVER=5.30.0.1" + echo [INFO] Installing Strawberry Perl %PERLVER% + curl -fsS --retry 3 -o C:\tools\perl-%PERLVER%.zip http://strawberryperl.com/download/%PERLVER%/strawberry-perl-%PERLVER%-64bit.zip + cd \tools + "C:\Program Files\7-Zip\7z" x perl-%PERLVER%.zip -oC:\strawberry + cd \strawberry + :: we set PATH in appveyor-build.bat + call relocation.pl.bat +) From 4aee25e8e2f911c08c8ebaf4245abd54d70bd84c Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 30 Sep 2019 22:37:42 +0100 Subject: [PATCH 162/281] Exclude VS2012 from -FS option --- configure/os/CONFIG.win32-x86.win32-x86 | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 7d6c11b6b..d2499c4c4 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -140,14 +140,15 @@ STATIC_LDLIBS_NO= STATIC_LDFLAGS= RANLIB= -# -# option needed for parallel builds with Visual Studio 2015 onward -# +# option needed for parallel builds with Visual Studio 2013 onward +# VS2012 and above have VisualStudioVersion, so just need to exclude 2012 (11.0) # -FS Force Synchronous PDB Writes ifneq ($(VisualStudioVersion),) +ifneq ($(VisualStudioVersion),11.0) OPT_CXXFLAGS_NO += -FS OPT_CFLAGS_NO += -FS endif +endif # From e29a53f01a2c3859202aa5c9f7f2055412634633 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 30 Sep 2019 22:48:54 +0100 Subject: [PATCH 163/281] Formatting --- configure/os/CONFIG.win32-x86.win32-x86 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index d2499c4c4..6a5078d60 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -140,9 +140,11 @@ STATIC_LDLIBS_NO= STATIC_LDFLAGS= RANLIB= +# # option needed for parallel builds with Visual Studio 2013 onward # VS2012 and above have VisualStudioVersion, so just need to exclude 2012 (11.0) # -FS Force Synchronous PDB Writes +# ifneq ($(VisualStudioVersion),) ifneq ($(VisualStudioVersion),11.0) OPT_CXXFLAGS_NO += -FS From d90e6b1a48196bb07b606327cf29bf6a26d69ba4 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 30 Sep 2019 23:21:59 +0100 Subject: [PATCH 164/281] Use MY_OS to avoid conflict with existing OS variable --- .ci/appveyor-make.bat | 14 +++++++------- .ci/appveyor-prepare.bat | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.ci/appveyor-make.bat b/.ci/appveyor-make.bat index d74c8758d..f06f7fa09 100644 --- a/.ci/appveyor-make.bat +++ b/.ci/appveyor-make.bat @@ -19,10 +19,10 @@ echo.%CONFIGURATION% | findstr /C:"static">nul && ( set "ST=-static" ) -set OS=64BIT -if "%PLATFORM%"=="x86" set OS=32BIT +set MY_OS=64BIT +if "%PLATFORM%"=="x86" set MY_OS=32BIT -echo [INFO] Platform: %OS% +echo [INFO] Platform: %MY_OS% :: Use parallel make, except for 3.14 set "MAKEARGS=-j2 -Otarget" @@ -30,7 +30,7 @@ if "%APPVEYOR_REPO_BRANCH%"=="3.14" set MAKEARGS= if "%TOOLCHAIN%"=="cygwin" ( set "MAKE=make" - if "%OS%"=="64BIT" ( + if "%MY_OS%"=="64BIT" ( set "EPICS_HOST_ARCH=cygwin-x86_64" set "INCLUDE=C:\cygwin64\include;%INCLUDE%" set "PATH=C:\cygwin64\bin;%PATH%" @@ -48,7 +48,7 @@ if "%TOOLCHAIN%"=="cygwin" ( if "%TOOLCHAIN%"=="mingw" ( set "MAKE=mingw32-make" - if "%OS%"=="64BIT" ( + if "%MY_OS%"=="64BIT" ( set "EPICS_HOST_ARCH=windows-x64-mingw" set "INCLUDE=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\include;%INCLUDE%" set "PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH%" @@ -77,7 +77,7 @@ set "MAKE=C:\tools\make" echo [INFO] APPVEYOR_BUILD_WORKER_IMAGE=%APPVEYOR_BUILD_WORKER_IMAGE% -if "%OS%"=="64BIT" ( +if "%MY_OS%"=="64BIT" ( set EPICS_HOST_ARCH=windows-x64%ST% :: VS 2017/2019 if exist "%VSINSTALL%\VC\Auxiliary\Build\vcvars64.bat" ( @@ -132,7 +132,7 @@ if "%OS%"=="64BIT" ( ) :MSMissing -echo [INFO] Installation for MSVC Toolchain %TOOLCHAIN% / %OS% seems to be missing +echo [INFO] Installation for MSVC Toolchain %TOOLCHAIN% / %MY_OS% seems to be missing exit 1 :MSFound diff --git a/.ci/appveyor-prepare.bat b/.ci/appveyor-prepare.bat index 95a6a07c8..255165256 100644 --- a/.ci/appveyor-prepare.bat +++ b/.ci/appveyor-prepare.bat @@ -11,10 +11,10 @@ Setlocal EnableDelayedExpansion -set OS=64BIT -if "%PLATFORM%"=="x86" set OS=32BIT +set MY_OS=64BIT +if "%PLATFORM%"=="x86" set MY_OS=32BIT -echo [INFO] Platform: %OS% +echo [INFO] Platform: %MY_OS% :: with MSVC either static or debug can be handled as part :: of EPICS_HOST_ARCH but not both. So we set the appropriate @@ -36,7 +36,7 @@ echo.%CONFIGURATION% | findstr /C:"debug">nul && ( ) if "%TOOLCHAIN%"=="cygwin" ( - if "%OS%"=="64BIT" ( + if "%MY_OS%"=="64BIT" ( echo [INFO] Installing Cygwin 64bit and dependencies @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86_64.exe', 'C:\cygwin64\setup-x86_64.exe')" C:\cygwin64\setup-x86_64.exe -q -P "libreadline-devel,libncursesw-devel" From 7325652d8b9e77546df0a34f31ebfe0e2ec1f7cf Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 1 Oct 2019 23:00:23 +0100 Subject: [PATCH 165/281] Set PERLVER outside if clause --- .ci/appveyor-prepare.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/appveyor-prepare.bat b/.ci/appveyor-prepare.bat index 255165256..bfeff3b56 100644 --- a/.ci/appveyor-prepare.bat +++ b/.ci/appveyor-prepare.bat @@ -52,8 +52,8 @@ curl -fsS --retry 3 -o C:\tools\make-4.2.1.zip https://epics.anl.gov/download/to cd \tools "C:\Program Files\7-Zip\7z" e make-4.2.1.zip +set "PERLVER=5.30.0.1" if "%TOOLCHAIN%"=="2019" ( - set "PERLVER=5.30.0.1" echo [INFO] Installing Strawberry Perl %PERLVER% curl -fsS --retry 3 -o C:\tools\perl-%PERLVER%.zip http://strawberryperl.com/download/%PERLVER%/strawberry-perl-%PERLVER%-64bit.zip cd \tools From 643d58fd0496b03c6ddd1d46bcae8de1ddce5283 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 2 Oct 2019 15:49:12 -0400 Subject: [PATCH 166/281] appveyor-ci: completely remove cygwin builds --- appveyor.yml | 7 ------- ci/appveyor-make.bat | 20 +------------------- ci/appveyor-prepare.bat | 29 ++--------------------------- 3 files changed, 3 insertions(+), 53 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 21ec93c86..ff829f801 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -46,7 +46,6 @@ environment: - TOOLCHAIN: 14.0 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 TOOLCHAIN: 2017 - - TOOLCHAIN: cygwin - TOOLCHAIN: mingw APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -61,12 +60,6 @@ matrix: # VS Express installs don't have the 64 bit compiler - platform: x64 TOOLCHAIN: 10.0 - # Cygwin static-debug has compiler problems - - configuration: static-debug - TOOLCHAIN: cygwin - # Cygwin x86 install is currently (08/2019) broken (libncursesw-devel fails) - - platform: x86 - TOOLCHAIN: cygwin #---------------------------------# diff --git a/ci/appveyor-make.bat b/ci/appveyor-make.bat index 9cd8fe684..8d976d93d 100644 --- a/ci/appveyor-make.bat +++ b/ci/appveyor-make.bat @@ -1,6 +1,6 @@ :: Universal build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/cygwin/mingw] +:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static] :: PLATFORM - architecture [x86/x64] :: @@ -20,24 +20,6 @@ echo [INFO] Platform: %OS% set "MAKEARGS=-j2 -Otarget" if "%APPVEYOR_REPO_BRANCH%"=="3.14" set MAKEARGS= -if "%TOOLCHAIN%"=="cygwin" ( - set "MAKE=make" - if "%OS%"=="64BIT" ( - set "EPICS_HOST_ARCH=cygwin-x86_64" - set "INCLUDE=C:\cygwin64\include;%INCLUDE%" - set "PATH=C:\cygwin64\bin;%PATH%" - echo [INFO] Cygwin Toolchain 64bit - ) else ( - set "EPICS_HOST_ARCH=cygwin-x86" - set "INCLUDE=C:\cygwin\include;%INCLUDE%" - set "PATH=C:\cygwin\bin;%PATH%" - echo [INFO] Cygwin Toolchain 32bit - ) - echo [INFO] Compiler Version - gcc -v - goto Finish -) - if "%TOOLCHAIN%"=="mingw" ( set "MAKE=mingw32-make" if "%OS%"=="64BIT" ( diff --git a/ci/appveyor-prepare.bat b/ci/appveyor-prepare.bat index 9f105ee96..a685dbfb3 100644 --- a/ci/appveyor-prepare.bat +++ b/ci/appveyor-prepare.bat @@ -1,12 +1,12 @@ :: Build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/cygwin/mingw] +:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static, -debug] :: PLATFORM - "x86" -> use 32bit architecture :: :: Prepares an Appveyor build by excuting the following steps :: - Set up configure\CONFIG_SITE for static vs. dynamic build -:: - Install Cygwin / Mingw (TOOLCHAIN setting) in the in the appropriate flavor +:: - Install Mingw (TOOLCHAIN setting) in the in the appropriate flavor :: - Download and install Make-4.1 from EPICS download page Setlocal EnableDelayedExpansion @@ -16,31 +16,6 @@ if "%PLATFORM%"=="x86" set OS=32BIT echo [INFO] Platform: %OS% -if "%TOOLCHAIN%"=="cygwin" ( - echo.%CONFIGURATION% | findstr /C:"static">nul && ( - echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE - echo STATIC_BUILD=YES>> configure\CONFIG_SITE - echo [INFO] EPICS set up for static build - ) || ( - echo [INFO] EPICS set up for dynamic build - ) - echo.%CONFIGURATION% | findstr /C:"debug">nul && ( - echo HOST_OPT=NO>> configure\CONFIG_SITE - echo [INFO] EPICS set up for debug build - ) || ( - echo [INFO] EPICS set up for optimized build - ) - if "%OS%"=="64BIT" ( - echo [INFO] Installing Cygwin 64bit and dependencies - @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86_64.exe', 'C:\cygwin64\setup-x86_64.exe')" - C:\cygwin64\setup-x86_64.exe -q -P "libreadline-devel,libncursesw-devel" - ) else ( - echo [INFO] Installing Cygwin 32bit and dependencies - @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86.exe', 'C:\cygwin\setup-x86.exe')" - C:\cygwin\setup-x86.exe -q -P "libreadline-devel,libncursesw-devel" - ) -) - if "%TOOLCHAIN%"=="mingw" ( echo.%CONFIGURATION% | findstr /C:"static">nul && ( echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE From 243b53ecaeb470c6c01b86d9f5e05a9a598bb637 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 2 Oct 2019 15:49:12 -0400 Subject: [PATCH 167/281] appveyor-ci: completely remove cygwin builds --- .appveyor.yml | 7 ------- .ci/appveyor-make.bat | 20 +------------------- .ci/appveyor-prepare.bat | 29 ++--------------------------- 3 files changed, 3 insertions(+), 53 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3d0b49f1b..626eeb3c4 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -46,7 +46,6 @@ environment: - TOOLCHAIN: 14.0 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 TOOLCHAIN: 2017 - - TOOLCHAIN: cygwin - TOOLCHAIN: mingw APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -61,12 +60,6 @@ matrix: # VS Express installs don't have the 64 bit compiler - platform: x64 TOOLCHAIN: 10.0 - # Cygwin static-debug has compiler problems - - configuration: static-debug - TOOLCHAIN: cygwin - # Cygwin x86 install is currently (08/2019) broken (libncursesw-devel fails) - - platform: x86 - TOOLCHAIN: cygwin #---------------------------------# diff --git a/.ci/appveyor-make.bat b/.ci/appveyor-make.bat index 9cd8fe684..8d976d93d 100644 --- a/.ci/appveyor-make.bat +++ b/.ci/appveyor-make.bat @@ -1,6 +1,6 @@ :: Universal build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/cygwin/mingw] +:: TOOLCHAIN - toolchain version [10.0/11.0/12.0/14.0/2017/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static] :: PLATFORM - architecture [x86/x64] :: @@ -20,24 +20,6 @@ echo [INFO] Platform: %OS% set "MAKEARGS=-j2 -Otarget" if "%APPVEYOR_REPO_BRANCH%"=="3.14" set MAKEARGS= -if "%TOOLCHAIN%"=="cygwin" ( - set "MAKE=make" - if "%OS%"=="64BIT" ( - set "EPICS_HOST_ARCH=cygwin-x86_64" - set "INCLUDE=C:\cygwin64\include;%INCLUDE%" - set "PATH=C:\cygwin64\bin;%PATH%" - echo [INFO] Cygwin Toolchain 64bit - ) else ( - set "EPICS_HOST_ARCH=cygwin-x86" - set "INCLUDE=C:\cygwin\include;%INCLUDE%" - set "PATH=C:\cygwin\bin;%PATH%" - echo [INFO] Cygwin Toolchain 32bit - ) - echo [INFO] Compiler Version - gcc -v - goto Finish -) - if "%TOOLCHAIN%"=="mingw" ( set "MAKE=mingw32-make" if "%OS%"=="64BIT" ( diff --git a/.ci/appveyor-prepare.bat b/.ci/appveyor-prepare.bat index 9f105ee96..a685dbfb3 100644 --- a/.ci/appveyor-prepare.bat +++ b/.ci/appveyor-prepare.bat @@ -1,12 +1,12 @@ :: Build script for AppVeyor (https://ci.appveyor.com/) :: Environment: -:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/cygwin/mingw] +:: TOOLCHAIN - Toolchain Version [9.0/10.0/11.0/12.0/14.0/mingw] :: CONFIGURATION - determines EPICS build [dynamic/static, -debug] :: PLATFORM - "x86" -> use 32bit architecture :: :: Prepares an Appveyor build by excuting the following steps :: - Set up configure\CONFIG_SITE for static vs. dynamic build -:: - Install Cygwin / Mingw (TOOLCHAIN setting) in the in the appropriate flavor +:: - Install Mingw (TOOLCHAIN setting) in the in the appropriate flavor :: - Download and install Make-4.1 from EPICS download page Setlocal EnableDelayedExpansion @@ -16,31 +16,6 @@ if "%PLATFORM%"=="x86" set OS=32BIT echo [INFO] Platform: %OS% -if "%TOOLCHAIN%"=="cygwin" ( - echo.%CONFIGURATION% | findstr /C:"static">nul && ( - echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE - echo STATIC_BUILD=YES>> configure\CONFIG_SITE - echo [INFO] EPICS set up for static build - ) || ( - echo [INFO] EPICS set up for dynamic build - ) - echo.%CONFIGURATION% | findstr /C:"debug">nul && ( - echo HOST_OPT=NO>> configure\CONFIG_SITE - echo [INFO] EPICS set up for debug build - ) || ( - echo [INFO] EPICS set up for optimized build - ) - if "%OS%"=="64BIT" ( - echo [INFO] Installing Cygwin 64bit and dependencies - @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86_64.exe', 'C:\cygwin64\setup-x86_64.exe')" - C:\cygwin64\setup-x86_64.exe -q -P "libreadline-devel,libncursesw-devel" - ) else ( - echo [INFO] Installing Cygwin 32bit and dependencies - @powershell -Command "(new-object net.webclient).DownloadFile('http://www.cygwin.com/setup-x86.exe', 'C:\cygwin\setup-x86.exe')" - C:\cygwin\setup-x86.exe -q -P "libreadline-devel,libncursesw-devel" - ) -) - if "%TOOLCHAIN%"=="mingw" ( echo.%CONFIGURATION% | findstr /C:"static">nul && ( echo SHARED_LIBRARIES=NO>> configure\CONFIG_SITE From 4bb81654d60a5d343aeee1aa1ac8276c9ab43f75 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Fri, 4 Oct 2019 14:32:07 +0200 Subject: [PATCH 168/281] use EPICS_PRIVATE_API macro and fix bug with darwin/ios --- modules/libcom/src/log/logClient.c | 1 + modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c | 4 +++- modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c | 1 + modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c | 1 + modules/libcom/src/osi/os/default/osdSockUnsentCount.c | 1 + modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c | 4 +++- modules/libcom/src/osi/osiSock.h | 2 ++ 7 files changed, 12 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 73664ff76..9a09ef7b7 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -21,6 +21,7 @@ #include #include +#define EPICS_PRIVATE_API #define epicsExportSharedSymbols #include "dbDefs.h" #include "epicsEvent.h" diff --git a/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c b/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c index 00ef550bd..20bd82b14 100644 --- a/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c +++ b/modules/libcom/src/osi/os/Darwin/osdSockUnsentCount.c @@ -3,6 +3,7 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +#define EPICS_PRIVATE_API #include "osiSock.h" /* @@ -11,7 +12,8 @@ */ int epicsSocketUnsentCount(SOCKET sock) { int unsent; - if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent) == 0) + socklen_t len = sizeof(unsent); + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0) return unsent; return -1; } diff --git a/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c b/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c index 6f6cbf0fe..3c0a8f915 100644 --- a/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c +++ b/modules/libcom/src/osi/os/Linux/osdSockUnsentCount.c @@ -4,6 +4,7 @@ \*************************************************************************/ #include +#define EPICS_PRIVATE_API #include "osiSock.h" /* diff --git a/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c b/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c index c2045bc79..fe68ead01 100644 --- a/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c +++ b/modules/libcom/src/osi/os/WIN32/osdSockUnsentCount.c @@ -4,6 +4,7 @@ \*************************************************************************/ #define epicsExportSharedSymbols +#define EPICS_PRIVATE_API #include "osiSock.h" #include diff --git a/modules/libcom/src/osi/os/default/osdSockUnsentCount.c b/modules/libcom/src/osi/os/default/osdSockUnsentCount.c index 61094c710..ef01e9b24 100644 --- a/modules/libcom/src/osi/os/default/osdSockUnsentCount.c +++ b/modules/libcom/src/osi/os/default/osdSockUnsentCount.c @@ -3,6 +3,7 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +#define EPICS_PRIVATE_API #include "osiSock.h" /* diff --git a/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c b/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c index 00ef550bd..20bd82b14 100644 --- a/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c +++ b/modules/libcom/src/osi/os/iOS/osdSockUnsentCount.c @@ -3,6 +3,7 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +#define EPICS_PRIVATE_API #include "osiSock.h" /* @@ -11,7 +12,8 @@ */ int epicsSocketUnsentCount(SOCKET sock) { int unsent; - if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent) == 0) + socklen_t len = sizeof(unsent); + if (getsockopt(sock, SOL_SOCKET, SO_NWRITE, &unsent, &len) == 0) return unsent; return -1; } diff --git a/modules/libcom/src/osi/osiSock.h b/modules/libcom/src/osi/osiSock.h index e1c2de881..6e3b053c5 100644 --- a/modules/libcom/src/osi/osiSock.h +++ b/modules/libcom/src/osi/osiSock.h @@ -52,12 +52,14 @@ enum epicsSocketSystemCallInterruptMechanismQueryInfo { epicsShareFunc enum epicsSocketSystemCallInterruptMechanismQueryInfo epicsSocketSystemCallInterruptMechanismQuery (); +#ifdef EPICS_PRIVATE_API /* * Some systems (e.g Linux and Windows 10) allow to check the amount * of unsent data in the output queue. * Returns -1 if the information is not available. */ epicsShareFunc int epicsSocketUnsentCount(SOCKET sock); +#endif /* * convert socket address to ASCII in this order From e83818b25e8ba23b7d07f59704b0a54a6c3c9e4e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 29 Sep 2019 21:02:19 -0700 Subject: [PATCH 169/281] workaround apparent MSVC mis-optimization MSVC appears to misapply the identity "A + -A == 0" which is not true for non-finite floating point values. --- modules/libcom/test/epicsCalcTest.cpp | 10 ++-------- modules/libcom/test/epicsMathTest.c | 18 +++++++++--------- 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/modules/libcom/test/epicsCalcTest.cpp b/modules/libcom/test/epicsCalcTest.cpp index 2492c95ba..25701b153 100644 --- a/modules/libcom/test/epicsCalcTest.cpp +++ b/modules/libcom/test/epicsCalcTest.cpp @@ -612,18 +612,12 @@ MAIN(epicsCalcTest) testExpr(0.0 + NaN); testExpr(Inf + 0.0); testExpr(Inf + Inf); -#if defined(_WIN64) && defined(_MSC_VER) + // only test CALC as MSVC seems to incorrectly evaluate this expression at compile time. + // see note in epicsMathTest testCalc("Inf + -Inf", NaN); -#else - testExpr(Inf + -Inf); -#endif testExpr(Inf + NaN); testExpr(-Inf + 0.0); -#if defined(_WIN64) && defined(_MSC_VER) testCalc("-Inf + Inf", NaN); -#else - testExpr(-Inf + Inf); -#endif testExpr(-Inf + -Inf); testExpr(-Inf + NaN); testExpr(NaN + 0.0); diff --git a/modules/libcom/test/epicsMathTest.c b/modules/libcom/test/epicsMathTest.c index 8ea763cf0..6d1fb85e8 100644 --- a/modules/libcom/test/epicsMathTest.c +++ b/modules/libcom/test/epicsMathTest.c @@ -32,23 +32,23 @@ MAIN(epicsMathTest) testOk1(epicsINF > 0.0); testOk1(epicsINF - epicsINF != 0.0); -#if defined(_WIN64) && defined(_MSC_VER) - testTodoBegin("Known failure on windows-x64"); +#if defined(_MSC_VER) + testTodoBegin("Known failure on windows (MSVC optimizer bug?)"); #endif testOk1(epicsINF + -epicsINF != 0.0); testOk1(-epicsINF + epicsINF != 0.0); -#if defined(_WIN64) && defined(_MSC_VER) +#if defined(_MSC_VER) testTodoEnd(); #endif testOk1(isnan(epicsINF - epicsINF)); -#if defined(_WIN64) && defined(_MSC_VER) - testTodoBegin("Known failure on windows-x64"); +#if defined(_MSC_VER) + testTodoBegin("Known failure on windows (MSVC optimizer bug?)"); #endif testOk1(isnan(epicsINF + -epicsINF)); testOk1(isnan(-epicsINF + epicsINF)); -#if defined(_WIN64) && defined(_MSC_VER) +#if defined(_MSC_VER) testTodoEnd(); #endif @@ -62,12 +62,12 @@ MAIN(epicsMathTest) testOk1(!(epicsNAN > epicsNAN)); testOk1(isnan(epicsNAN - epicsNAN)); -#if defined(_WIN64) && defined(_MSC_VER) - testTodoBegin("Known failure on windows-x64"); +#if defined(_MSC_VER) + testTodoBegin("Known failure on windows (MSVC optimizer bug?)"); #endif testOk1(isnan(epicsNAN + -epicsNAN)); testOk1(isnan(-epicsNAN + epicsNAN)); -#if defined(_WIN64) && defined(_MSC_VER) +#if defined(_MSC_VER) testTodoEnd(); #endif From 8ff7658291f9ad37d6578a41cca255181247a158 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 25 Sep 2019 11:36:42 -0700 Subject: [PATCH 170/281] asLib: osiSockAttach() for asCheckClientIP WIN32 needs osiSockAttach() prior to aToIPAddr() which can now happen during ACF parsing. --- modules/libcom/src/as/asLibRoutines.c | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index ab0bf5071..3011d0a37 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -79,6 +79,7 @@ static long asAsgRuleCalc(ASGRULE *pasgrule,const char *calc); */ static void asInitializeOnce(void *arg) { + osiSockAttach(); asLock = epicsMutexMustCreate(); } long epicsShareAPI asInitialize(ASINPUTFUNCPTR inputfunction) From 1b12914ff0d6176526b399686881c8d4c4c16527 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 26 Sep 2019 19:45:20 -0700 Subject: [PATCH 171/281] avoid prove executable On windows prove.bat has the annoying limitations of a .bat script. Like a max. of 9 arguments. --- configure/RULES_BUILD | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 626788969..4f71838fa 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -364,7 +364,7 @@ testspec: $(TESTSCRIPTS) test-results: tapfiles ifneq ($(TAPFILES),) ifdef RUNTESTS_ENABLED - prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES) + $(PERL) -e 'use App::Prove;my $$app = App::Prove->new;$$app->process_args(@ARGV);exit( $$app->run ? 0 : 1 );' -- --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES) endif CURRENT_TAPFILES := $(wildcard $(TAPFILES)) From 46f6fc6bfa8576cdbef7ea1fdc8c9bcf3bb1130a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 1 Oct 2019 16:48:43 -0700 Subject: [PATCH 172/281] appveyor test-results --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index a2dbcb826..9bacc3596 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -76,7 +76,8 @@ build_script: - cmd: .ci/appveyor-make.bat test_script: - - cmd: .ci/appveyor-make.bat runtests + - cmd: .ci/appveyor-make.bat tapfiles + - cmd: .ci/appveyor-make.bat test-results #---------------------------------# From 51cceeab89960262e99fad07042cb6e0f258fd8d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 1 Oct 2019 16:56:17 -0700 Subject: [PATCH 173/281] appveyor always push artifacts on success or failure --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 9bacc3596..00c27ab60 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -79,6 +79,9 @@ test_script: - cmd: .ci/appveyor-make.bat tapfiles - cmd: .ci/appveyor-make.bat test-results +on_finish: + - ps: Get-ChildItem *.tap -Recurse -Force | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + #---------------------------------# # debugging # From d814d67a359348db023755278fef8c0c38c31886 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 6 Oct 2019 20:16:10 -0700 Subject: [PATCH 174/281] update release notes --- documentation/RELEASE_NOTES.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index e6e3fbdc1..b444cadcd 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -30,6 +30,13 @@ release.

--> +

Timers and delays use monotonic clock

+ +

Many internal timers and delay calculations use a monotonic clock +epicsTimeGetMonotonic() instead of the realtime epicsTimeGetCurrent(). +This is intended to make IOCs less susceptible to jumps in system +time.

+

Iocsh "on error ..."

A new statement is added to enable IOC shell commands From 1c93726ee6996f22aedf7887c5ce0d0d2c2ed89e Mon Sep 17 00:00:00 2001 From: Niamh Dougan Date: Fri, 6 Sep 2019 13:00:00 +0200 Subject: [PATCH 175/281] renamed RELEASE_NOTES.html -> RELEASE_NOTES.md --- documentation/{RELEASE_NOTES.html => RELEASE_NOTES.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename documentation/{RELEASE_NOTES.html => RELEASE_NOTES.md} (100%) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.md similarity index 100% rename from documentation/RELEASE_NOTES.html rename to documentation/RELEASE_NOTES.md From 292dfe8e16d0d2f325541025fecc8497af5c2b7d Mon Sep 17 00:00:00 2001 From: Niamh Dougan Date: Fri, 6 Sep 2019 13:00:54 +0200 Subject: [PATCH 176/281] Convert RELEASE_NOTES from html to .md Reformat relocations table, escape words with underscores inside `back-ticks`. --- documentation/RELEASE_NOTES.md | 2014 ++++++++++++++------------------ 1 file changed, 889 insertions(+), 1125 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 6f2019379..133c823a0 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -1,927 +1,865 @@ - - - - - EPICS Base R3.15.6 Release Notes - +# EPICS Base Release 3.15.7 - -

EPICS Base Release 3.15.7

+This version of EPICS Base has not been released yet. -

This version of EPICS Base has not been released yet.

- - -

Changes made on the 3.15 branch since 3.15.6

+## Changes made on the 3.15 branch since 3.15.6 -

Add option to avoid CALLBACK conflict

+### Add option to avoid CALLBACK conflict -

If a macro EPICS_NO_CALLBACK is defined, then callback.h will no longer (re)define CALLBACK. +If a macro `EPICS_NO_CALLBACK` is defined, then callback.h will no longer (re)define CALLBACK. The name 'CALLBACK' is used by the WIN32 API, and redefinition in callback.h cause errors if some windows headers are later included. -

-

Code which defines EPICS_NO_CALLBACK, but still wishes to use callbacks, should use +Code which defines `EPICS_NO_CALLBACK`, but still wishes to use callbacks, should use the alternate name 'epicsCallback' introduced in 3.15.6, 3.16.2, and 7.0.2. It is also possible, though not encouraged, to use 'struct callbackPvt' -which has been present since the callback API was introduced.

+which has been present since the callback API was introduced. -

Cleaning up with Multiple CA contexts in a Process

+### Cleaning up with Multiple CA contexts in a Process -

Bruno Martins reported a problem with the CA client library at shutdown in a +Bruno Martins reported a problem with the CA client library at shutdown in a process that uses multiple CA client contexts. The first context that triggers the CA client exit handler prevents any others from being able to clean up because it resets the ID of an internal epicsThreadPrivate variable which is shared by all clients. This action has been removed from the client library, -which makes cleanup of clients like this possible.

+which makes cleanup of clients like this possible. -

Perl CA bindings fixed for macOS Mojave

+### Perl CA bindings fixed for macOS Mojave -

Apple removed some Perl header files from macOS Mojave that were available +Apple removed some Perl header files from macOS Mojave that were available in their SDK, requiring a change to the include paths used when compiling the CA bindings. The new version should build on new and older macOS versions, and these changes may also help other targets that have an incomplete installation of Perl (the build will continue after printing a warning that the Perl CA -bindings could not be built).

+bindings could not be built). -

Routine epicsTempName() removed from libCom

+### Routine `epicsTempName()` removed from libCom -

This routine was a simple wrapper around the C89 function tmpnam() +This routine was a simple wrapper around the C89 function `tmpnam()` which is now seen as unsafe and causes warning messages to be generated by most modern compilers. The two internal uses of this function have been -modified to call epicsTempFile() instead. We were unable to find any +modified to call `epicsTempFile()` instead. We were unable to find any published code that used this function, so it was removed immediately instead -of being deprecated.

+of being deprecated. -

DBD Parsing of Record Types

+### DBD Parsing of Record Types -

The Perl DBD file parser has been made slightly more liberal; the order in +The Perl DBD file parser has been made slightly more liberal; the order in which DBD files must be parsed is now more flexible, so that a record type definition can now be parsed after a device support that referred to that record type. A warning message will be displayed when the device support is seen, but the subsequent loading of the record type will be accepted without triggering an error. See -Launchpad bug -#1801145.

+[Launchpad bug 1801145](https://bugs.launchpad.net/epics-base/+bug/1801145). -

menuScan and several record types documented with POD

+### menuScan and several record types documented with POD -

The EPICS Wiki pages describing a number of standard record types has been +The EPICS Wiki pages describing a number of standard record types has been converted into the Perl POD documentation format and added to the DBD files, so at build-time an HTML version of these documents is generated and installed -into the htmls directory. Thanks to Tony Pietryla.

+into the htmls directory. Thanks to Tony Pietryla. -

CA client tools learned -V option

+### CA client tools learned `-V` option -

This displays the version numbers of EPICS Base and the CA protocol.

+This displays the version numbers of EPICS Base and the CA protocol. +## Changes made between 3.15.5 and 3.15.6 -

Changes made between 3.15.5 and 3.15.6

+### Unsetting environment variables -

Unsetting environment variables

+The new command `epicsEnvUnset varname` can be used to +unset an environment variable. -

The new command epicsEnvUnset varname can be used to -unset an environment variable.

+### Warning indicators in msi (and macLib) output -

Warning indicators in msi (and macLib) output

- -

The libCom macro expansion library has been modified so that when the -SUPPRESS_WARNINGS flag is set it will no longer include any ,undefined -or ,recursive indicators in its output when undefined or recursive +The libCom macro expansion library has been modified so that when the +`SUPPRESS_WARNINGS` flag is set it will no longer include any `,undefined` +or `,recursive` indicators in its output when undefined or recursive macros are encountered. These indicators were harmless when the output was fed -into an IOC along with a definition for the macro, but when the msi +into an IOC along with a definition for the macro, but when the `msi` tool was used to generate other kinds of files they caused problems. If the -msi -V flag is used the markers will still be present in the output -whenever the appropriate condition is seen.

+`msi -V` flag is used the markers will still be present in the output +whenever the appropriate condition is seen. -

Improvements to msi

+### Improvements to msi -

In addition to fixing its response to discovering parsing errors in its +In addition to fixing its response to discovering parsing errors in its substitution input file (reported as Launchpad -bug #1503661) +[bug 1503661](https://bugs.launchpad.net/epics-base/+bug/1503661)) so it now deletes the incomplete output file, the msi program has been cleaned -up a little bit internally.

+up a little bit internally. -

All array records now post monitors on their array-length fields

+### All array records now post monitors on their array-length fields -

The waveform record has been posting monitors on its NORD field since Base +The waveform record has been posting monitors on its NORD field since Base 3.15.0.1; we finally got around to doing the equivalent in all the other built-in record types, which even required modifying device support in some -cases. This fixes -Launchpad bug #1730727.

+cases. This fixes +[Launchpad bug 1730727](https://bugs.launchpad.net/epics-base/+bug/1730727). -

HOWTO: Converting Wiki Record Reference to POD

+### HOWTO: Converting Wiki Record Reference to POD -

Some documentation has been added to the dbdToHtml.pl script +Some documentation has been added to the `dbdToHtml.pl` script explaining how Perl POD (Plain Old Documentation) markup can be added to -.dbd files to generate HTML documentation for the record types. To see -these instructions, run perl bin/<host>/dbdToHtml.pl -H -or perldoc bin/<host>/dbdToHtml.pl.

+`.dbd` files to generate HTML documentation for the record types. To see +these instructions, run `perl bin//dbdToHtml.pl -H` +or `perldoc bin//dbdToHtml.pl`. -

Fix problem with numeric soft events

+### Fix problem with numeric soft events -

Changing from numeric to named soft events introduced an incompatibility +Changing from numeric to named soft events introduced an incompatibility when a numeric event 1-255 is converted from a DOUBLE, e.g. from a calc record. -The post_event() API is not marked deprecated any more. +The `post_event()` API is not marked deprecated any more. -

Also scanpel has been modified to accept a glob pattern for -event name filtering and to show events with no connected records as well.

+Also `scanpel` has been modified to accept a glob pattern for +event name filtering and to show events with no connected records as well. -

Add osiSockOptMcastLoop_t and osiSockTest

+### Add `osiSockOptMcastLoop_t` and osiSockTest -

Added a new OS-independent typedef for multicast socket options, and a test -file to check their correct operation.

+Added a new OS-independent typedef for multicast socket options, and a test +file to check their correct operation. -

Support for CONFIG_SITE.local in Base

+### Support for `CONFIG_SITE.local` in Base -

This feature is mostly meant for use by developers; configuration -settings that would normally appear in Base/configure/CONFIG_SITE can now -be put in a locally created base/configure/CONFIG_SITE.local file instead -of having go modify or replace the original. A new .gitignore pattern -tells git to ignore all configure/*.local files.

+This feature is mostly meant for use by developers; configuration +settings that would normally appear in `base/configure/CONFIG_SITE` can now +be put in a locally created `base/configure/CONFIG_SITE.local` file instead +of having go modify or replace the original. A new `.gitignore` pattern +tells git to ignore all `configure/*.local` files. - +### Fix broken `EPICS_IOC_LOG_FILE_LIMIT=0` setting -

Fix broken EPICS_IOC_LOG_FILE_LIMIT=0 setting

- -

The Application Developers' Guide says this is allowed and disables the +The Application Developers' Guide says this is allowed and disables the limit on the log-file, but it hasn't actually worked for some time (if ever). Note that the iocLogServer will be removed from newer Base release sometime soon as its functionality can be implemented by other dedicated log servers -such as logstash or syslog-ng.

+such as logstash or syslog-ng. -

Fixes lp:1786858 -and part of lp:1786966. -

+Fixes [lp:1786858](https://bugs.launchpad.net/bugs/1786858) +and part of [lp:1786966](https://bugs.launchpad.net/bugs/1786966). -

Cleanup of startup directory

+### Cleanup of startup directory -

The files in the startup directory have not been maintained in recent years +The files in the startup directory have not been maintained in recent years and have grown crufty (technical term). This release includes the following -updates to these files:

+updates to these files: -
    + - The Perl `EpicsHostArch.pl` script has been rewritten, and support + for a few previously missing host architectures has been added to it. + - The `EpicsHostArch.pl` script has also been moved into the standard + `src/tools` directory, from where it will be installed into + `lib/perl`. In this new location it is no longer executable, so it must + be run by the `perl` executable. + - The build system has been adjusted to look for `EpicsHostArch.pl` in + both places if the `EPICS_HOST_ARCH` environment variable has not been + set at build-time. + - Sites that used the original Perl script to set `EPICS_HOST_ARCH` as + part of their standard environment will need to adjust their scripts when they + upgrade to this release. + - The `EpicsHostArch` shell script has been replaced with a wrapper + routine that calls the Perl `EpicsHostArch.pl` script. Sites that rely on + this script to set `EPICS_HOST_ARCH` should consider switching to the + Perl script instead. + - The `Site.cshrc` and `Site.profile` files have been renamed to + `unix.csh` and `unix.sh`, respectively. + - The existing `win32.bat` file has been cleaned up and a new + `windows.bat` file added for 64-bit targets. The contents of these files + should be seen as examples, don't uncomment or install parts for software that + you don't explicitly know that you need. -
  • The Perl EpicsHostArch.pl script has been rewritten, and support -for a few previously missing host architectures has been added to it.
  • +### Recent Apple XCode Build Issues -
  • The EpicsHostArch.pl script has also been moved into the standard -src/tools directory, from where it will be installed into -lib/perl. In this new location it is no longer executable, so it must -be run by the perl executable.
  • - -
  • The build system has been adjusted to look for EpicsHostArch.pl in -both places if the EPICS_HOST_ARCH environment variable has not been -set at build-time.
  • - -
  • Sites that used the original Perl script to set EPICS_HOST_ARCH as -part of their standard environment will need to adjust their scripts when they -upgrade to this release.
  • - -
  • The EpicsHostArch shell script has been replaced with a wrapper -routine that calls the Perl EpicsHostArch.pl script. Sites that rely on -this script to set EPICS_HOST_ARCH should consider switching to the -Perl script instead.
  • - -
  • The Site.cshrc and Site.profile files have been renamed to -unix.csh and unix.sh, respectively.
  • - -
  • The existing win32.bat file has been cleaned up and a new -windows.bat file added for 64-bit targets. The contents of these files -should be seen as examples, don't uncomment or install parts for software that -you don't explicitly know that you need.
  • - -
- -

Recent Apple XCode Build Issues

- -

The latest version of XCode will not compile calls to system() or -clock_settime() for iOS targets. There were several places in Base +The latest version of XCode will not compile calls to `system()` or +`clock_settime()` for iOS targets. There were several places in Base where these were being compiled, although there were probably never called. The -code has now been modified to permit iOS builds to complete again.

+code has now been modified to permit iOS builds to complete again. -

Prevent illegal alarm severities

+### Prevent illegal alarm severities -

A check has been added to recGblResetAlarms() that prevents records -from getting an alarm severity higher than INVALID_ALARM. It is still possible +A check has been added to `recGblResetAlarms()` that prevents records +from getting an alarm severity higher than `INVALID_ALARM`. It is still possible for a field like HSV to get set to a value that is not a legal alarm severity, but the core IOC code should never copy such a value into a record's SEVR or ACKS fields. With this fix the record's alarm severity will be limited to -INVALID_ALARM.

+`INVALID_ALARM`. -

Fixes for Launchpad bugs

+### Fixes for Launchpad bugs -

The following launchpad bugs have fixes included:

+The following launchpad bugs have fixes included: - + - [lp: 1786320](https://bugs.launchpad.net/epics-base/+bug/1786320), dbCa subscribes twice to ENUM + - [lp: 541221](https://bugs.launchpad.net/epics-base/+bug/541221), 'assert (pca-\>pgetNative)' failed in ../dbCa.c + - [lp: 1747091](https://bugs.launchpad.net/epics-base/+bug/1747091), epicsTimeGetEvent() / generalTime bug + - [lp: 1743076](https://bugs.launchpad.net/epics-base/+bug/1743076), Segfault in `ca_attach_context()` during exits + - [lp: 1751380](https://bugs.launchpad.net/epics-base/+bug/1751380), Deadlock in `ca_clear_subscription()` + - [lp: 1597809](https://bugs.launchpad.net/epics-base/+bug/1597809), Setting NAME field in DB file may break IOC + - [lp: 1770292](https://bugs.launchpad.net/epics-base/+bug/1770292), `get_alarm_double()` inconsistent across record types + - [lp: 1771298](https://bugs.launchpad.net/epics-base/+bug/1771298), Conversion of NaN to integer relies on undefined + behavior -

Updated VxWorks Timezone settings

+### Updated VxWorks Timezone settings -

Removed the settings for 2017; fixed the hour of the change for MET.

+Removed the settings for 2017; fixed the hour of the change for MET. -

Fixed camonitor server side relative timestamps bug

+### Fixed camonitor server side relative timestamps bug -

Initialize the first time-stamp from the first monitor, not the client-side -current time in this configuration.

+Initialize the first time-stamp from the first monitor, not the client-side +current time in this configuration. -

Build changes for MSVC

+### Build changes for MSVC -

Windows builds using Visual Studio 2015 and later now use the -FS -compiler option to allow parallel builds to work properly.

+Windows builds using Visual Studio 2015 and later now use the `-FS` +compiler option to allow parallel builds to work properly. -

We now give the -FC option to tell the compiler to print absolute -paths for source files in diagnostic messages.

+We now give the `-FC` option to tell the compiler to print absolute +paths for source files in diagnostic messages. -

Extend maximum Posix epicsEventWaitWithTimeout() delay

+### Extend maximum Posix epicsEventWaitWithTimeout() delay -

The Posix implementation of epicsEventWaitWithTimeout() was limiting the +The Posix implementation of epicsEventWaitWithTimeout() was limiting the timeout delay to at most 60 minutes (3600.0 seconds). This has been changed to 10 years; significantly longer maximum delays cause problems on systems where -time_t is still a signed 32-bit integer so cannot represent absolute +`time_t` is still a signed 32-bit integer so cannot represent absolute time-stamps after 2038-01-19. Our assumption is that such 32-bit systems will have been retired before the year 2028, but some additional tests have been added to the epicsTimeTest program to detect and fail if this assumption is -violated.

+violated. -

New test-related make targets

+### New test-related make targets -

This release adds several new make targets intended for use by developers +This release adds several new make targets intended for use by developers and Continuous Integration systems which simplify the task of running the built-in self-test programs and viewing the results. Since these targets are intended for limited use they can have requirements for the build host which -go beyond the standard minimum set needed to build and run Base.

+go beyond the standard minimum set needed to build and run Base. -
+#### `test-results` — Summarize test results -

test-results — Summarize test results

- -

The new make target test-results will run the self-tests if +The new make target `test-results` will run the self-tests if necessary to generate a TAP file for each test, then summarizes the TAP output files in each test directory in turn, displaying the details of any failures. -This step uses the program prove which comes with Perl, but also needs -cat to be provided in the default search path so will not work on most -Windows systems.

+This step uses the program “prove” which comes with Perl, but also needs +“cat” to be provided in the default search path so will not work on most +Windows systems. -

junitfiles — Convert test results to JUnit XML Format

+#### `junitfiles` — Convert test results to JUnit XML Format -

The new make target junitfiles will run the self-tests if necessary +The new make target `junitfiles` will run the self-tests if necessary and then convert the TAP output files into the more commonly-supported JUnit XML format. The program that performs this conversion needs the Perl module -XML::Generator to have been installed.

+“`XML::Generator`” to have been installed. -

clean-tests — Delete test result files

+#### `clean-tests` — Delete test result files -

The new make target clean-tests removes any test result files from -previous test runs. It cleans both TAP and JUnit XML files.

+The new make target `clean-tests` removes any test result files from +previous test runs. It cleans both TAP and JUnit XML files. -
+### Fix DNS related crash on exit -

Fix DNS related crash on exit

- -

The attempt to fix DNS related delays for short lived CLI programs (eg. caget) +The attempt to fix DNS related delays for short lived CLI programs (eg. caget) in lp:1527636 introduced a bug which cased these short lived clients to crash on exit. -This bug should now be fixed.

+This bug should now be fixed. -

Server bind issue on Windows

+### Server bind issue on Windows -

When a National Instruments network variables CA server is already running on +When a National Instruments network variables CA server is already running on a Windows system and an IOC or PCAS server is started, the IOC's attempt to bind a TCP socket to the CA server port number fails, but Windows returns a different error status value than the IOC is expecting in that circumstance (because the National Instruments code requests exclusive use of that port, unlike the EPICS code) so the IOC fails to start properly. The relevent EPICS bind() checks have now been updated so the IOC will request that a dynamic port -number be allocated for this TCP socket instead when this happens.

+number be allocated for this TCP socket instead when this happens. -

Checking Periodic Scan Rates

+### Checking Periodic Scan Rates -

Code has been added to the IOC startup to better protect it against bad -periodic scan rates, including against locales where . is not +Code has been added to the IOC startup to better protect it against bad +periodic scan rates, including against locales where `.` is not accepted as a decimal separator character. If the scan period in a menuScan choice string cannot be parsed, the associated periodic scan thread will no longer be started by the IOC and a warning message will be displayed at iocInit -time. The scanppl command will also flag the faulty menuScan value.

+time. The `scanppl` command will also flag the faulty menuScan value. +## Changes made between 3.15.4 and 3.15.5 -

Changes made between 3.15.4 and 3.15.5

+### dbStatic Library Speedup and Cleanup -

dbStatic Library Speedup and Cleanup

- -

Loading of database files has been optimized to avoid overproportionally +Loading of database files has been optimized to avoid over-proportionally long loading times for large databases. As a part of this, the alphabetical ordering of records instances (within a record type) has been dropped. In the unexpected case that applications were relying on the alphabetic order, setting -dbRecordsAbcSorted = 1 before loading the databases will retain the -old behavior.

+`dbRecordsAbcSorted = 1` before loading the databases will retain the +old behavior. -

The routine dbRenameRecord() has been removed, as it was intended +The routine `dbRenameRecord()` has been removed, as it was intended to be used by database configuration tools linked against a host side version -of the dbStatic library that is not being built anymore.

+of the dbStatic library that is not being built anymore. -

Launchpad Bug-fixes

+### Launchpad Bug-fixes -

In addition to the more detailed change descriptions below, the following -Launchpad bugs have also been fixed in this release:

+In addition to the more detailed change descriptions below, the following +Launchpad bugs have also been fixed in this release: -
    -
  • - #1440186 Crash due to a too small buffer being provided in - dbContextReadNotifyCache
  • -
  • - #1479316 Some data races found using Helgrind
  • -
  • - #1495833 biRecord prompt groups are nonsensical
  • -
  • - #1606848 WSAIoctl SIO_GET_INTERFACE_LIST failed in Windows
  • -
+ - [lp:1440186](https://bugs.launchpad.net/epics-base/+bug/1440186) Crash due to a too small buffer being provided in + dbContextReadNotifyCache + - [lp:1479316](https://bugs.launchpad.net/epics-base/+bug/1479316) Some data races found using Helgrind + - [lp:1495833](https://bugs.launchpad.net/epics-base/+bug/1495833) biRecord prompt groups are nonsensical + - [lp:1606848](https://bugs.launchpad.net/epics-base/+bug/1606848) WSAIoctl `SIO_GET_INTERFACE_LIST` failed in Windows -

Whole-Program Optimization for MS Visual Studio Targets

+### Whole-Program Optimization for MS Visual Studio Targets -

When using the Microsoft compilers a new build system variable is provided +When using the Microsoft compilers a new build system variable is provided that controls whether whole program optimization is used or not. For static builds using Visual Studio 2010 this optimization must be disabled. This is -controlled in the files configure/os/CONFIG_SITE.Common.windows-x64-static and -configure/os/CONFIG_SITE.Common.win32-x86-static by setting the variable -OPT_WHOLE_PROGRAM = NO to override the default value -YES that would otherwise be used.

+controlled in the files `configure/os/CONFIG_SITE.Common.windows-x64-static` and +`configure/os/CONFIG_SITE.Common.win32-x86-static` by setting the variable +`OPT_WHOLE_PROGRAM = NO` to override the default value +`YES` that would otherwise be used. -

Note that enabling this optimization slows down the build process. It is not +Note that enabling this optimization slows down the build process. It is not possible to selectively disable this optimization, when building a particular module say; Microsoft's linker will restart itself automatically with the --LTCG flag set and display a warning if it is asked to link any object -files that were compiled with the -GL flag.

+`-LTCG` flag set and display a warning if it is asked to link any object +files that were compiled with the `-GL` flag. -

Add dynamic (variable length) array support to PCAS

+### Add dynamic (variable length) array support to PCAS -

Dynamic array sizing support was added to the IOC server (RSRV) in the -Base-3.14.12 release, but has not until now been supported in the Portable -Channel Access Server (PCAS). Channel Access server applications using the +Dynamic array sizing support was added to the IOC server (RSRV) in the +Base-3.14.12 release, but has not until now been supported in the “Portable +Channel Access Server” (PCAS). Channel Access server applications using the PCAS may not need to be modified at all; if they already push monitors with different gdd array lengths, those variable sizes will be forwarded to any CA clients who have requested variable length updates. The example CAS server -application has been modified to demonstrate this feature.

+application has been modified to demonstrate this feature. -

In implementing the above, the gdd method gdd::put(const gdd *) now +In implementing the above, the gdd method `gdd::put(const gdd *)` now copies the full-sized array from the source gdd if the destination gdd is of -type array, has no allocated memory and a boundary size of 0.

+type array, has no allocated memory and a boundary size of 0. -

Additional epicsTime conversion

+### Additional epicsTime conversion -

The EPICS timestamp library (epicsTime) inside libCom's OSI layer has -been extended by routines that convert from struct tm to the EPICS -internal epicsTime type, assuming UTC - i.e. without going through +The EPICS timestamp library (epicsTime) inside libCom's OSI layer has +been extended by routines that convert from `struct tm` to the EPICS +internal `epicsTime` type, assuming UTC - i.e. without going through the timezone mechanism. This solves issues with converting from the structured type to the EPICS timestamp at driver level from multiple threads at a high -repetition rate, where the timezone mechanism was blocking on file access.

+repetition rate, where the timezone mechanism was blocking on file access. -

MinGW Cross-builds from Linux

+### MinGW Cross-builds from Linux -

The build configuration files that allow cross-building of the 32-bit +The build configuration files that allow cross-building of the 32-bit win32-x86-mingw cross-target have been adjusted to default to building shared libraries (DLLs) as this is now supported by recent MinGW compilers. The 64-bit windows-x64-mingw cross-target was already being built that way by default. The configuration options to tell the minGW cross-compiler to link programs with static versions of the compiler support libraries have now been moved into the -CONFIG_SITE.linux-x86.target files.

+`CONFIG_SITE.linux-x86.` files. -

General Time updates

+### General Time updates -

The iocInit code now performs a sanity check of the current time +The `iocInit` code now performs a sanity check of the current time returned by the generalTime subsystem and will print a warning if the wall-clock time returned has not been initialized yet. This is just a warning message; when a time provider does synchonize the IOC will subsequently pick up and use the correct time. This check code also primes the registered event system provider -if there is one so the epicsTimeGetEventInt() routine will work on IOCs -that ask for event time within an interrupt service routine.

+if there is one so the `epicsTimeGetEventInt()` routine will work on IOCs +that ask for event time within an interrupt service routine. -

The osiClockTime provider's synchronization thread (which is only used on +The osiClockTime provider's synchronization thread (which is only used on some embedded targets) will now poll the other time providers at 1Hz until the first time it manages to get a successful timestamp, after which it will poll -for updates every 60 seconds as before.

+for updates every 60 seconds as before. -

The routine generalTimeGetExceptPriority() was designed for use by +The routine `generalTimeGetExceptPriority()` was designed for use by backup (lower priority) time providers like the osiClockTime provider which do not have their own absolute time reference and rely on other providers for an absolute time source. This routine no longer implements the ratchet mechanism that prevented the time it returned from going backwards. If the backup clock's tick-timer runs fast the synchronization of the backup time provider would never allow it to be corrected backwards when the ratchet was in place. The regular -epicsTimeGetCurrent() API still uses the ratchet mechanism, so this -change will not cause the IOC to see time going backwards.

+`epicsTimeGetCurrent()` API still uses the ratchet mechanism, so this +change will not cause the IOC to see time going backwards. -

Microsoft Visual Studio builds

+### Microsoft Visual Studio builds -

The build configuration files for builds using the Microsoft compilers have +The build configuration files for builds using the Microsoft compilers have been updated, although there should be no noticable difference at most sites. -One extra compiler warning is now being suppressed for C++ code, C4344: -behavior change: use of explicit template arguments results in ... which is -gratuitous and was appearing frequently in builds of the EPICS V4 modules.

+One extra compiler warning is now being suppressed for C++ code, `C4344: behavior change: use of explicit template arguments results in ...` which is +gratuitous and was appearing frequently in builds of the EPICS V4 modules. -

Cross-builds of the windows-x64 target from a win32-x86 host have been -removed as they don't actually work within the context of a single make +Cross-builds of the windows-x64 target from a win32-x86 host have been +removed as they don't actually work within the context of a single `make` run. Significant changes to the build configuration files would be necessary for these kinds of cross-builds to work properly, which could be done if someone needs them (email Andrew Johnson before working on this, and see - -this stack-overflow answer for a starting point).

+[this stack-overflow answer](http://stackoverflow.com/questions/5807647/how-do-you-compile-32-bit-and-64-bit-applications-at-the-same-time-in-visual-stu) for a starting point). -

Bazaar keywords such as 'Revision-Id' removed

+### Bazaar keywords such as 'Revision-Id' removed -

In preparation for moving to git in place of the Bazaar revision control -system we have removed all the keywords from the Base source code.

+In preparation for moving to git in place of the Bazaar revision control +system we have removed all the keywords from the Base source code. -

Linux systemd service file for CA Repeater

+### Linux systemd service file for CA Repeater -

Building this version of Base on a Linux system creates a systemd service +Building this version of Base on a Linux system creates a systemd service file suitable for starting the Channel Access Repeater under systemd. The file will be installed into the target bin directory, from where it can be copied into the appropriate systemd location and modified as necessary. Installation -instructions are included as comments in the file.

+instructions are included as comments in the file. +## Changes made between 3.15.3 and 3.15.4 -

Changes made between 3.15.3 and 3.15.4

+### New string input device support "getenv" -

New string input device support "getenv"

- -

A new "getenv" device support for both the stringin and lsi (long string +A new "getenv" device support for both the stringin and lsi (long string input) record types can be used to read the value of an environment variable -from the IOC at runtime. See base/db/softIocExit.db for sample usage.

+from the IOC at runtime. See base/db/softIocExit.db for sample usage. -

Build rules and DELAY_INSTALL_LIBS

+### Build rules and `DELAY_INSTALL_LIBS` -

A new order-only prerequisite build rule has been added to ensure that +A new order-only prerequisite build rule has been added to ensure that library files (and DLL stubs on Windows) get installed before linking any executables, which resolves parallel build problems on high-powered CPUs. There are some (rare) cases though where a Makefile has to build an executable and run it to be able to compile code for a library built by the same Makefile. With this new build rule GNUmake will complain about a circular dependency and the build will probably fail in those cases. To avoid this problem the failing -Makefile should set DELAY_INSTALL_LIBS = YES before including the -$(TOP)/configure/RULES file, disabling the new build rule.

+Makefile should set `DELAY_INSTALL_LIBS = YES` before including the +`$(TOP)/configure/RULES` file, disabling the new build rule. -

IOC environment variables and build parameters

+### IOC environment variables and build parameters -

The IOC now sets a number of environment variables at startup that provide -the version of EPICS Base it was built against (EPICS_VERSION_...) and its build +The IOC now sets a number of environment variables at startup that provide +the version of EPICS Base it was built against (`EPICS_VERSION_...`) and its build architecture (ARCH). In some cases this allows a single iocBoot/ioc directory to be used to run the same IOC on several different architectures without any -changes.

+changes. -

There are also 3 new environment parameters (EPICS_BUILD_...) available that +There are also 3 new environment parameters (`EPICS_BUILD_...`) available that C/C++ code can use to find out the target architecture, OS class and compiler class it was built with. These may be useful when writing interfaces to other -languages.

+languages. -

New implementation of promptgroup/gui_group field property

+### New implementation of promptgroup/gui\_group field property -

The mechanism behind the "promptgroup()" field property inside a record type +The mechanism behind the `promptgroup()` field property inside a record type definition has been changed. Instead of using a fixed set of choices, the static database access library now collects the used gui group names while parsing DBD information. Group names should start with a two-digit number -plus space-dash-space to allow proper sorting of groups.

+plus space-dash-space to allow proper sorting of groups. -

The include file guigroup.h that defined the fixed set of choices +The include file `guigroup.h` that defined the fixed set of choices has been deprecated. Instead, use the conversion functions between index number -and group string that have been added to dbStaticLib.

+and group string that have been added to dbStaticLib. -

When a DBD file containing record-type descriptions is expanded, any -old-style GUI_xxx group names will be replaced by a new-style +When a DBD file containing record-type descriptions is expanded, any +old-style `GUI_xxx` group names will be replaced by a new-style string for use by the IOC. This permits an older record type to be used with the 3.15.4 release, although eventually record types should be converted by -hand with better group names used.

+hand with better group names used. -

CA server configuration changes

+### CA server configuration changes -

RSRV now honors EPICS_CAS_INTF_ADDR_LIST and binds only to the provided list +RSRV now honors `EPICS_CAS_INTF_ADDR_LIST` and binds only to the provided list of network interfaces. Name searches (UDP and TCP) on other network interfaces are ignored. For example on a computer with interfaces 10.5.1.1/24, 10.5.2.1/24, -and 10.5.3.1/24, setting "EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'" will -accept traffic on the .1.1 and .2.1, but ignore from .3.1

+and 10.5.3.1/24, setting `EPICS_CAS_INTF_ADDR_LIST='10.5.1.1 10.5.2.1'` will +accept traffic on the .1.1 and .2.1, but ignore from .3.1 -

RSRV now honors EPICS_CAS_IGNORE_ADDR_LIST and ignores UDP messages received -from addresses in this list.

+RSRV now honors `EPICS_CAS_IGNORE_ADDR_LIST` and ignores UDP messages received +from addresses in this list. -

Previously, CA servers (RSRV and PCAS) would build the beacon address list -using EPICS_CA_ADDR_LIST if EPICS_CAS_BEACON_ADDR_LIST was no set. This is no -longer done. Sites depending on this should set both envronment variables to the -same value.

+Previously, CA servers (RSRV and PCAS) would build the beacon address list +using `EPICS_CA_ADDR_LIST` if `EPICS_CAS_BEACON_ADDR_LIST` was no set. This is no +longer done. Sites depending on this should set both environment variables to the +same value. -

IPv4 multicast for name search and beacons

+### IPv4 multicast for name search and beacons -

libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name +libca, RSRV, and PCAS may now use IPv4 multicasting for UDP traffic (name search and beacons). This is disabled by default. To enable multicast address(s) -must be listed in EPICS_CA_ADDR_LIST for clients and EPICS_CAS_INTF_ADDR_LIST +must be listed in `EPICS_CA_ADDR_LIST` for clients and `EPICS_CAS_INTF_ADDR_LIST` for servers (IOCs should set both). For example: -"EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9".

+`EPICS_CAS_INTF_ADDR_LIST='224.0.2.9' EPICS_CA_ADDR_LIST=224.0.2.9` -

Please note that no IPv4 multicast address is officially assigned for Channel -Access by IANA. The example 224.0.2.9 is taken from the AD-HOC Block I range.

+Please note that no IPv4 multicast address is officially assigned for Channel +Access by IANA. The example 224.0.2.9 is taken from the AD-HOC Block I range. -

Moved mlockall() into its own epicsThread routine

+### Moved `mlockall()` into its own epicsThread routine -

Since EPICS Base 3.15.0.2 on Posix OSs the initialization of the epicsThread -subsystem has called mlockall() when the OS supports it and thread +Since EPICS Base 3.15.0.2 on Posix OSs the initialization of the epicsThread +subsystem has called `mlockall()` when the OS supports it and thread priority scheduling is enabled. Doing so has caused problems in third-party applications that call the CA client library, so the functionality has been -moved to a separate routine epicsThreadRealtimeLock() which will be +moved to a separate routine `epicsThreadRealtimeLock()` which will be called by the IOC at iocInit (unless disabled by setting the global variable -dbThreadRealtimeLock to zero).

+`dbThreadRealtimeLock` to zero). -

Added dbQuietMacroWarnings control

+### Added dbQuietMacroWarnings control -

When loading database files, macros get expanded even on comment lines. If a +When loading database files, macros get expanded even on comment lines. If a comment contains an undefined macro, the load still continues but an error message gets printed. For this release the error message has been changed to a warning, but even this warning can be made less verbose by setting this new -variable to a non-zero value before loading the file, like this:

+variable to a non-zero value before loading the file, like this: -
-var dbQuietMacroWarnings 1      iocsh
-dbQuietMacroWarnings=1          VxWorks
-
+``` + var dbQuietMacroWarnings 1 iocsh + dbQuietMacroWarnings=1 VxWorks +``` -

This was Launchpad bug -541119.

+This was [Launchpad bug +541119](https://bugs.launchpad.net/bugs/541119). +## Changes from the 3.14 branch between 3.15.3 and 3.15.4 -

Changes from the 3.14 branch between 3.15.3 and 3.15.4

+### NTP Time Provider adjusts to OS tick rate changes -

NTP Time Provider adjusts to OS tick rate changes

- -

Dirk Zimoch provided code that allows the NTP Time provider (used on VxWorks +Dirk Zimoch provided code that allows the NTP Time provider (used on VxWorks and RTEMS only) to adapt to changes in the OS clock tick rate after the provider has been initialized. Note that changing the tick rate after iocInit() is not advisable, and that other software might still misbehave if initialized before -an OS tick rate change. This change was back-ported from the 3.15 branch.

+an OS tick rate change. This change was back-ported from the 3.15 branch. -

Making IOC ca_get operations atomic

+### Making IOC `ca_get` operations atomic -

When a CA client gets data from an IOC record using a compound data type such -as DBR_TIME_DOUBLE the value field is fetched from the database in a +When a CA client gets data from an IOC record using a compound data type such +as `DBR_TIME_DOUBLE` the value field is fetched from the database in a separate call than the other metadata, without keeping the record locked. This allows some other thread such as a periodic scan thread a chance to interrupt the get operation and process the record in between. CA monitors have always been atomic as long as the value data isn't a string or an array, but this race condition in the CA get path has now been fixed so the record will stay locked -between the two fetch operations.

+between the two fetch operations. -

This fixes -Launchpad bug #1581212, thanks to Till Strauman and Dehong Zhang.

+This fixes +[Launchpad bug 1581212](https://bugs.launchpad.net/epics-base/+bug/1581212), +thanks to Till Strauman and Dehong Zhang. -

New CONFIG_SITE variable for running self-tests

+### New `CONFIG_SITE` variable for running self-tests -

The 'make runtests' and 'make tapfiles' build targets normally only run the -self-tests for the main EPICS_HOST_ARCH architecture. If the host is +The 'make runtests' and 'make tapfiles' build targets normally only run the +self-tests for the main `EPICS_HOST_ARCH` architecture. If the host is able to execute self-test programs for other target architectures that are being -built by the host, such as when building a -debug version of the host +built by the host, such as when building a `-debug` version of the host architecture for example, the names of those other architectures can be added to -the new CROSS_COMPILER_RUNTEST_ARCHS variable in either the -configure/CONFIG_SITE file or in an appropriate -configure/os/CONFIG_SITE.<host>.Common file to have the test -programs for those targets be run as well.

+the new `CROSS_COMPILER_RUNTEST_ARCHS` variable in either the +`configure/CONFIG_SITE` file or in an appropriate +`configure/os/CONFIG_SITE..Common` file to have the test +programs for those targets be run as well. -

Additional RELEASE file checks

+### Additional RELEASE file checks -

An additional check has been added at build-time for the contents of the -configure/RELEASE file(s), which will mostly only affect users of the Debian +An additional check has been added at build-time for the contents of the +`configure/RELEASE` file(s), which will mostly only affect users of the Debian EPICS packages published by NSLS-2. Support modules may share an install path, -but all such modules must be listed adjacent to each other in any RELEASE files -that point to them. For example the following will fail the new checks:

+but all such modules must be listed adjacent to each other in any `RELEASE` files +that point to them. For example the following will fail the new checks: -
-AUTOSAVE = /usr/lib/epics
-ASYN = /home/mdavidsaver/asyn
-EPICS_BASE = /usr/lib/epics
-
+``` + AUTOSAVE = /usr/lib/epics + ASYN = /home/mdavidsaver/asyn + EPICS_BASE = /usr/lib/epics +``` -

giving the compile-time error

+giving the compile-time error -
-This application's RELEASE file(s) define
-	EPICS_BASE = /usr/lib/epics
-after but not adjacent to
-	AUTOSAVE = /usr/lib/epics
-Module definitions that share paths must be grouped together.
-Either remove a definition, or move it to a line immediately
-above or below the other(s).
-Any non-module definitions belong in configure/CONFIG_SITE.
-
+``` + This application's RELEASE file(s) define + EPICS_BASE = /usr/lib/epics + after but not adjacent to + AUTOSAVE = /usr/lib/epics + Module definitions that share paths must be grouped together. + Either remove a definition, or move it to a line immediately + above or below the other(s). + Any non-module definitions belong in configure/CONFIG_SITE. +``` - -

In many cases such as the one above the order of the AUTOSAVE and -ASYN lines can be swapped to let the checks pass, but if the -AUTOSAVE module depended on ASYN and hence had to appear -before it in the list this error indicates that AUTOSAVE should also be +In many cases such as the one above the order of the `AUTOSAVE` and +`ASYN` lines can be swapped to let the checks pass, but if the +`AUTOSAVE` module depended on `ASYN` and hence had to appear +before it in the list this error indicates that `AUTOSAVE` should also be built in its own private area; a shared copy would likely be incompatible with -the version of ASYN built in the home directory.

+the version of `ASYN` built in the home directory. -

String field buffer overflows

+### String field buffer overflows -

Two buffer overflow bugs that can crash the IOC have been fixed, caused by +Two buffer overflow bugs that can crash the IOC have been fixed, caused by initializing a string field with a value larger than the field size -(Launchpad bug -#1563191).

+([Launchpad bug 1563191](https://bugs.launchpad.net/bugs/1563191)). -

Fixed stack corruption bug in epicsThread C++ API

+### Fixed stack corruption bug in epicsThread C++ API -

The C++ interface to the epicsThread API could corrupt the stack on thread +The C++ interface to the epicsThread API could corrupt the stack on thread exit in some rare circumstances, usually at program exit. This bug has been -fixed (Launchpad bug -#1558206).

+fixed ([Launchpad bug 1558206](https://bugs.launchpad.net/bugs/1558206)). -

RTEMS NTP Support Issue

+### RTEMS NTP Support Issue -

On RTEMS the NTP Time Provider could in some circumstances get out of sync -with the server because the osdNTPGet() code wasn't clearing its input socket +On RTEMS the NTP Time Provider could in some circumstances get out of sync +with the server because the `osdNTPGet()` code wasn't clearing its input socket before sending out a new request. This -(Launchpad bug 1549908) -has now been fixed.

+([Launchpad bug 1549908](https://bugs.launchpad.net/bugs/1549908)) +has now been fixed. -

CALC engine bitwise operator fixes

+### CALC engine bitwise operator fixes -

The bitwise operators in the CALC engine have been modified to work properly +The bitwise operators in the CALC engine have been modified to work properly with values that have bit 31 (0x80000000) set. This modification involved back-porting some earlier changes from the 3.15 branch, and fixes -Launchpad bug -#1514520.

+[Launchpad bug 1514520](https://code.launchpad.net/bugs/1514520). -

Fix ipAddrToAsciiAsync(): Don't try to join the daemon thread

+### Fix `ipAddrToAsciiAsync()`: Don't try to join the daemon thread -

On process exit, don't try to stop the worker thread that makes DNS lookups +On process exit, don't try to stop the worker thread that makes DNS lookups asynchronous. Previously this would wait for any lookups still in progress, delaying the exit unnecessarily. This was most obvious with catools (eg. cainfo). -lp:1527636

+[lp:1527636](https://bugs.launchpad.net/bugs/1527636) -

Fix epicsTime_localtime() on Windows

+### Fix `epicsTime_localtime()` on Windows -

Simpler versions of the epicsTime_gmtime() and epicsTime_localtime() +Simpler versions of the `epicsTime_gmtime()` and `epicsTime_localtime()` routines have been included in the Windows implementations, and a new test program added. The original versions do not report DST status properly. Fixes -Launchpad bug 1528284.

+[Launchpad bug 1528284](https://bugs.launchpad.net/bugs/1528284). +## Changes made between 3.15.2 and 3.15.3 -

Changes made between 3.15.2 and 3.15.3

+### Make the NTP Time provider optional on VxWorks -

Make the NTP Time provider optional on VxWorks

- -

Recent versions of VxWorks (sometime after VxWorks 6) provide facilities for +Recent versions of VxWorks (sometime after VxWorks 6) provide facilities for automatically synchronizing the OS clock time with an NTP server. The EPICS time system used to assume that it had to provide time synchronization on VxWorks, but now it tests for the existance of either of the two OS synchronization threads before starting the NTP time provider. It is still possible to force the NTP provider to be started even if the OS synchronization is running by defining -the environment variable EPICS_TS_FORCE_NTPTIME in the startup script -before loading the IOC's .munch file. Forcing may be necessary if the VxWorks -image is not correctly configured with the IP address of a local NTP server.

+the environment variable `EPICS_TS_FORCE_NTPTIME` in the startup script +before loading the IOC's `.munch` file. Forcing may be necessary if the VxWorks +image is not correctly configured with the IP address of a local NTP server. -

Assembling files from numbered snippets

+### Assembling files from numbered snippets -

A tool has been added that assembles file snippets specified on the +A tool has been added that assembles file snippets specified on the command line into a single output file, with sorting and replacing/adding of snippets done based on their file names. The build system integration requires -the output file to be specified setting COMMON_ASSEMBLIES (arch independent) -or ASSEMBLIES (created by arch), then defining the snippets for each assembly -setting *_SNIPPETS (explicitly) or *_PATTERN (searched relative to all source +the output file to be specified setting `COMMON_ASSEMBLIES` (arch independent) +or `ASSEMBLIES` (created by arch), then defining the snippets for each assembly +setting `*_SNIPPETS` (explicitly) or `*_PATTERN` (searched relative to all source directories). -

-

Clean up after GNU readline()

+### Clean up after GNU readline() -

If EPICS Base is built with readline support, any IOC that calls epicsExit() +If EPICS Base is built with readline support, any IOC that calls epicsExit() from a thread other than the main thread is likely to leave the user's terminal in a weird state, requiring the user to run something like 'stty sane' to clean it up. This release patches the readline support code to clean up automatically -by registering an epicsAtExit() routine.

+by registering an epicsAtExit() routine. -

Removed the last vestiges of RSET::get_value()

+### Removed the last vestiges of `RSET::get_value()` -

The IOC has not called the get_value() routine in the RSET for a very long +The IOC has not called the `get_value()` routine in the RSET for a very long time, but there was still one implementation left in the event record support code, and a structure definition for one of the original arguments to that -routine was defined in recGbl.h. Both of these have now been removed.

+routine was defined in recGbl.h. Both of these have now been removed. +## Changes made between 3.15.1 and 3.15.2 -

Changes made between 3.15.1 and 3.15.2

+### Raised limit on link field length in database files -

Raised limit on link field length in database files

- -

The length of INP/OUT link fields in database files was limited to 79 chars +The length of INP/OUT link fields in database files was limited to 79 chars by an internal buffer size in the db file parser. This limitation will go away completely in 3.16, and has been statically raised to 255 chars for the 3.15 -series.

+series. -

aoRecord raw conversion overflows

+### aoRecord raw conversion overflows -

The ao record type now checks converted raw values and limits them to the +The ao record type now checks converted raw values and limits them to the 32-bit integer range before writing them to the RVAL field. Previously value overflows relied on Undefined Behaviour which could give different results on different platforms. The ROFF fields of the ao and ai record types are now -DBF_ULONG to allow an ROFF setting of 0x80000000 to work properly.

+`DBF_ULONG` to allow an ROFF setting of 0x80000000 to work properly. -

Changes to <top>/cfg/* files

+### Changes to `/cfg/*` files -

The order in which cfg/CONFIG* and cfg/RULES* files are included from support -applications listed in the configure/RELEASE* files has been changed. Previously +The order in which `cfg/CONFIG*` and `cfg/RULES*` files are included from support +applications listed in the `configure/RELEASE*` files has been changed. Previously these files were included in the order in which the top areas are listed in the RELEASE file, but it makes more sense to load them in reverse order since later entries override earlier ones in Makefiles but the release file order is supposed to allow earlier entries to take precedence over later ones. The same -change has been made to the inclusion of the <top>/configure/RULES_BUILD -files.

+change has been made to the inclusion of the `/configure/RULES_BUILD` +files. -

Two new file types can also be provided in a module's cfg directory. Files -named TOP_RULES* will be included by the top-level Makefile of other modules -that refer to this module; files name DIR_RULES* will be included by all -Makefiles that merely descend into lower-level directories. The cfg/RULES* files -are only included when make is building code inside the O.<arch> -directories.

+Two new file types can also be provided in a module's `cfg` directory. Files +named `TOP_RULES*` will be included by the top-level Makefile of other modules +that refer to this module; files name `DIR_RULES*` will be included by all +Makefiles that merely descend into lower-level directories. The `cfg/RULES*` files +are only included when make is building code inside the `O.` directories. -

The new cfg/DIR_RULES* file inclusion was designed to permit new recursive +The new `cfg/DIR_RULES*` file inclusion was designed to permit new recursive make actions to be implemented by appending the name of the new action to the -ACTIONS variable. There must be a matching rule in one of the cfg/RULES* files -when doing this. Similar rules may also be defined in the cfg/TOP_RULES* and/or -cfg/DIR_RULES* files, but these should only state prerequisites and not directly -provide commands to be executed.

+`ACTIONS` variable. There must be a matching rule in one of the `cfg/RULES*` files +when doing this. Similar rules may also be defined in the `cfg/TOP_RULES*` and/or +`cfg/DIR_RULES*` files, but these should only state prerequisites and not directly +provide commands to be executed. -

Build rules for RTEMS GESYS modules

+### Build rules for RTEMS GESYS modules -

RTEMS target builds can now be configured to make GESYS modules by changing -the USE_GESYS=NO setting in the file -configure/os/CONFIG_SITE.Common.RTEMS to YES.

+RTEMS target builds can now be configured to make GESYS modules by changing +the `USE_GESYS=NO` setting in the file +`configure/os/CONFIG_SITE.Common.RTEMS` to `YES`. -

Added Make variables for command-line use

+### Added Make variables for command-line use -

The following variables are now used during the build process, reserved for +The following variables are now used during the build process, reserved for setting on the command-line only (Makefiles should continue to use the -USR_ equivalents):

+`USR_` equivalents): -
    -
  • CMD_INCLUDES
  • -
  • CMD_CPPFLAGS
  • -
  • CMD_CFLAGS
  • -
  • CMD_CXXFLAGS
  • -
  • CMD_LDFLAGS
  • -
  • CMD_DBFLAGS
  • -
  • CMD_DBDFLAGS
  • -
  • CMD_REGRDDFLAGS
  • -
  • CMD_ARFLAGS
  • -
+ - `CMD_INCLUDES` + - `CMD_CPPFLAGS` + - `CMD_CFLAGS` + - `CMD_CXXFLAGS` + - `CMD_LDFLAGS` + - `CMD_DBFLAGS` + - `CMD_DBDFLAGS` + - `CMD_REGRDDFLAGS` + - `CMD_ARFLAGS` -

For example:

+For example: -
-make CMD_INCLUDES=/opt/local/include CMD_LDFLAGS=-L/opt/local/lib
-
+``` + make CMD_INCLUDES=/opt/local/include CMD_LDFLAGS=-L/opt/local/lib +``` -

Enhanced API for asTrapWrite listeners

+### Enhanced API for asTrapWrite listeners -

External software such as the CA Put Logging module that registers a listener +External software such as the CA Put Logging module that registers a listener with the asTrapWrite subsystem was not previously given access to the actual data being sent by the CA client. In most cases this was not a problem as the listener can look at the field being modified both before and after the operation, but if the put processes the record which immediately overwrites the -new value, the client's value cannot be observed.

+new value, the client's value cannot be observed. -

This release adds three fields to the asTrapWriteMessage structure that is +This release adds three fields to the asTrapWriteMessage structure that is passed to the listener routines. These new fields provide the CA data type, the number of array elements, and a pointer to the source data buffer. This change is completely backwards compatible with listener code written against the -original API. The new API can be detected at compile-time as follows:

+original API. The new API can be detected at compile-time as follows: -
-#include "asLib.h"
+```
+    #include "asLib.h"
 
-/* ... */
+    /* ... */
 
-#ifdef asTrapWriteWithData
-    /* Enhanced API */
-#endif
-
+ #ifdef asTrapWriteWithData + /* Enhanced API */ + #endif +``` -

Use of PATH_FILTER in Makefiles deprecated

+### Use of `PATH_FILTER` in Makefiles deprecated -

The PATH_FILTER variable was being called to convert forward shashes -/ in file paths into pairs of backward slashes -\\ on Windows architectures. This has never been strictly +The `PATH_FILTER` variable was being called to convert forward slashes +`/` in file paths into pairs of backward slashes +`\\` on Windows architectures. This has never been strictly necessary, and was added about 10 years ago to get around some short-comings in -Windows tools at the time. All uses of PATH_FILTER in Base have now been +Windows tools at the time. All uses of `PATH_FILTER` in Base have now been removed; the definition is still present, but will result in a warning being -printed if it is ever used.

+printed if it is ever used. -

Using msi for dependencies

+### Using msi for dependencies -

To reduce confusion the msi program has been modified to allow the generation -of dependency rules by adding support for a -D option, and changing the +To reduce confusion the msi program has been modified to allow the generation +of dependency rules by adding support for a `-D` option, and changing the commands in RULES.Db to use this option instead of the mkmf.pl script. The new build rules will not work with old versions of the msi program, so the command -variable name used in the rules has been changed from MSI to MSI3_15. Sites that -use a modified version of msi must provide support for both the -D and --o outfile options, and should then point the MSI3_15 variable in -their applications' CONFIG_SITE files to that updated executable.

+variable name used in the rules has been changed from `MSI` to `MSI3_15`. Sites that +use a modified version of msi must provide support for both the `-D` and +`-o outfile` options, and should then point the `MSI3_15` variable in +their applications' `CONFIG_SITE` files to that updated executable. +## Changes made between 3.15.0.2 and 3.15.1 -

Changes made between 3.15.0.2 and 3.15.1

+### `epicsStrnEscapedFromRaw()` and `epicsStrnRawFromEscaped()` -

epicsStrnEscapedFromRaw() and epicsStrnRawFromEscaped()

+These routines have been rewritten; the previous implementations did not +always behave exactly as specified. -

These routines have been rewritten; the previous implementations did not -always behave exactly as specified.

+### Shared Library Versions -

Shared Library Versions

- -

On architectures that can support it, the shared library version number for +On architectures that can support it, the shared library version number for libraries provided with Base has had the third component of the EPICS version number added to it, thus libCom.so.3.15.1 instead of libCom.so.3.15. Windows can only support two components to its internal product version number, and the Darwin bug that external shared libraries were being built using the EPICS -version number has been fixed.

+version number has been fixed. -

Hooking into dbLoadRecords

+### Hooking into dbLoadRecords -

A function pointer hook has been added to the dbLoadRecords() routine, to +A function pointer hook has been added to the dbLoadRecords() routine, to allow external modules such as autosave to be notified when new records have -been loaded during IOC initialization. The hook is called dbLoadRecordsHook and -follows the model of the recGblAlarmHook pointer in that modules that wish to +been loaded during IOC initialization. The hook is called `dbLoadRecordsHook` and +follows the model of the `recGblAlarmHook` pointer in that modules that wish to use it must save the current value of the pointer before installing their own function pointer, and must call the original function from their own -routine.

+routine. -

The hook is activiated from the dbLoadRecords() routine and gets called only +The hook is activiated from the `dbLoadRecords()` routine and gets called only after a database instance file has been read in without error. Note that the -dbLoadTemplates() routine directly calls dbLoadRecords() so this hook also +`dbLoadTemplates()` routine directly calls `dbLoadRecords()` so this hook also provides information about instantiated database templates. It is still possible -to load record instances using dbLoadDatabase() though, and doing this will not -result in the hook routines being called.

+to load record instances using `dbLoadDatabase()` though, and doing this will not +result in the hook routines being called. -

Code to use this hook should look something like this:

+Code to use this hook should look something like this: -
-#include "dbAccessDefs.h"
+```
+    #include "dbAccessDefs.h"
 
-static DB_LOAD_RECORDS_HOOK_ROUTINE previousHook;
+    static DB_LOAD_RECORDS_HOOK_ROUTINE previousHook;
 
-static void myRoutine(const char* file, const char* subs) {
-    if (previousHook)
-        previousHook(file, subs);
+    static void myRoutine(const char* file, const char* subs) {
+        if (previousHook)
+            previousHook(file, subs);
 
-    /* Do whatever ... */
-}
-
-void myInit(void) {
-    static int done = 0;
-
-    if (!done) {
-        previousHook = dbLoadRecordsHook;
-        dbLoadRecordsHook = myRoutine;
-        done = 1;
+        /* Do whatever ... */
     }
-}
-
-

As with many other parts of the static database access library there is no + void myInit(void) { + static int done = 0; + + if (!done) { + previousHook = dbLoadRecordsHook; + dbLoadRecordsHook = myRoutine; + done = 1; + } + } +``` + +As with many other parts of the static database access library there is no mutex to protect the function pointer. Initialization is expected to take place in the context of the IOC's main thread, from either a static C++ constructor or -an EPICS registrar routine.

+an EPICS registrar routine. +## Changes made between 3.15.0.1 and 3.15.0.2 -

Changes made between 3.15.0.1 and 3.15.0.2

+### New iocshLoad command -

New iocshLoad command

- -

A new command iocshLoad has been added to iocsh which executes a +A new command `iocshLoad` has been added to iocsh which executes a named iocsh script and can also set one or more shell macro variables at the same time, the values of which will be forgotten immediately after the named -script finishes executing. The following example shows the syntax:

+script finishes executing. The following example shows the syntax: -
-iocshLoad "serial.cmd", "DEV=/dev/ttyS0,PORT=com1,TYPE=RS485"
-iocshLoad "radmon.cmd", "PORT=com1,ADDR=0"
-
+``` + iocshLoad "serial.cmd", "DEV=/dev/ttyS0,PORT=com1,TYPE=RS485" + iocshLoad "radmon.cmd", "PORT=com1,ADDR=0" +``` -

Support routines for 64-bit integers

+### Support routines for 64-bit integers -

The libCom library now provides support for 64-bit integer types on all +The libCom library now provides support for 64-bit integer types on all supported architectures. The epicsTypes.h header file defines epicsInt64 and epicsUInt64 type definitions for both C and C++ code. The epicsStdlib.h header also declares the following for parsing strings into the relevent sized integer @@ -930,369 +868,365 @@ epicsScanLLong() and epicsScanULLong(), and the functions epicsParseInt64() and epicsParseUInt64(). Use the first two functions and the macros for long long and unsigned long long integer types, and the last two functions for the epicsInt64 and epicsUInt64 types. Note that the latter can map to the types long -and unsigned long on some 64-bit architectures such as linux-x86_64, not to the -two long long types.

+and unsigned long on some 64-bit architectures such as linux-x86\_64, not to the +two long long types. -

This version does not provide the ability to define 64-bit record fields, the +This version does not provide the ability to define 64-bit record fields, the use of the 64-bit types in the IOC database will come in a later release of -EPICS Base.

+EPICS Base. -

Full support for loadable support modules

+### Full support for loadable support modules -

Apparently later versions of Base 3.14 permitted support modules to be loaded +Apparently later versions of Base 3.14 permitted support modules to be loaded from a shared library at runtime without the IOC having been linked against that shared library; the registerRecordDeviceDriver.pl program would accept a partial DBD file containing just the entries needed for the library and generate the appropriate registration code. In 3.15 however the registerRecordDeviceDriver.pl program was replaced by one using the new DBD file parser, and in this a device support entry would only be accepted after first loading the record type that it -depended on.

+depended on. -

The parser has been modified to accept device entries without having seen the +The parser has been modified to accept device entries without having seen the record type first, although a warning is given when that happens. To remove the warning the DBD file can provide a record type declaration instead (no fields can be defined, so the braces must be empty), before the device() entry. The result will generate the correct registration code for the device entry without including anything for any merely declared record types. The generated code can be linked into a shared library and loaded by an IOC at runtime using dlload. -

-

Parallel callback threads

+### Parallel callback threads -

The general purpose callback facility can run multiple parallel callback +The general purpose callback facility can run multiple parallel callback threads per priority level. This makes better use of SMP architectures (e.g. processors with multiple cores), as callback work - which includes second stage processing of records with asynchronuous device support and I/O -scanned processing - can be distributed over the available CPUs.

+scanned processing - can be distributed over the available CPUs. -

Note that by using parallel callback threads the order of scan callback +Note that by using parallel callback threads the order of scan callback requests in the queue is not retained. If a device support needs to be informed when scanIoRequest processing has finished, it should use the new scanIoSetComplete() feature to add a user function that will be called after -the scanIoRequest record processing has finished.

+the scanIoRequest record processing has finished. -

Parallel callback threads have to be explicitly configured, by default -the IOC keeps the old behavior of running one callback thread per priority.

+Parallel callback threads have to be explicitly configured, by default +the IOC keeps the old behavior of running one callback thread per priority. -

Merge MMIO API from devLib2

+### Merge MMIO API from devLib2 -

Added calls to handle 8, 16, and 32 bit Memory Mapped I/O reads and writes. -The calls added include X_iowriteY() and -X_ioreadY() -where X is nat (native), be or le, -and Y is 16 or 32. -Also added are ioread8() and iowrite8().

+Added calls to handle 8, 16, and 32 bit Memory Mapped I/O reads and writes. +The calls added include `X_iowriteY()` and `X_ioreadY()` +where `X` is `nat` (native), `be` or `le`, and `Y` is `16` or `32`. +Also added are `ioread8()` and `iowrite8()`. -

Added optional dbServer API to database

+### Added optional dbServer API to database -

A server layer that sits on top of the IOC database may now register itself -as such by calling dbRegisterServer() and providing optional routines +A server layer that sits on top of the IOC database may now register itself +as such by calling `dbRegisterServer()` and providing optional routines that other components can use. The initial purpose of this API allows the Trace -Processing implementation in dbProcess() to identify a client that -causes a record to process when TPRO is set.

+Processing implementation in `dbProcess()` to identify a client that +causes a record to process when TPRO is set. -

To support the client idenfication, the server provides a routine that +To support the client identification, the server provides a routine that returns that identity string when called by one of its own processing -threads.

+threads. -

Concatenated database definition files

+### Concatenated database definition files -

A series of database definition (dbd) files can now be concatenated during +A series of database definition (dbd) files can now be concatenated during the build process into a newly-created dbd file with result being installed into -$(INSTALL_LOCATION)/dbd without expanding it.

+`$(INSTALL_LOCATION)/dbd` without expanding it. -

The following lines in an EPICS Makefile will create a file name.dbd in the +The following lines in an EPICS Makefile will create a file name.dbd in the O.Common build directory containing the contents of file1.dbd followed by file2.dbd then file3.dbd. The new file will then be installed into -$(INSTALL_LOCATION)/dbd without expanding any of its include statements.

+`$(INSTALL_LOCATION)/dbd` without expanding any of its include statements. -
-DBDCAT += name.dbd
-name_DBD += file1.dbd file2.dbd file3.dbd
-
+``` + DBDCAT += name.dbd + name_DBD += file1.dbd file2.dbd file3.dbd +``` -

The source files file1.dbd, file2.dbd and file3.dbd may be created by the +The source files file1.dbd, file2.dbd and file3.dbd may be created by the current Makefile, be located in the parent directory or any other directory in -the SRC_DIRS list, be specified by their full pathname, exist in the install dbd +the `SRC_DIRS` list, be specified by their full pathname, exist in the install dbd directory, or be found in any dbd directory linked from the application's -RELEASE files.

+RELEASE files. -

Posix: Drop SCHED_FIFO before exec() in child process

+### Posix: Drop `SCHED_FIFO` before exec() in child process -

If Base is compiled with USE_POSIX_THREAD_PRIORITY_SCHEDULING = YES -in configure/CONFIG_SITE or related files, the Posix implementation of the -libCom osiSpawnDetachedProcess() routine will switch the child process -to use the normal SCHED_OTHER (non real-time) scheduler before executing the +If Base is compiled with `USE_POSIX_THREAD_PRIORITY_SCHEDULING = YES` +in `configure/CONFIG_SITE` or related files, the Posix implementation of the +libCom `osiSpawnDetachedProcess()` routine will switch the child process +to use the normal `SCHED_OTHER` (non real-time) scheduler before executing the named executable program. If it needs to use the real-time scheduler the new -program can request that for itself.

+program can request that for itself. -

Posix: Lock all memory when running with FIFO scheduler

+### Posix: Lock all memory when running with FIFO scheduler -

On Posix systems, an IOC application's ability to meet timing deadlines is +On Posix systems, an IOC application's ability to meet timing deadlines is often dependent on its ability to lock part or all of the process's virtual address space into RAM, preventing that memory from being paged to the swap area. This change will attempt to lock the process's virtual address space into RAM if the process has the ability to run threads with different priorities. If -unsuccessful, it prints an message to stderr and continues.

+unsuccessful, it prints an message to stderr and continues. -

On Linux, one can grant a process the ability to run threads with different -priorities by using the command ulimit -r unlimited. To use the -FIFO scheduler for an IOC, use a command like this:

+On Linux, one can grant a process the ability to run threads with different +priorities by using the command `ulimit -r unlimited`. To use the +FIFO scheduler for an IOC, use a command like this: -
chrt -f 1 softIoc -d test.db
+``` + chrt -f 1 softIoc -d test.db +``` -

On Linux, one can grant a process the ability to lock itself into memory -using the command ulimit -l unlimited. These limits can also be -configured on a per user/per group basis by changing /etc/security/limits.conf -or its equivalent.

+On Linux, one can grant a process the ability to lock itself into memory +using the command `ulimit -l unlimited`. These limits can also be +configured on a per user/per group basis by changing `/etc/security/limits.conf` +or its equivalent. -

A child process created via fork() normally inherits its parent's resource +A child process created via `fork()` normally inherits its parent's resource limits, so a child of a real-time soft-IOC will get its parent's real-time priority and memlock limits. The memory locks themselves however are not -inherited by child processes.

+inherited by child processes. -

Implement EPICS_CAS_INTF_ADDR_LIST in rsrv

+### Implement `EPICS_CAS_INTF_ADDR_LIST` in rsrv -

The IOC server can now bind to a single IP address (and optional port number) -read from the standard environment parameter EPICS_CAS_INTF_ADDR_LIST. +The IOC server can now bind to a single IP address (and optional port number) +read from the standard environment parameter `EPICS_CAS_INTF_ADDR_LIST`. Additional addresses included in that parameter after the first will be ignored -and a warning message displayed at iocInit time.

+and a warning message displayed at iocInit time. -

alarmString.h deprecated again

+### alarmString.h deprecated again -

The string arrays that provide string versions of the alarm status and +The string arrays that provide string versions of the alarm status and severity values have been moved into libCom and the header file that used to instanciate them is no longer required, although a copy is still provided for backwards compatibility reasons. Only the alarm.h header needs to be included -now to declare the epicsAlarmSeverityStrings and epicsAlarmConditionStrings -arrays.

+now to declare the `epicsAlarmSeverityStrings` and `epicsAlarmConditionStrings` +arrays. -

General purpose thread pool

+### General purpose thread pool -

A general purpose threaded work queue API epicsThreadPool is added. -Multiple pools can be created with controlable priority and number -of worker threads. Lazy worker startup is supported.

+Multiple pools can be created with controllable priority and number +of worker threads. Lazy worker startup is supported. -

Database field setting updates

+### Database field setting updates -

A database (.db) file loaded by an IOC does not have to repeat the record +A database (.db) file loaded by an IOC does not have to repeat the record type of a record that has already been loaded. It may replace the first -parameter of the record(type, name) statement with an asterisk -character inside double-quotes, "*" instead. Thus the following is a -legal database file:

+parameter of the `record(type, name)` statement with an asterisk +character inside double-quotes, `"*"` instead. Thus the following is a +legal database file: -
record(ao, "ao1") {}
-record("*", "ao1") {
-    field(VAL, 10)
-}
+``` + record(ao, "ao1") {} + record("*", "ao1") { + field(VAL, 10) + } +``` -

Note that database configuration tools will not be expected to have to +Note that database configuration tools will not be expected to have to understand this syntax, which is provided for scripted and hand-coded database -and template instantiation only. Setting the IOC's dbRecordsOnceOnly +and template instantiation only. Setting the IOC's `dbRecordsOnceOnly` flag also makes this syntax illegal, since its purpose is to prevent -multiply-defined records from being collapsed into a single instance.

+multiply-defined records from being collapsed into a single instance. -

Added echo command to iocsh

+### Added echo command to iocsh -

The single argument string may contain escaped characters, which will be +The single argument string may contain escaped characters, which will be translated to their raw form before being printed (enclose the string in quotes to avoid double-translation). A newline is always appended to the output, and -output stream redirection is supported.

+output stream redirection is supported. -

Added macro EPICS_UNUSED to compilerDependencies.h

+### Added macro `EPICS_UNUSED` to compilerDependencies.h -

To prevent the compiler from warning about a known-unused variable, mark it -with the macro EPICS_UNUSED. On gcc and clang this will expand to -__attribute__((unused)) to prevent the warning.

+To prevent the compiler from warning about a known-unused variable, mark it +with the macro `EPICS_UNUSED`. On gcc and clang this will expand to +`__attribute__((unused))` to prevent the warning. -

User specified db substitution file suffix

+### User specified db substitution file suffix -

Per Dirk Zimoch's suggestion, a user specified db substitution file suffix is -now allowed by setting the variable SUBST_SUFFIX in a configuration directory -CONFIG_SITE file or in a Makefile before the include $(TOP)/configure/RULES -line. The default for SUBST_SUFFIX is .substitutions

+Per Dirk Zimoch's suggestion, a user specified db substitution file suffix is +now allowed by setting the variable `SUBST_SUFFIX` in a configuration directory +`CONFIG_SITE` file or in a Makefile before the include $(TOP)/configure/RULES +line. The default for `SUBST_SUFFIX` is `.substitutions` -

NTP Time Provider adjusts to OS tick rate changes

+### NTP Time Provider adjusts to OS tick rate changes -

Dirk Zimoch provided code that allows the NTP Time provider (used on VxWorks +Dirk Zimoch provided code that allows the NTP Time provider (used on VxWorks and RTEMS only) to adapt to changes in the OS clock tick rate after the provider -has been initialized. Note that changing the tick rate after iocInit() is not +has been initialized. Note that changing the tick rate after `iocInit()` is not advisable, and that other software might still misbehave if initialized before -an OS tick rate change.

+an OS tick rate change. -

Added newEpicsMutex macro

+### Added newEpicsMutex macro -

Internal C++ uses of new epicsMutex() have been replaced with a new +Internal C++ uses of `new epicsMutex()` have been replaced with a new macro which calls a new constructor, passing it the file name and line number of the mutex creation code. C code that creates mutexes has been using a similar macro for a long time, but there was no equivalent constructor for the C++ -wrapper class, so identifying a specific mutex was much harder to do.

+wrapper class, so identifying a specific mutex was much harder to do. -

Post DBE_PROPERTY events automatically

+### Post `DBE_PROPERTY` events automatically -

A new record field attribute "prop(YES)" has been added to identify fields +A new record field attribute `prop(YES)` has been added to identify fields holding meta-data. External changes to these fields will cause a CA monitor -event to be sent to all record subscribers who have asked for DBE_PROPERTY -updates. Meta-data fields have been marked for all Base record types.

+event to be sent to all record subscribers who have asked for `DBE_PROPERTY` +updates. Meta-data fields have been marked for all Base record types. -

errlogRemoveListener() routine changed

+### errlogRemoveListener() routine changed -

Code that calls errlogRemoveListener(myfunc) must be modified to use -the new, safer routine errlogRemoveListeners(myfunc, &pvt) instead. +Code that calls `errlogRemoveListener(myfunc)` must be modified to use +the new, safer routine `errlogRemoveListeners(myfunc, &pvt)` instead. The replacement routine takes a second argument which must be the same private -pointer that was passed to errlogAddListener() when adding that +pointer that was passed to `errlogAddListener()` when adding that listener. It also deletes all matching listeners (hence the new plural name) and returns how many were actually deleted, whereas the previous routine only -removed the first listener that matched.

+removed the first listener that matched. -

Simplified generation of .dbd files

+### Simplified generation of .dbd files -

The Perl script makeIncludeDbd.pl has been removed and the rules -that created an intermediate xxxInclude.dbd file from the -Makefile variable xxx_DBD have been modified to generate the target -xxx.dbd file directly. This should simplify applications that +The Perl script `makeIncludeDbd.pl` has been removed and the rules +that created an intermediate `xxxInclude.dbd` file from the +Makefile variable `xxx_DBD` have been modified to generate the target +`xxx.dbd` file directly. This should simplify applications that might have had to provide dependency rules for the intermediate files in 3.15. -Applications which provide their own xxxInclude.dbd source file -will continue to have it expanded as before.

+Applications which provide their own `xxxInclude.dbd` source file +will continue to have it expanded as before. -

New Undefined Severity field UDFS

+### New Undefined Severity field UDFS -

A new field has been added to dbCommon which configures the alarm severity +A new field has been added to dbCommon which configures the alarm severity associated with the record being undefined (when UDF=TRUE). The default value is INVALID so old databases will not be affected, but now individual records can be configured to have a lower severity or even no alarm when undefined. Be careful when changing this on applications where the IVOA field of output records is -used, IVOA still requires an INVALID severity to trigger value replacement.

+used, IVOA still requires an INVALID severity to trigger value replacement. -

New build target tapfiles

+### New build target “tapfiles” -

This new make target runs the same tests as the runtests target, but +This new make target runs the same tests as the “runtests” target, but instead of summarizing or displaying the output for each test script it creates -a .tap file inside the architecture build directory which contains the +a “.tap” file inside the architecture build directory which contains the detailed test output. The output file can be parsed by continuous integration -packages such as Jenkins to show the -test results.

+packages such as [Jenkins](http://www.jenkins-ci.org/) to show the +test results. -

Array field double-buffering

+### Array field double-buffering -

Array data can now be moved, without copying, into and out of the VAL field +Array data can now be moved, without copying, into and out of the VAL field of the waveform, aai, and aao record types by replacing the pointer in BPTR. -The basic rules which device support must follow are:

+The basic rules which device support must follow are: -
    -
  1. BPTR, and the memory it is currently pointing to, can only be accessed - while the record is locked.
  2. -
  3. NELM may not be changed; NORD should be updated whenever the number of - valid data elements changes.
  4. -
  5. When BPTR is replaced it must always point to a block of memory large - enough to hold the maximum number of elements, as given by the NELM and - FTVL fields.
  6. -
+1. BPTR, and the memory it is currently pointing to, can only be accessed + while the record is locked. +2. NELM may not be changed; NORD should be updated whenever the number of + valid data elements changes. +3. When BPTR is replaced it must always point to a block of memory large + enough to hold the maximum number of elements, as given by the NELM and + FTVL fields. -

Spin-locks API added

+### Spin-locks API added -

The new header file epicsSpin.h adds a portable spin-locks API which is +The new header file epicsSpin.h adds a portable spin-locks API which is intended for locking very short sections of code (typically one or two lines of C or C++) to provide a critical section that protects against race conditions. -On Posix platforms this uses the pthread_spinlock_t type if it's available and +On Posix platforms this uses the `pthread_spinlock_t` type if it's available and the build is not configured to use Posix thread priorities, but otherwise it -falls back to a pthread_mutex_t. On the UP VxWorks and RTEMS platforms the +falls back to a `pthread_mutex_t`. On the UP VxWorks and RTEMS platforms the implementations lock out CPU interrupts and disable task preemption while a spin-lock is held. The default implementation (used when no other implementation is provided) uses an epicsMutex. Spin-locks may not be taken recursively, and -the code inside the critical section should be short and deterministic.

+the code inside the critical section should be short and deterministic. -

Improvements to aToIPAddr()

+### Improvements to aToIPAddr() -

The libCom routine aToIPAddr() and the vxWorks implementation of the +The libCom routine aToIPAddr() and the vxWorks implementation of the associated hostToIPAddr() function have been modified to be able to look up hostnames that begin with one or more digits. The epicsSockResolveTest program -was added to check this functionality.

+was added to check this functionality. -

mbboDirect and mbbiDirect records

+### mbboDirect and mbbiDirect records -

These record types have undergone some significant rework, and will behave +These record types have undergone some significant rework, and will behave slightly differently than they did in their 3.14 versions. The externally -visible changes are as follows:

+visible changes are as follows: -
mbbiDirect
+##### mbbiDirect -
    -
  • If the MASK field is set in a database file, it will not be over-written + - If the MASK field is set in a database file, it will not be over-written when the record is initialized. This allows non-contiguous masks to be set, - although only the device support actually uses the MASK field.
  • -
  • If process() finds the UDF field to be set, the record will raise a - UDF/INVALID alarm.
  • -
+ although only the device support actually uses the MASK field. + - If process() finds the UDF field to be set, the record will raise a + UDF/INVALID alarm. -
mbboDirect
+##### mbboDirect -
    -
  • If the MASK field is set in a database file, it will not be over-written + - If the MASK field is set in a database file, it will not be over-written when the record is initialized. This allows non-contiguous masks to be set, - although only the device support actually uses the MASK field.
  • -
  • After the device support's init_record() routine returns during record - initialization, if OMSL is supervisory and UDF is clear the fields - B0-BF will be set from the current VAL field.
  • -
  • When a put to the OMSL field sets it to supervisory, the fields + although only the device support actually uses the MASK field. + - After the device support's `init_record()` routine returns during record + initialization, if OMSL is “supervisory” and UDF is clear the fields + B0-BF will be set from the current VAL field. + - When a put to the OMSL field sets it to “supervisory”, the fields B0-BF will be set from the current VAL field. This did not used to happen, the individual bit fields were previously never modified by the record. Note that this change may require some databases to be modified, if they - were designed to take advantage of the previous behavior.
  • -
+ were designed to take advantage of the previous behavior. -

Redirection of the errlog console stream

+### Redirection of the errlog console stream -

A new routine has been added to the errlog facility which allows the console +A new routine has been added to the errlog facility which allows the console error message stream to be redirected from stderr to some other already open -file stream:

+file stream: -
int errlogSetConsole(FILE *stream);
-
+``` + int errlogSetConsole(FILE *stream); +``` -

The stream argument must be a FILE* pointer as returned by fopen() that is -open for output. If NULL is passed in, the errlog thread's stderr output stream +The stream argument must be a `FILE*` pointer as returned by `fopen()` that is +open for output. If `NULL` is passed in, the errlog thread's stderr output stream will be used instead. Note that messages to the console can be disabled and -re-enabled using the eltc routine which is also an iocsh command, but there is -no iocsh command currently provided for calling errlogSetConsole.

+re-enabled using the `eltc` routine which is also an iocsh command, but there is +no iocsh command currently provided for calling `errlogSetConsole()`. -

Add cleanup subroutine to aSub record

+### Add cleanup subroutine to aSub record -

An aSub routine may set the CADR field with a function pointer which will be +An aSub routine may set the CADR field with a function pointer which will be run before a new routine in the event that a change to the SNAM field changes -the record's process subroutine.

+the record's process subroutine. -

This can be used to free any resources the routine needs to allocate. It can +This can be used to free any resources the routine needs to allocate. It can also be used to determine if this is the first time this routine has been called by this record instance. The CADR field is set to NULL immediately after the -routine it points to is called.

+routine it points to is called. -

Example:

+Example: -
void cleanup(aSubRecord* prec) {
-    free(prec->dpvt);
-    prec->dpvt = NULL;
-}
-
-long myAsubRoutine(aSubRecord* prec) {
-    if (!prec->cadr) {
-        /* check types of inputs and outputs */
-        if (prec->ftva != menuFtypeDOUBLE)
-            return 1; /* oops */
-
-        dpvt = malloc(42);
-        prec->cadr = &cleanup;
+```
+    void cleanup(aSubRecord* prec) {
+        free(prec->dpvt);
+        prec->dpvt = NULL;
     }
 
-    /* normal processing */
-}
-epicsRegisterFunction(myAsubRoutine);
-
+ long myAsubRoutine(aSubRecord* prec) { + if (!prec->cadr) { + /* check types of inputs and outputs */ + if (prec->ftva != menuFtypeDOUBLE) + return 1; /* oops */ -

Sequence record enhancements

+ dpvt = malloc(42); + prec->cadr = &cleanup; + } -

The sequence record type now has 16 link groups numbered 0 through 9 and A + /* normal processing */ + } + epicsRegisterFunction(myAsubRoutine); +``` + +### Sequence record enhancements + +The sequence record type now has 16 link groups numbered 0 through 9 and A through F, instead of the previous 10 groups numbered 1 through 9 and A. The changes to this record are directly equivalent to those described below for the fanout record. The fields OFFS and SHFT have been added and operate on the SELN @@ -1303,544 +1237,374 @@ when the selection number exceeded 10. The record also now posts monitors on the SELN field at the end of the sequence if its value changed when read through the SELL link. -

Fanout record enhancements

+### Fanout record enhancements -

The fanout record type now has 16 output links LNK0-LNK9 and LNKA-LNKF, plus +The fanout record type now has 16 output links LNK0-LNK9 and LNKA-LNKF, plus two additional fields which make the result backwards compatible with 3.14 databases, but also allow the link selection to be shifted without having to -process the SELN value through a calc or calcout record first.

+process the SELN value through a calc or calcout record first. -

Previously there was no LNK0 field, so when SELM is Mask bit 0 of SELN +Previously there was no LNK0 field, so when SELM is “Mask” bit 0 of SELN controls whether the LNK1 link field was activated; bit 1 controls LNK2 and so -on. When SELM is Specified and SELN is zero no output link would be +on. When SELM is “Specified” and SELN is zero no output link would be activated at all; LNK1 gets activated when SELN is 1 and so on. Only 6 links were provided, LNK1 through LNK6. The updated record type maintains the original behavior when the new fields are not configured, except that the SOFT/INVALID -alarm is not generated when SELN is 7 through 15.

+alarm is not generated when SELN is 7 through 15. -

The update involved adding a LNK0 field, as well as fields LNK7 through LNK9 +The update involved adding a LNK0 field, as well as fields LNK7 through LNK9 and LNKA through LNKF. To add flexibility and maintain backwards compatibility, -two additional fields have been added:

+two additional fields have been added: -
-
OFFS
+ - **OFFS** + This field holds a signed offset which is added to SELN to select which link + to activate when SELM is “Specified”. If the resulting value is outside the + range 0 .. 15 the record will go into a SOFT/INVALID alarm state. The default + value of OFFS is zero, so if it is not explicitly set and SELN is 1 the LNK1 + link will be activated. + - **SHFT** + When SELM is “Mask” the signed field SHFT is used to shift the SELN + value by SHFT bits (positive means right-wards, values outside the range -15 .. + 15 will result in a SOFT/INVALID alarm), before using the resulting bit-pattern + to control which links to activate. The default value is -1, so if SHFT is not + explicitly set bit 0 of SELN will be used to control whether LNK1 gets + activated. -
This field holds a signed offset which is added to SELN to select which link -to activate when SELM is Specified. If the resulting value is outside the -range 0 .. 15 the record will go into a SOFT/INVALID alarm state. The default -value of OFFS is zero, so if it is not explicitly set and SELN is 1 the LNK1 -link will be activated.
+The record also now posts monitors on the SELN field if it changes as a +result of record processing (i.e. when read through the SELL link). -
SHFT
+### Deleted Java build rules -
When SELM is Mask the signed field SHFT is used to shift the SELN -value by SHFT bits (positive means right-wards, values outside the range -15 .. -15 will result in a SOFT/INVALID alarm), before using the resulting bit-pattern -to control which links to activate. The default value is -1, so if SHFT is not -explicitly set bit 0 of SELN will be used to control whether LNK1 gets -activated.
- -
- -

The record also now posts monitors on the SELN field if it changes as a -result of record processing (i.e. when read through the SELL link).

- -

Deleted Java build rules

- -

Java has its own build systems now, so we've deleted the rules and associated +Java has its own build systems now, so we've deleted the rules and associated variables from Base, although they might get added to the Extensions build rules -for a while in case anyone still needs them.

+for a while in case anyone still needs them. -

Changes made between 3.14.x and 3.15.0.1

+## Changes made between 3.14.x and 3.15.0.1 -

Application clean rules

+### Application clean rules -

The clean Makefile target has changed between a single-colon rule +The `clean` Makefile target has changed between a single-colon rule and a double-colon rule more than once in the life of the EPICS build rules, and it just changed back to a single-colon rule, but now we recommend that applications that wish to provide a Makefile that is backwards compatible with -the 3.14 build rules use the construct shown below. The 3.15 rules now support -a variable called CLEANS to which a Makefile can add a list of files to -be deleted when the user does a make clean like this:

+the 3.14 build rules use the construct shown below. The 3.15 rules now support +a variable called `CLEANS` to which a Makefile can add a list of files to +be deleted when the user does a `make clean` like this: -
CLEANS += <list of files to be cleaned>
+```
+    CLEANS += 
 
-ifndef BASE_3_15
-clean::
-	$(RM) $(CLEANS)
-endif
+ ifndef BASE_3_15 + clean:: + $(RM) $(CLEANS) + endif +``` -

The conditional rule provides compatibility for use with the 3.14 build -system.

+The conditional rule provides compatibility for use with the 3.14 build +system. -

MSI included with Base

+### MSI included with Base -

An enhanced version of the Macro Substitution and Include program msi +An enhanced version of the Macro Substitution and Include program “msi” has been included with Base. Both this new version of msi and the IOC's -dbLoadTemplates command now support setting global macros in -substitution files, and dbLoadTemplates can now take a list of global +`dbLoadTemplates` command now support setting global macros in +substitution files, and `dbLoadTemplates` can now take a list of global macro settings as the second argument on its command line. The substitution file -syntax is documented in the Application Developers Guide.

+syntax is documented in the Application Developers Guide. -

Cross-builds targeting win32-x86-mingw

+### Cross-builds targeting win32-x86-mingw -

Some Linux distributions now package the MinGW cross-compiler which makes it +Some Linux distributions now package the MinGW cross-compiler which makes it possible to cross-build the win32-x86-mingw target from a linux-x86 host. Build configuration files for this combination are now included; adjust the settings -in configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw and add win32-x86-mingw to -the CROSS_COMPILER_TARGET_ARCHS variable in configure/CONFIG_SITE or in -configure/os/CONFIG_SITE.linux-x86.Common.

+in `configure/os/CONFIG_SITE.linux-x86.win32-x86-mingw` and add win32-x86-mingw to +the `CROSS_COMPILER_TARGET_ARCHS` variable in `configure/CONFIG_SITE` or in +`configure/os/CONFIG_SITE.linux-x86.Common`. -

Architecture win32-x86-cygwin Removed

+### Architecture win32-x86-cygwin Removed -

The ability to compile non-cygwin binaries using the Cygwin build tools is no +The ability to compile non-cygwin binaries using the Cygwin build tools is no longer supported by current versions of Cygwin, so this architecture has been -removed. Use the MinWG tools and the win32-x86-mingw architecture instead.

+removed. Use the MinWG tools and the win32-x86-mingw architecture instead. -

RTEMS and VxWorks Test Harnesses

+### RTEMS and VxWorks Test Harnesses -

The original libCom test harness has been renamed libComTestHarness, -and two additional test harnesses have been created dbTestHarness and -filterTestHarness which are all built for RTEMS and vxWorks targets. -The new ones include tests in src/ioc/db/test and src/std/filters/test.

+The original libCom test harness has been renamed `libComTestHarness`, +and two additional test harnesses have been created `dbTestHarness` and +`filterTestHarness` which are all built for RTEMS and vxWorks targets. +The new ones include tests in src/ioc/db/test and src/std/filters/test. -

Running the new tests requires additional .db and .dbd files to be loaded at +Running the new tests requires additional .db and .dbd files to be loaded at runtime, which can be found in the relevant source directory or its O.Common subdirectory. If the target can access the Base source tree directly it may be simplest to cd to the relevant source directory before running the test. If not, the files needed are listed in the generated 'testspec' file found in the -associated build (O.arch) directory.

+associated build (O.*arch*) directory. -

For RTEMS users the current directory is determined in a BSP specific way. -See rtems_init.c and setBootConfigFromNVRAM.c in src/libCom/RTEMS.

+For RTEMS users the current directory is determined in a BSP specific way. +See `rtems_init.c` and `setBootConfigFromNVRAM.c` in `src/libCom/RTEMS`. -

New API to hook into thread creation

+### New API to hook into thread creation -

A hook API has been added allowing user-supplied functions to be called +A hook API has been added allowing user-supplied functions to be called whenever a thread starts. The calls are made from the thread's context, and can be used to control additional thread properties not handled inside EPICS base, e.g. setting the scheduling policy or CPU affinity (on SMP -systems).

+systems). -

The API also supports a mapping operation, calling a user-supplied function -for every thread that is currently running.

+The API also supports a mapping operation, calling a user-supplied function +for every thread that is currently running. -

New scan rate units

+### New scan rate units -

Scan rates defined in the menuScan.dbd file may now be specified in seconds, +Scan rates defined in the menuScan.dbd file may now be specified in seconds, minutes, hours or Hertz, and plural time units will also be accepted (seconds -are used if no unit is mentioned in the choice string). At iocInit each +are used if no unit is mentioned in the choice string). At `iocInit` each scan rate is compared with the OS's clock tick and a warning printed if the rate is too fast or likely to be more than 10% different to the requested rate. For example the rates given below are all valid, although non-standard (the -default menuScan choices that come with Base have not been changed):

+default menuScan choices that come with Base have not been changed): -
-
menu(menuScan) {
-    choice(menuScanPassive,     "Passive")
-    choice(menuScanEvent,       "Event")
-    choice(menuScanI_O_Intr,    "I/O Intr")
-    choice(menuScan1_hour,      "1 hour")
-    choice(menuScan0_5_hours, "0.5 hours")
-    choice(menuScan15_minutes, "15 minutes")
-    choice(menuScan5_minutes,   "5 minutes")
-    choice(menuScan1_minute,    "1 minute")
-    choice(menuScan10_seconds, "10 seconds")
-    choice(menuScan5_seconds,   "5 seconds")
-    choice(menuScan2_seconds,   "2 seconds")
-    choice(menuScan1_second,    "1 second")
-    choice(menuScan2_Hertz,     "2 Hertz")
-    choice(menuScan5_Hertz,     "5 Hertz")
-    choice(menuScan10_Hertz,   "10 Hz")
-}
+``` + menu(menuScan) { + choice(menuScanPassive, "Passive") + choice(menuScanEvent, "Event") + choice(menuScanI_O_Intr, "I/O Intr") + choice(menuScan1_hour, "1 hour") + choice(menuScan0_5_hours, "0.5 hours") + choice(menuScan15_minutes, "15 minutes") + choice(menuScan5_minutes, "5 minutes") + choice(menuScan1_minute, "1 minute") + choice(menuScan10_seconds, "10 seconds") + choice(menuScan5_seconds, "5 seconds") + choice(menuScan2_seconds, "2 seconds") + choice(menuScan1_second, "1 second") + choice(menuScan2_Hertz, "2 Hertz") + choice(menuScan5_Hertz, "5 Hertz") + choice(menuScan10_Hertz, "10 Hz") + } +``` -

Alarm filtering added to input record types

+### Alarm filtering added to input record types -

The record types ai, calc, longin and mbbi have a new alarm filter added to +The record types ai, calc, longin and mbbi have a new alarm filter added to them. This provides a low-pass filter that can be used to delay the reporting of alarms caused by the input level passing the HIGH, HIHI, LOW or LOLO values. The filter is controlled with a new AFTC field that sets the filter's time constant. The default value for this field is zero, which keeps the record's original -alarm behaviour.

+alarm behaviour. -

The record must be scanned often enough for the filtering action to work +The record must be scanned often enough for the filtering action to work effectively and the alarm severity can only change when the record is processed, but that processing does not have to be regular; the filter uses the time since the record last processed in its calculation. Setting AFTC to a positive number of seconds will delay the record going into or out of a minor alarm severity or from minor to major severity until the input signal has been in that range for -that number of seconds.

+that number of seconds. -

Post events on Waveform record's NORD field

+### Post events on Waveform record's NORD field -

When the record type or device support modify the NORD field of a waveform -record, the record support code now posts DBE_VALUE and DBE_LOG events for that -field, signalling the array length change to any client monitoring the NORD -field.

+When the record type or device support modify the NORD field of a waveform +record, the record support code now posts `DBE_VALUE` and `DBE_LOG` events for that +field, signaling the array length change to any client monitoring the NORD +field. -

Attributes of Non-VAL Fields

+### Attributes of Non-VAL Fields -

Non-VAL fields now report meaningful information for precision, units, +Non-VAL fields now report meaningful information for precision, units, graphic limits, control limits, and alarm limits instead of simply using PREC, EGU, HOPR, LOPR, DRVL, DRVH, HIHI, HIGH, LOW, and LOLO. All delay fields have a default precision of 2 digits, units "s" and control limits of 0 to 100,000 seconds (these precision and limit values can be changed for each record type as a whole at runtime by updating a registered global variable). Input fields like A-L of the calc record read their metadata -from the corresponding INPn link if possible.

-

epicsStdioRedirect.h merged into epicsStdio.h

+from the corresponding INPn link if possible. -

The definitions from the header file epicsStdioRedirect.h have been moved +#### epicsStdioRedirect.h merged into epicsStdio.h + +The definitions from the header file epicsStdioRedirect.h have been moved into epicsStdio.h so all calls to printf(), puts() and putchar() in files that -include that OSI header will now be subject to stdout redirection. In past +include that OSI header will now be subject to stdout redirection. In past releases (3.14.7 and later) it was necessary to request the redirection support -by including the epicsStdioRedirect.h header file. The header file is still -provided, but now it just includes epicsStdio.h.

+by including the epicsStdioRedirect.h header file. The header file is still +provided, but now it just includes epicsStdio.h. -

Named Soft Events

+#### Named Soft Events -

Soft events can now be given meaningful names instead of just using the -numbers 1-255. The EVNT field is now a DBF_STRING. The post_event() API +Soft events can now be given meaningful names instead of just using the +numbers 1-255. The EVNT field is now a `DBF_STRING`. The `post_event()` API is now deprecated but still works. It should be replaced by code that in advance -looks up the EVNTPVT event handle associated with the named event by -calling eventNameToHandle(char *), and when that event occurs passes -that handle to the new postEvent(EVNTPVT) routine (which may be called -from interrupt level). A new iocsh command postEvent name will +looks up the `EVNTPVT` event handle associated with the named event by +calling `eventNameToHandle(char *)`, and when that event occurs passes +that handle to the new `postEvent(EVNTPVT)` routine (which may be called +from interrupt level). A new iocsh command `postEvent name` will trigger a named event from the command-line or a startup script (on vxWorks the -expression postEvent(eventNameToHandle("name")) must be used -instead though).

+expression `postEvent(eventNameToHandle("name"))` must be used +instead though). -

Parallel Builds

+#### Parallel Builds -

As EPICS sites get computers with more CPUs they report additional bugs in our parallel build rules. Various issues have been fixed by separating out the build rules that generate dependency (.d) files, ensuring that they are constructed at -the appropriate time in the build.

+the appropriate time in the build. -

These rule changes can cause additional warning messages to appear when building support modules. Where an application provides its own Makefile rules it may now have to add rules to construct an associated dependency file. In many cases though the change needed is just to replace a dependency for a -target$(OBJ) with the target$(DEP) so this

+`target$(OBJ)` with the `target$(DEP)` so this -
-    myLib$(OBJ): myLib_lex.c
+``` + myLib$(OBJ): myLib_lex.c +``` -

-becomes

+becomes -
-    myLib$(DEP): myLib_lex.c
+``` + myLib$(DEP): myLib_lex.c +``` -

-To debug build issues assocated with dependency files, use the command make ---debug=m which tells GNUmake to display information about what it is doing -during the first pass when it updates its makefiles.

+To debug build issues associated with dependency files, use the command +`make --debug=m` which tells GNUmake to display information about what it is doing +during the first pass when it updates its makefiles. -

-Removed tsDefs.h

+### Removed tsDefs.h -

The deprecated tsDefs API was provided for 3.13 compatibility only, and has now -been removed. Convert any remaining code that used it to call the epicsTime API -instead.

+been removed. Convert any remaining code that used it to call the epicsTime API +instead. -

-Changes to epicsVersion.h

+### Changes to epicsVersion.h -

-The two macros EPICS_UPDATE_LEVEL and EPICS_CVS_SNAPSHOT have +The two macros `EPICS_UPDATE_LEVEL` and `EPICS_CVS_SNAPSHOT` have been deleted from the epicsVersion.h file; they were deprecated in R3.14 and can -be replaced with EPICS_PATCH_LEVEL and EPICS_DEV_SNAPSHOT -respectively.

+be replaced with `EPICS_PATCH_LEVEL` and `EPICS_DEV_SNAPSHOT` +respectively. -

A new pair of macros has been added to make version number comparisons easier. Code that will not work with a version of Base before 3.15.0 can now be -written like this to prevent it from compiling:

+written like this to prevent it from compiling: -
-#if defined(VERSION_INT) && EPICS_VERSION_INT < VERSION_INT(3,15,0,0)
-#  error EPICS Base R3.15.0 or later is required
-#endif
-
+``` + #if defined(VERSION_INT) && EPICS_VERSION_INT < VERSION_INT(3,15,0,0) + # error EPICS Base R3.15.0 or later is required + #endif + ``` -

-Added support for iocLogPrefix

+### Added support for iocLogPrefix -

-Added a iocLogPrefix command to iocsh. This adds a +Added a `iocLogPrefix` command to `iocsh`. This adds a prefix to all messages from this IOC (or other log client) as they get sent to the -iocLogServer. This lets sites use the "fac=<facility>" syntax for +iocLogServer. This lets sites use the `fac=` syntax for displaying the facility, process name etc. in log viewers like the -cmlogviewer.

+`cmlogviewer`. -

-Reworked the epicsEvent C & C++ APIs

+### Reworked the epicsEvent C & C++ APIs -
    -
  • Renamed the enum epicsEventWaitStatus to epicsEventStatus
  • -
  • Defined epicsEventWaitStatus as a macro for epicsEventStatus
  • -
  • Renamed epicsEventWaitOk to epicsEventOk
  • -
  • Renamed epicsEventWaitError to epicsEventError
  • -
  • Defined epicsEventWaitOK and epicsEventWaitError as macros
  • -
  • Added epicsEventTrigger(id) which triggers an event and returns OK or an - error status if the underlying OS primitives report an error
  • -
  • Added epicsEventMustTrigger(id) which halts on error
  • -
  • Defined epicsEventSignal(id) as a macro for epicsEventMustTrigger(id)
  • -
  • Added a new C++ method epicsEvent::trigger() which throws an - epicsEvent::invalidSemaphore in the event of an error
  • -
  • epicsEvent::signal() makes an inline call to epicsEvent::trigger()
  • -
  • epicsEventWait() and epicsEventWaitWithTimeout() now return an error - status if the underlying OS primitives report an error
  • -
  • All the epicsEventMust...() routines are now implemented in the common + - Renamed the enum epicsEventWaitStatus to epicsEventStatus + - Defined epicsEventWaitStatus as a macro for epicsEventStatus + - Renamed epicsEventWaitOk to epicsEventOk + - Renamed epicsEventWaitError to epicsEventError + - Defined epicsEventWaitOK and epicsEventWaitError as macros + - Added epicsEventTrigger(id) which triggers an event and returns OK or an + error status if the underlying OS primitives report an error + - Added epicsEventMustTrigger(id) which halts on error + - Defined epicsEventSignal(id) as a macro for epicsEventMustTrigger(id) + - Added a new C++ method epicsEvent::trigger() which throws an + epicsEvent::invalidSemaphore in the event of an error + - epicsEvent::signal() makes an inline call to epicsEvent::trigger() + - epicsEventWait() and epicsEventWaitWithTimeout() now return an error + status if the underlying OS primitives report an error + - All the epicsEventMust...() routines are now implemented in the common libCom/osi/epicsEvent.cpp source file, and call cantProceed() instead of - mis-using assert()
  • -
  • Implemented epicsEventShow() on Posix
  • -
  • Win32: Removed all epicsShareAPI decorations
  • -
+ mis-using assert() + - Implemented epicsEventShow() on Posix + - Win32: Removed all epicsShareAPI decorations -

-Enabled histogram record type

+### Enabled histogram record type -

The histogram record was not included in the base.dbd file in any 3.14 release, but has now been added along with its associated soft device support. The build system now generates the list of all the record.dbd files in base automatically -in src/std/rec/Makefile.

+in src/std/rec/Makefile. -

-Reorganization of src/

+### Reorganization of src/ -

Reorganization of subdirectories of src/ to better represent the relation -between different parts as described in the following table.

+Reorganization of subdirectories of src/ to better represent the relation +between different parts as described in the following table. -

This change also allows the number of libraries built to be reduced to: -libCap5.so, libca.so, libdbCore.so, libdbStaticHost.so, -libCom.so, libcas.so, libdbRecStd.so, and libgdd.so

+This change also allows the number of libraries built to be reduced to: +libCap5.so, libca.so, libdbCore.so, libdbStaticHost.so, +libCom.so, libcas.so, libdbRecStd.so, and libgdd.so - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ComponentDependencyLibrary nameDescription
src/toolsBuild system scripts
src/libComsrc/toolsComUtility routines and OS-independant API
src/templatesrc/toolsUser application templates (e.g. makeBaseApp)
src/ca/clientsrc/libComcaChannel Access client
src/ca/legacy/gddsrc/ca/clientgddGeneric data layer for PCAS
src/ca/legacy/pcassrc/ca/legacy/gddcasPortable Channel Access Server
src/iocsrc/cadbCoreCore database processing functions
src/stdsrc/iocdbRecStdStandard records, soft device support and the softIoc
+| Component | Dependency | Library name | Description | +| ------------------ | ----------------- | ------------ | ----------------------------------------------------- | +| src/tools | | | Build system scripts | +| src/libCom | src/tools | Com | Utility routines and OS-independant API | +| src/template | src/tools | | User application templates (e.g. makeBaseApp) | +| src/ca/client | src/libCom | ca | Channel Access client | +| src/ca/legacy/gdd | src/ca/client | gdd | Generic data layer for PCAS | +| src/ca/legacy/pcas | src/ca/legacy/gdd | cas | Portable Channel Access Server | +| src/ioc | src/ca | dbCore | Core database processing functions | +| src/std | src/ioc | dbRecStd | Standard records, soft device support and the softIoc | -

In order to better reflect these relations the following -directories and files were moved as described:

+directories and files were moved as described: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Relocations
PreviousNew
libCom
src/RTEMSsrc/libCom/RTEMS
src/toolsComm/flexsrc/libCom/flex
src/toolsComm/antelopesrc/libCom/yacc
src/dbStatic/alarm.h
.../alarmString.h
src/libCom/misc/
IOC Core Components
src/bptsrc/ioc/bpt
src/dbsrc/ioc/db
src/dbStaticsrc/ioc/dbStatic
src/dbtoolssrc/ioc/dbtemplate
src/miscsrc/ioc/misc
src/registrysrc/ioc/registry
src/rsrvsrc/ioc/rsrv 1
Standard Record Definitions
src/dev/softDevsrc/std/dev
src/recsrc/std/rec
src/softIocsrc/std/softIoc
Channel Access
src/casrc/ca/client
src/catoolssrc/ca/client/tools
src/cap5src/ca/client/perl
src/gddsrc/ca/legacy/gdd
src/cassrc/ca/legacy/pcas
src/excassrc/ca/legacy/pcas/ex
User Templates
src/makeBaseAppsrc/template/base
src/makeBaseExtsrc/template/ext
Dispersed
src/util 2src/ca/client
src/ca/client/test
src/libCom/log
src/as 3src/libCom/as
src/ioc/as
+#### Relocations -

1 +Category | Previous | New +:--- | :--- | :--- +libCom | srcRTEMS | src/libCom/RTEMS +| | src/toolsComm/flex | src/libCom/flex | +| | src/toolsComm/antelope | src/libCom/yacc +| | src/dbStatic/alarm.h | src/libCom/misc +| | .../alarmString.h | src/libCom/misc +IOC Core Components | src/bpt | src/ioc/bpt +| | src/db | src/ioc/db +| | src/dbStatic | src/ioc/dbStatic +| | src/dbtools | src/ioc/dbtemplate +| | src/misc | src/ioc/misc +| | src/registry | src/ioc/registry +| | src/rsrv | src/ioc/rsrv [1](#rsrv) +Standard Record Definitions | src/dev/softDev | src/std/dev +| | src/rec | src/std/rec +| | src/softIoc | src/std/softIoc +Channel Access | src/ca | src/ca/client +| | src/catools | src/ca/client/tools +| | src/cap5 | src/ca/client/perl +| | src/gdd | src/ca/legacy/gdd +| | src/cas | src/ca/legacy/pcas +| | src/excas | src/ca/legacy/pcas/ex +User Templates | src/makeBaseApp | src/template/base +| | src/makeBaseExt | src/template/ext +Dispersed | src/util [2](#util) | src/ca/client +| | | src/ca/client/test +| | | src/libCom/log +| | src/as [3](#as) | src/libCom/as +| | | src/ioc/as + +1 RSRV is built as part of dbCore due to its tight (bidirectional) coupling -with the other database code.

+with the other database code. -

2 -The contents for src/util/ moved to three locations. The caRepeater init script -was moved to src/ca/client/. ca_test is now in src/ca/client/test/. +2 +The contents for src/util/ moved to three locations. The caRepeater init script +was moved to src/ca/client/. `ca_test` is now in src/ca/client/test/. The iocLogServer was moved into the same directory (src/libCom/log) as -the log client code.

+the log client code. -

3 +3 The Access Security code has been divided, with the parts not related to the database (lexer/parser and trap registration) becoming part of libCom. -The remaining components are included in the dbCore library

+The remaining components are included in the dbCore library -

-Moved src/RTEMS/base directory

+### Moved src/RTEMS/base directory -

-These files are now found under src/RTEMS.

+These files are now found under src/RTEMS. -

-Removed 3.13 compatibility

+### Removed 3.13 compatibility -

-Removed the 3.13 <top>/config directory and build compatibility rules and -variables, and various conversion documents.

- - - +Removed the 3.13 `/config` directory and build compatibility rules and +variables, and various conversion documents. From 9efefad9554961d8eda8d01fb6107d5e824dc693 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Oct 2019 00:57:45 -0400 Subject: [PATCH 177/281] Fix markdown formatting issue --- documentation/RELEASE_NOTES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 133c823a0..7580b3a3b 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -1490,7 +1490,7 @@ written like this to prevent it from compiling: #if defined(VERSION_INT) && EPICS_VERSION_INT < VERSION_INT(3,15,0,0) # error EPICS Base R3.15.0 or later is required #endif - ``` +``` ### Added support for iocLogPrefix From 0a01c386984db607fb7f79bdde7482d64f9311a8 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Oct 2019 12:12:41 -0400 Subject: [PATCH 178/281] File renames .dbd to .dbd.pod for stringout --- src/ioc/db/{menuIvoa.dbd => menuIvoa.dbd.pod} | 0 src/ioc/db/{menuOmsl.dbd => menuOmsl.dbd.pod} | 0 src/ioc/db/{menuYesNo.dbd => menuYesNo.dbd.pod} | 0 src/std/rec/{stringoutRecord.dbd => stringoutRecord.dbd.pod} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/ioc/db/{menuIvoa.dbd => menuIvoa.dbd.pod} (100%) rename src/ioc/db/{menuOmsl.dbd => menuOmsl.dbd.pod} (100%) rename src/ioc/db/{menuYesNo.dbd => menuYesNo.dbd.pod} (100%) rename src/std/rec/{stringoutRecord.dbd => stringoutRecord.dbd.pod} (100%) diff --git a/src/ioc/db/menuIvoa.dbd b/src/ioc/db/menuIvoa.dbd.pod similarity index 100% rename from src/ioc/db/menuIvoa.dbd rename to src/ioc/db/menuIvoa.dbd.pod diff --git a/src/ioc/db/menuOmsl.dbd b/src/ioc/db/menuOmsl.dbd.pod similarity index 100% rename from src/ioc/db/menuOmsl.dbd rename to src/ioc/db/menuOmsl.dbd.pod diff --git a/src/ioc/db/menuYesNo.dbd b/src/ioc/db/menuYesNo.dbd.pod similarity index 100% rename from src/ioc/db/menuYesNo.dbd rename to src/ioc/db/menuYesNo.dbd.pod diff --git a/src/std/rec/stringoutRecord.dbd b/src/std/rec/stringoutRecord.dbd.pod similarity index 100% rename from src/std/rec/stringoutRecord.dbd rename to src/std/rec/stringoutRecord.dbd.pod From ee38b99e0fe23280a08d35c84963868b598a35a5 Mon Sep 17 00:00:00 2001 From: Saeed Haghtalab Date: Fri, 6 Sep 2019 10:36:29 +0200 Subject: [PATCH 179/281] Adding POD to stringout record Also to menuYesNo, menuOmsl, menuIvoa menus --- src/ioc/db/menuIvoa.dbd.pod | 15 +- src/ioc/db/menuOmsl.dbd.pod | 18 +- src/ioc/db/menuYesNo.dbd.pod | 22 +- src/std/rec/stringoutRecord.dbd.pod | 368 ++++++++++++++++++++++++++-- 4 files changed, 395 insertions(+), 28 deletions(-) diff --git a/src/ioc/db/menuIvoa.dbd.pod b/src/ioc/db/menuIvoa.dbd.pod index b1b3ce51f..8ea2c7a7d 100644 --- a/src/ioc/db/menuIvoa.dbd.pod +++ b/src/ioc/db/menuIvoa.dbd.pod @@ -3,10 +3,19 @@ # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuIvoa + +This menu specifies the possibile actions to take when the INVALID alarm is +triggered. See individual record types for more information. + +=menu menuIvoa + +=cut + menu(menuIvoa) { choice(menuIvoaContinue_normally,"Continue normally") choice(menuIvoaDon_t_drive_outputs,"Don't drive outputs") diff --git a/src/ioc/db/menuOmsl.dbd.pod b/src/ioc/db/menuOmsl.dbd.pod index 3022437dc..833f44354 100644 --- a/src/ioc/db/menuOmsl.dbd.pod +++ b/src/ioc/db/menuOmsl.dbd.pod @@ -3,10 +3,22 @@ # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuOmsl + +This menu is used for the C field of many output record types. It controls +whether the record will fetch an input value from its C input link when +processed, which is useful when it is part of a closed loop control algorithm. +The C state means the input link will not be used, C +enables the input link. + +=menu menuOmsl + +=cut + menu(menuOmsl) { choice(menuOmslsupervisory,"supervisory") choice(menuOmslclosed_loop,"closed_loop") diff --git a/src/ioc/db/menuYesNo.dbd.pod b/src/ioc/db/menuYesNo.dbd.pod index 2d09dd65a..d4237e7b8 100644 --- a/src/ioc/db/menuYesNo.dbd.pod +++ b/src/ioc/db/menuYesNo.dbd.pod @@ -3,10 +3,26 @@ # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuYesNo + +This menu is used by many record types to specify simple C or C +options for record-specific purposes. + +Note that no other values for a field that uses menuYesNo are possible, e.g. +C or C would not be accepted as choices for the field. +Also, the choices C, C, and C are not valid choices since they +don't match the case of C or C. +The integer values C<0> and C<1> may often be used instead however, they are +used as an index into the choices so C<0> becomes C and C<1> becomes . + +=menu menuYesNo + +=cut + menu(menuYesNo) { choice(menuYesNoNO,"NO") choice(menuYesNoYES,"YES") diff --git a/src/std/rec/stringoutRecord.dbd.pod b/src/std/rec/stringoutRecord.dbd.pod index fe0bae5d0..5e6caf758 100644 --- a/src/std/rec/stringoutRecord.dbd.pod +++ b/src/std/rec/stringoutRecord.dbd.pod @@ -6,12 +6,80 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 String Output Record (stringout) + +The stringout record is used to write an arbitrary ASCII string of up to 40 +characters to other records or software variables. + +=head2 Contents + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +
+
+
+ +=end html + +=recordtype stringout + +=cut + +include "menuIvoa.dbd" + menu(stringoutPOST) { choice(stringoutPOST_OnChange,"On Change") choice(stringoutPOST_Always,"Always") } recordtype(stringout) { - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_STRING) { prompt("Current Value") promptgroup("50 - Output") @@ -19,12 +87,41 @@ recordtype(stringout) { pp(TRUE) size(40) } - field(OVAL,DBF_STRING) { - prompt("Previous Value") - special(SPC_NOMOD) - interest(3) - size(40) - } + +=head2 Parameter Fields + +=head3 Scan Parameters + +The string output record has the standard fields for specifying under what +circumstances it will be processed. These fields are listed in +L. +In addition, L +explains how these fields are used. + +=head3 Desired Output Parameters + +The string output record must specify from where it gets its desired output +string. The first field that determines where the desired output originates is +the output mode select (OSML) field, which can have two possible value: C<<< +closed_loop >>> or C<<< supervisory >>>. If C<<< supervisory >>> is specified, +DOL is ignored, the current value of VAL is written, and the VAL can be changed +externally via dbPuts at run-time. If C<<< closed_loop >>> is specified, the VAL +field's value is obtained from the address specified in the desired output +location field (DOL) which can be either a database link or a channel access +link. + +DOL can also be a constant in addition to a link, in which case VAL is +initialized to the constant value. However, your string constant may be +interpreted as a CA link name, so if you want to initialize your string output +record, it's best to use the VAL field. Note that if DOL is a constant, OMSL +cannot be C<<< closed_loop. >>> See +L
+for information on specifying links. + +=fields VAL, DOL, OMSL + +=cut + field(DOL,DBF_INLINK) { prompt("Desired Output Loc") promptgroup("40 - Input") @@ -36,11 +133,42 @@ recordtype(stringout) { interest(1) menu(menuOmsl) } + +=head3 Write Parameters + +The output link specified in the OUT field specifies where the string output +record is to write its string. The link can be a database or channel access +link. If the OUT field is a constant, no output will be written. See L
for information on specifying links. + +In addition, the appropriate device support module must be entered into the DTYP +field. + +=fields OUT, DTYP + +=cut + field(OUT,DBF_OUTLINK) { prompt("Output Specification") promptgroup("50 - Output") interest(1) } + +=head3 Monitor Parameters + +These parameters are used to specify when the monitor post should be sent by +C routine. There are two possible choices: + +=head4 Menu stringoutPOST + +=menu stringoutPOST + +APST is used for archiver monitors and MPST is for all other type of monitors. + +=fields MPST, APST + +=cut + field(MPST,DBF_MENU) { prompt("Post Value Monitors") promptgroup("80 - Display") @@ -53,6 +181,78 @@ recordtype(stringout) { interest(1) menu(stringoutPOST) } + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. These +fields are used to display the value and other parameters of the string output +either textually or graphically. + +See L +for more on the record name (NAME) and description (DESC) fields. + +=fields NAME, DESC + +=head3 Alarm Parameters + +The possible alarm conditions for the string output record are the SCAN, READ, +and INVALID alarms. The severity of the first two is always MAJOR and not +configurable. + +The IVOA field specifies an action to take when the INVALID alarm is triggered. +There are three possible actions: + +=head4 Menu menuIvoa + +=menu menuIvoa + +When C<<< Set output to IVOV >>>, the value contained in the IVOV field is +written to the output link during an alarm condition. See +L +for more information on the IVOA and IVOV fields. +L +lists other fields related to a alarms that are common to all record types. + +=fields IVOA, IVOV + +=cut + + field(IVOA,DBF_MENU) { + prompt("INVALID output action") + promptgroup("50 - Output") + interest(2) + menu(menuIvoa) + } + field(IVOV,DBF_STRING) { + prompt("INVALID output value") + promptgroup("50 - Output") + interest(2) + size(40) + } + +=head3 Run-time and Simulation Mode Parameters + +The old value field (OVAL) of the string input is used to implement value change +monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered. + +=fields OVAL + +The following fields are used to operate the string output in the simulation +mode. See +L +for more information on these fields. + +=fields SIOL, SIML, SIMM, SIMS + +=cut + + field(OVAL,DBF_STRING) { + prompt("Previous Value") + special(SPC_NOMOD) + interest(3) + size(40) + } + field(SIOL,DBF_OUTLINK) { prompt("Sim Output Specifctn") promptgroup("90 - Simulate") @@ -74,16 +274,146 @@ recordtype(stringout) { interest(2) menu(menuAlarmSevr) } - field(IVOA,DBF_MENU) { - prompt("INVALID output action") - promptgroup("50 - Output") - interest(2) - menu(menuIvoa) - } - field(IVOV,DBF_STRING) { - prompt("INVALID output value") - promptgroup("50 - Output") - interest(2) - size(40) - } + +=begin html + +
+
+
+ +=end html + +=head2 Record Support + +=head3 Record Support Routines (stringoutRecord.c) + +=head4 init_record + + long (*init_record)(struct dbCommon *precord, int pass) + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available. The routine +next checks to see if the device support write routine is defined. If either +device support or the device support write routine does not exist, an error +message is issued and processing is terminated. + +If DOL is a constant, then the type double constant, if non-zero, is converted +to a string and stored into VAL and UDF is set to FALSE. If DOL type is a +PV_LINK then dbCaAddInlink is called to create a channel access link. + +If device support includes C, it is called. + +=head4 process + + long (*process)(struct dbCommon *precord) + +See L. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE and OMSL is CLOSED_LOOP, recGblGetLinkValue is called to read +the current value of VAL. See L. +If the return status of recGblGetLinkValue is zero then UDF is set to FALSE. + +=item 3. + +Check severity and write the new value. See +L +and L +for details on how the simulation mode and the INVALID alarm conditions affect output. + +=item 4. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if OVAL is not equal to VAL. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +
+
+
+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each stringout output record must have an associated set of device support +routines. The primary responsibility of the device support routines is to write +a new value whenever write_stringout is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, VAL, OUT + +=head3 Device Support Routines (devSoSoft.c) + +=head4 write_stringout + + long write_stringout(stringoutRecord *prec) + +This routine must output a new value. It returns the following values: + +=over + +=item * 0: Success. + +=item * Other: Error. + +=back + +=head3 Device Support for Soft Records + +The C<<< Soft Channel >>> device support module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_so calls recGblPutLinkValue to write the current value of VAL. See +L. + +=cut + } From 7ca26c515aec7897f1cb9298832be64a560d1be9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Oct 2019 14:46:18 -0400 Subject: [PATCH 180/281] Clean up stringin POD links --- src/std/rec/stringinRecord.dbd.pod | 33 ++++++++++++------------------ 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/src/std/rec/stringinRecord.dbd.pod b/src/std/rec/stringinRecord.dbd.pod index 2dd305502..1de0cbe85 100644 --- a/src/std/rec/stringinRecord.dbd.pod +++ b/src/std/rec/stringinRecord.dbd.pod @@ -77,7 +77,7 @@ menu(stringinPOST) { choice(stringinPOST_Always,"Always") } recordtype(stringin) { - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_STRING) { prompt("Current Value") promptgroup("40 - Input") @@ -91,11 +91,8 @@ recordtype(stringin) { =head3 Scan Parameters The string input record has the standard fields for specifying under what -circumstances it will be processed. These fields are listed in -L. -In addition, -L -explains how these fields are used. +circumstances it will be processed. These fields are listed in L. +In addition, L explains how these fields are used. =head3 Read Parameters @@ -107,8 +104,7 @@ placed in the VAL field. The maximum number of characters that the string in VAL can be is 40. In addition, the appropriate device support module must be entered into the DTYP field. -See L
-for information on specifying links. +See L
for information on specifying links. =fields VAL, INP, DTYP @@ -122,7 +118,7 @@ for information on specifying links. =head3 Monitor Parameters -These parameters are used to specify when the monitor post should be sent by +These parameters are used to specify when the monitor post should be sent by C routine. There are two possible choices: =head4 Menu stringinPOST @@ -150,16 +146,16 @@ APST is used for archiver monitors and MPST is for all other type of monitors. =head3 Operator Display Parameters -See L -for more on the record name (NAME) and description (DESC) fields. +See L for more on the record name (NAME) and +description (DESC) fields. =fields NAME, DESC =head3 Alarm Parameters The string input record has the alarm parameters common to all record types. -L -lists other fields related to a alarms that are common to all record types. +L lists other fields related to a alarms that are common to all +record types. =head3 Run-time and Simulation Mode Parameters @@ -171,9 +167,7 @@ monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered. The following fields are used to operate the string input in the simulation -mode. See -L -for more information on simulation mode fields. +mode. See L for more information on simulation mode fields. =fields SIOL, SVAL, SIML, SIMM, SIMS @@ -259,9 +253,8 @@ record. Thus error storms will not occur. =item 2. -readValue is called. See -L -for more information on simulation mode fields and how they affect input. +readValue is called. See L for more information on simulation +mode fields and how they affect input. =item 3. @@ -350,7 +343,7 @@ to a string and stored into VAL by C, and UDF is set to FALSE. If the INP link type is PV_LINK, then dbCaAddInlink is called by C. read_stringin calls recGblGetLinkValue to read the current value of VAL. See -L. +L. If the return status of recGblGetLinkValue is zero, then read_stringin sets UDF to FALSE. The status of recGblGetLinkValue is returned. From e0950643bbfe05895a807539bbb230d78d6edada Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Oct 2019 14:53:10 -0400 Subject: [PATCH 181/281] Clean up state POD links --- src/std/rec/stateRecord.dbd.pod | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/std/rec/stateRecord.dbd.pod b/src/std/rec/stateRecord.dbd.pod index 8734f01bd..9dab4b53a 100644 --- a/src/std/rec/stateRecord.dbd.pod +++ b/src/std/rec/stateRecord.dbd.pod @@ -14,7 +14,7 @@ interface. Its only function is to provide a place in the database through which the state program can inform the operator interface of its state by storing an arbitrary ASCII string in its VAL field. -B +B =head2 Contents @@ -55,31 +55,28 @@ B. -In addition, -L -explains how these fields are used. +it will be processed. These fields are listed in L. In addition, +L explains how these fields are used. =head3 Operator Display Parameters -See L -for more on the record name (NAME) and description (DESC) fields. +See L for more on the record name (NAME) and +description (DESC) fields. =fields NAME, DESC =head3 Alarm Parameters -The state record has the alarm parameters common to all record types. -L -lists other fields related to a alarms that are common to all record types. +The state record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. =head3 Run-time Parameters @@ -87,7 +84,7 @@ These parameters are used by the application code to convey the state of the program to the operator interface. The VAL field holds the string retrieved from the state program. The OVAL is used to implement monitors for the VAL field. When the string in OVAL differs from the one in VAL, monitors are triggered. -They represent the current state of the sequence program. +They represent the current state of the sequence program. =fields VAL, OVAL @@ -115,8 +112,8 @@ They represent the current state of the sequence program. long (*process)(struct dbCommon *precord) -process triggers monitors on VAL when it changes and scans the forward link if -necessary. +C triggers monitors on VAL when it changes and scans the forward +link if necessary. =cut From 47f295fecb86773c7e6c5bc9c219a0a374224115 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Oct 2019 15:02:06 -0400 Subject: [PATCH 182/281] Clean up permissive POD links --- src/std/rec/permissiveRecord.dbd.pod | 32 +++++++++++++--------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/std/rec/permissiveRecord.dbd.pod b/src/std/rec/permissiveRecord.dbd.pod index 8e0747fe9..bdcecb5e7 100644 --- a/src/std/rec/permissiveRecord.dbd.pod +++ b/src/std/rec/permissiveRecord.dbd.pod @@ -14,7 +14,7 @@ example would be a sequence program server and an operator interface client. By using multiple permissive records a sequence program can communicate its current state to the client. -B +B =head2 Contents @@ -59,19 +59,17 @@ B. -In addition, -L - explains how these fields are used. Since the permissive record supports - no direct interfaces to hardware, its SCAN field cannot be C<<< I/O Intr >>>. +circumstances the record will be processed. These fields are listed in +L. In addition, L explains how these +fields are used. Since the permissive record supports no direct interfaces to +hardware, its SCAN field cannot be C<<< I/O Intr >>>. =head3 Client-server Parameters @@ -106,9 +104,9 @@ Note that when WFLG is ON, the client program ''must not'' turn VAL to on. =head3 Operator Display Parameters The label field (LABL) contains a string given to it that should describe the -record in further detail. In addition to the DESC field. See -L -for more on the record name (NAME) and description (DESC) fields. +record in further detail. In addition to the DESC field. See +L for more on the record name (NAME) and +description (DESC) fields. =fields LABL, NAME, DESC @@ -124,9 +122,9 @@ for more on the record name (NAME) and description (DESC) fields. =head3 Alarm Parameters -The Permissive record has the alarm parameters common to all record types. -L -lists other fields related to a alarms that are common to all record types. +The Permissive record has the alarm parameters common to all record types. +L lists other fields related to a alarms that are common to all +record types. =head3 Run-time Parameters @@ -158,9 +156,9 @@ OLFG. long (*process)(struct dbCommon *precord) -process sets UDF to FALSE, triggers monitors on VAL and WFLG when they change, -and scans the forward link if necessary. +C<<< process() >>> sets UDF to FALSE, triggers monitors on VAL and WFLG when +they change, and scans the forward link if necessary. =cut -} \ No newline at end of file +} From 3128fdb930e0f7e6afb51c24f26f291aca17725b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 17 Oct 2019 16:14:59 -0500 Subject: [PATCH 183/281] Add and use epicsProve.pl script Some Windows Perl installations don't have a working prove.bat so 'make test-results' doesn't work properly on them. --- configure/CONFIG_BASE | 1 + configure/RULES_BUILD | 2 +- src/tools/Makefile | 1 + src/tools/epicsProve.pl | 10 ++++++++++ 4 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 src/tools/epicsProve.pl diff --git a/configure/CONFIG_BASE b/configure/CONFIG_BASE index 2f099be96..c979d6d7c 100644 --- a/configure/CONFIG_BASE +++ b/configure/CONFIG_BASE @@ -69,6 +69,7 @@ REGISTERRECORDDEVICEDRIVER = $(PERL) $(TOOLS)/registerRecordDeviceDriver.pl CONVERTRELEASE = $(PERL) $(call FIND_TOOL,convertRelease.pl) FULLPATHNAME = $(PERL) $(TOOLS)/fullPathName.pl TAPTOJUNIT = $(PERL) $(TOOLS)/tap-to-junit-xml.pl +PROVE = $(PERL) $(TOOLS)/epicsProve.pl #------------------------------------------------------- # tools for installing libraries and products diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 7061c5658..ca05f19c6 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -351,7 +351,7 @@ testspec: $(TESTSCRIPTS) test-results: tapfiles ifneq ($(TAPFILES),) ifdef RUNTESTS_ENABLED - prove --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES) + $(PROVE) --failures --ext .tap --exec "$(CAT)" --color $(TAPFILES) endif CURRENT_TAPFILES := $(wildcard $(TAPFILES)) diff --git a/src/tools/Makefile b/src/tools/Makefile index c1606c8b3..636717d90 100644 --- a/src/tools/Makefile +++ b/src/tools/Makefile @@ -39,6 +39,7 @@ PERL_SCRIPTS += assembleSnippets.pl PERL_SCRIPTS += convertRelease.pl PERL_SCRIPTS += cvsclean.pl PERL_SCRIPTS += dos2unix.pl +PERL_SCRIPTS += epicsProve.pl PERL_SCRIPTS += expandVars.pl PERL_SCRIPTS += fullPathName.pl PERL_SCRIPTS += installEpics.pl diff --git a/src/tools/epicsProve.pl b/src/tools/epicsProve.pl new file mode 100644 index 000000000..a1b0c14d4 --- /dev/null +++ b/src/tools/epicsProve.pl @@ -0,0 +1,10 @@ +#!/usr/bin/env perl + +# Some Windows Perl installations provide a prove.bat file which +# doesn't work properly. + +use App::Prove; + +my $app = App::Prove->new; +$app->process_args(@ARGV); +exit( $app->run ? 0 : 1 ); From 953dd2b7f92647ed712714ab04f376a6d9b610eb Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 17 Oct 2019 17:17:05 -0500 Subject: [PATCH 184/281] Document use of epicsProve.pl Also replaced UTF-8 smart-quotes and m-dashes with ASCII/Markdown --- documentation/RELEASE_NOTES.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 7580b3a3b..451b2371d 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -6,6 +6,14 @@ This version of EPICS Base has not been released yet. +### `make test-results` for Windows + +The make target `test-results` should now work properly on Windows. Some Perl +installations used versions of `prove.bat` that would only display the results of +up to 3 tests or didn't return an error status in the event of tests failing. The +build system now calls its own perl script to summarize the results instead of +passing a list of TAP filenames to `prove`. + ### Add option to avoid CALLBACK conflict If a macro `EPICS_NO_CALLBACK` is defined, then callback.h will no longer (re)define CALLBACK. @@ -235,23 +243,23 @@ built-in self-test programs and viewing the results. Since these targets are intended for limited use they can have requirements for the build host which go beyond the standard minimum set needed to build and run Base. -#### `test-results` — Summarize test results +#### `test-results` - Summarize test results The new make target `test-results` will run the self-tests if necessary to generate a TAP file for each test, then summarizes the TAP output files in each test directory in turn, displaying the details of any failures. -This step uses the program “prove” which comes with Perl, but also needs -“cat” to be provided in the default search path so will not work on most +This step uses the program `prove` which comes with Perl, but also needs +`cat` to be provided in the default search path so will not work on most Windows systems. -#### `junitfiles` — Convert test results to JUnit XML Format +#### `junitfiles` - Convert test results to JUnit XML Format The new make target `junitfiles` will run the self-tests if necessary and then convert the TAP output files into the more commonly-supported JUnit XML format. The program that performs this conversion needs the Perl module -“`XML::Generator`” to have been installed. +`XML::Generator` to have been installed. -#### `clean-tests` — Delete test result files +#### `clean-tests` - Delete test result files The new make target `clean-tests` removes any test result files from previous test runs. It cleans both TAP and JUnit XML files. @@ -1103,11 +1111,11 @@ configured to have a lower severity or even no alarm when undefined. Be careful when changing this on applications where the IVOA field of output records is used, IVOA still requires an INVALID severity to trigger value replacement. -### New build target “tapfiles” +### New build target `tapfiles` -This new make target runs the same tests as the “runtests” target, but +This new make target runs the same tests as the `runtests` target, but instead of summarizing or displaying the output for each test script it creates -a “.tap” file inside the architecture build directory which contains the +a `.tap` file inside the architecture build directory which contains the detailed test output. The output file can be parsed by continuous integration packages such as [Jenkins](http://www.jenkins-ci.org/) to show the test results. From 69035629154c1ea20e8dacf5d122802d3d3277e5 Mon Sep 17 00:00:00 2001 From: Michael Ritzert Date: Tue, 15 Oct 2019 19:31:26 -0700 Subject: [PATCH 185/281] RSRV: fix large buffer resize Take into account that realloc may already have moved the data to a new buffer. --- modules/database/src/ioc/rsrv/caservertask.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index 7a9ae63b3..c51a06db6 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -1343,10 +1343,13 @@ void casExpandBuffer ( struct message_buffer *buf, ca_uint32_t size, int sendbuf // round up to multiple of 4K size = ((size-1)|0xfff)+1; - if (buf->type==mbtLargeTCP) + if (buf->type==mbtLargeTCP) { newbuf = realloc (buf->buf, size); - else + if(newbuf) + buf->buf = newbuf; + } else { newbuf = malloc (size); + } newtype = mbtLargeTCP; newsize = size; From 32aeabfc615568391bc51535710a0668873f8e92 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 7 Oct 2019 11:29:27 -0700 Subject: [PATCH 186/281] msvc unittests disable dialog on error or assert() failure Showing a dialog is really unhelpful in headless CI environments. _CrtSetReportMode also set _CRT_WARN Not clear what the default is. --- modules/libcom/src/misc/epicsUnitTest.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/libcom/src/misc/epicsUnitTest.c b/modules/libcom/src/misc/epicsUnitTest.c index 4ac18ea1c..0c827b0b3 100644 --- a/modules/libcom/src/misc/epicsUnitTest.c +++ b/modules/libcom/src/misc/epicsUnitTest.c @@ -16,6 +16,10 @@ #include #include +#ifdef _WIN32 +# include +#endif + #define epicsExportSharedSymbols #include "epicsThread.h" #include "epicsMutex.h" @@ -57,6 +61,14 @@ static epicsThreadOnceId onceFlag = EPICS_THREAD_ONCE_INIT; static void testOnce(void *dummy) { testLock = epicsMutexMustCreate(); perlHarness = (getenv("HARNESS_ACTIVE") != NULL); +#ifdef _WIN32 + _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); + _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR ); + _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); + _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR ); + _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); + _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR ); +#endif } void testPlan(int plan) { From c8006f2934071a97c198674310134283b998c26d Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 7 Oct 2019 22:32:32 +0100 Subject: [PATCH 187/281] WIN32: Add stack trace printing on assert/error --- modules/libcom/src/misc/epicsUnitTest.c | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/modules/libcom/src/misc/epicsUnitTest.c b/modules/libcom/src/misc/epicsUnitTest.c index 0c827b0b3..dce05983e 100644 --- a/modules/libcom/src/misc/epicsUnitTest.c +++ b/modules/libcom/src/misc/epicsUnitTest.c @@ -29,6 +29,7 @@ #include "ellLib.h" #include "errlog.h" #include "cantProceed.h" +#include "epicsStackTrace.h" typedef struct { ELLNODE node; @@ -58,6 +59,32 @@ const char *testing = NULL; static epicsThreadOnceId onceFlag = EPICS_THREAD_ONCE_INIT; +#ifdef _WIN32 +/* + * if we return FALSE, _CrtDbgReport is called to print to file etc + * if we return TRUE, we are the only function called + */ +static int testReportHook(int reportType, char *message, int *returnValue) +{ + int nRet = 0; + switch (reportType) + { + case _CRT_ASSERT: + case _CRT_ERROR: + epicsStackTrace(); + break; + + default: + break; + } + if (returnValue) + { + *returnValue = 0; + } + return nRet; +} +#endif + static void testOnce(void *dummy) { testLock = epicsMutexMustCreate(); perlHarness = (getenv("HARNESS_ACTIVE") != NULL); @@ -68,6 +95,7 @@ static void testOnce(void *dummy) { _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR ); _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE |_CRTDBG_MODE_DEBUG ); _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR ); + _CrtSetReportHook2( _CRT_RPTHOOK_INSTALL, testReportHook ); #endif } From edc66418ac3c145dabf8f1d42b28b9d69534118c Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 7 Oct 2019 22:50:40 +0100 Subject: [PATCH 188/281] WIN32: Add symbol lookup --- configure/os/CONFIG.linux-x86.win32-x86-mingw | 2 +- .../os/CONFIG.win32-x86-mingw.win32-x86-mingw | 2 +- configure/os/CONFIG.win32-x86.win32-x86 | 2 +- modules/libcom/src/Makefile | 2 +- modules/libcom/src/log/Makefile | 2 +- modules/libcom/src/osi/os/WIN32/osdFindAddr.c | 108 ++++++++++++++++++ modules/libcom/test/Makefile | 9 ++ modules/libcom/test/epicsStackTraceTest.c | 2 +- 8 files changed, 123 insertions(+), 6 deletions(-) create mode 100644 modules/libcom/src/osi/os/WIN32/osdFindAddr.c diff --git a/configure/os/CONFIG.linux-x86.win32-x86-mingw b/configure/os/CONFIG.linux-x86.win32-x86-mingw index 150f13864..bd75f5ebd 100644 --- a/configure/os/CONFIG.linux-x86.win32-x86-mingw +++ b/configure/os/CONFIG.linux-x86.win32-x86-mingw @@ -21,4 +21,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm +OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw index 2a7827ccd..a08f19902 100644 --- a/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw +++ b/configure/os/CONFIG.win32-x86-mingw.win32-x86-mingw @@ -32,4 +32,4 @@ LOADABLE_SHRLIB_LDFLAGS = -shared \ GNU_LDLIBS_YES = # Link with system libraries -OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm +OP_SYS_LDLIBS = -lws2_32 -ladvapi32 -luser32 -lkernel32 -lwinmm -ldbghelp diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 6a5078d60..62a3ee257 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -135,7 +135,7 @@ OBJ_CXXFLAG = -Fo STATIC_CXXFLAGS_YES= -MT$(VISC_CFLAGS_DEBUG) $(BUILD_DLL_CFLAGS) STATIC_CXXFLAGS_NO= -MD$(VISC_CFLAGS_DEBUG) $(BUILD_DLL_CFLAGS) -DEPICS_CALL_DLL -STATIC_LDLIBS_YES=ws2_32.lib advapi32.lib user32.lib kernel32.lib winmm.lib +STATIC_LDLIBS_YES=ws2_32.lib advapi32.lib user32.lib kernel32.lib winmm.lib dbghelp.lib STATIC_LDLIBS_NO= STATIC_LDFLAGS= RANLIB= diff --git a/modules/libcom/src/Makefile b/modules/libcom/src/Makefile index 4a1c61e38..8ff52a74f 100644 --- a/modules/libcom/src/Makefile +++ b/modules/libcom/src/Makefile @@ -47,7 +47,7 @@ include $(LIBCOM)/yajl/Makefile # Library to build: LIBRARY=Com -Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32 +Com_SYS_LIBS_WIN32 = ws2_32 advapi32 user32 dbghelp Com_RCS = Com.rc diff --git a/modules/libcom/src/log/Makefile b/modules/libcom/src/log/Makefile index 7d7a6b620..2dcfbc516 100644 --- a/modules/libcom/src/log/Makefile +++ b/modules/libcom/src/log/Makefile @@ -19,7 +19,7 @@ iocLogServer_SRCS = iocLogServer.c iocLogServer_LIBS = Com iocLogServer_SYS_LIBS_solaris += socket -iocLogServer_SYS_LIBS_WIN32 += user32 ws2_32 +iocLogServer_SYS_LIBS_WIN32 += user32 ws2_32 dbghelp SCRIPTS_HOST = S99logServer diff --git a/modules/libcom/src/osi/os/WIN32/osdFindAddr.c b/modules/libcom/src/osi/os/WIN32/osdFindAddr.c new file mode 100644 index 000000000..5172e2638 --- /dev/null +++ b/modules/libcom/src/osi/os/WIN32/osdFindAddr.c @@ -0,0 +1,108 @@ +/*************************************************************************\ +* Copyright (C) 2017 Freddie Akeroyd +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include +#include +#define epicsExportSharedSymbols +#include "epicsStackTracePvt.h" +#include "epicsStackTrace.h" +#include "epicsString.h" +#include "epicsStdio.h" +#include "gpHash.h" + +#define MAX_SYM_SIZE 255 + +/* + * we cache a list of previously located symbols, currently just to + * avoid a memory leak in allocating sym_p->s_nam and not + * to save on a SymFromAddr() call. This was done in case libraries + * were dynamically unloaded/reloaded and the cached answer might not + * then be correct, but this may be over cautious. + */ +static struct gphPvt* symbol_table; + +typedef struct +{ + char* name; + void* value; + char* file; + char* fileAndLine; + size_t line; +} SymbolData; + +int epicsFindAddr(void *addr, epicsSymbol *sym_p) +{ + static int first_call = 1; + static HANDLE process = NULL; + DWORD64 displacement64 = 0; + DWORD displacement = 0; + SYMBOL_INFO *symbol; + IMAGEHLP_LINE64 line; + GPHENTRY* symbol_entry; + SymbolData* symbol_data; + size_t len; + if (first_call) + { + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS); + process = GetCurrentProcess(); + SymInitialize(process, NULL, TRUE); + gphInitPvt(&symbol_table, 256); /* table size must be a power of 2 in range 256 to 65536 */ + first_call = 0; + } + symbol = (SYMBOL_INFO *)calloc(sizeof(SYMBOL_INFO) + (MAX_SYM_SIZE + 1) * sizeof(char), 1); + symbol->MaxNameLen = MAX_SYM_SIZE; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + if (!SymFromAddr(process, (DWORD64)addr, &displacement64, symbol)) + { + sym_p->s_nam = 0; + sym_p->s_val = 0; + sym_p->f_nam = 0; + free(symbol); + return -1; + } + if ( (symbol_entry = gphFind(symbol_table, symbol->Name, addr)) != NULL ) + { + symbol_data = (SymbolData*)symbol_entry->userPvt; + } + else + { + symbol_entry = gphAdd(symbol_table, symbol->Name, addr); + symbol_data = (SymbolData*)calloc(sizeof(SymbolData), 1); + symbol_data->name = strdup(symbol->Name); + symbol_data->value = (void*)symbol->Address; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + if (SymGetLineFromAddr64(process, (DWORD64)addr, &displacement, &line)) + { + symbol_data->file = strdup(line.FileName); + symbol_data->line = line.LineNumber; + len = strlen(line.FileName) + 32; /* add enough for [line %lu] */ + symbol_data->fileAndLine = calloc((len + 1) * sizeof(char), 1); + epicsSnprintf(symbol_data->fileAndLine, len, "%s[line %lu]", line.FileName, (unsigned long)line.LineNumber); + } + symbol_entry->userPvt = symbol_data; + } + sym_p->s_nam = symbol_data->name; + sym_p->s_val = symbol_data->value; + sym_p->f_nam = symbol_data->fileAndLine; + free(symbol); + return 0; +} + +int epicsFindAddrGetFeatures(void) +{ +#if defined(_MINGW) +/* 64bit MINGW can lookup DLL public symbols, 32bit cannot - but we need to be a dynamic build to have a DLL to lookup */ +# if defined(_WIN64) && defined(EPICS_CALL_DLL) + return EPICS_STACKTRACE_DYN_SYMBOLS; +# else + return 0; /* only able to print addresses */ +# endif /* _WIN64 && EPICS_CALL_DLL */ +#else + return EPICS_STACKTRACE_LCL_SYMBOLS + | EPICS_STACKTRACE_GBL_SYMBOLS + | EPICS_STACKTRACE_DYN_SYMBOLS; +#endif /* _MINGW */ +} diff --git a/modules/libcom/test/Makefile b/modules/libcom/test/Makefile index 5b8ab6046..cf55760a6 100755 --- a/modules/libcom/test/Makefile +++ b/modules/libcom/test/Makefile @@ -217,8 +217,17 @@ epicsMessageQueueTest_SRCS += epicsMessageQueueTest.cpp testHarness_SRCS += epicsMessageQueueTest.cpp TESTS += epicsMessageQueueTest +# we need to build this with debug symbols in all configurations +# otherwise the test will not be able to lookup names and so fail TESTPROD_HOST += epicsStackTraceTest epicsStackTraceTest_SRCS += epicsStackTraceTest.c +ifneq ($(findstring mingw,$(T_A)),) +epicsStackTraceTest_CFLAGS_WIN32 += -g -O0 +epicsStackTraceTest_LDFLAGS_WIN32 += -g +else +epicsStackTraceTest_CFLAGS_WIN32 += -Zi +epicsStackTraceTest_LDFLAGS_WIN32 += -DEBUG +endif testHarness_SRCS += epicsStackTraceTest.c TESTS += epicsStackTraceTest diff --git a/modules/libcom/test/epicsStackTraceTest.c b/modules/libcom/test/epicsStackTraceTest.c index b89fc7836..f6c81a8f2 100644 --- a/modules/libcom/test/epicsStackTraceTest.c +++ b/modules/libcom/test/epicsStackTraceTest.c @@ -106,7 +106,7 @@ findStringOcc(const char *buf, const char *what) while ( (buf = strstr(buf, what)) ) { /* Is it just a prefix? */ ch = buf[l]; - if ( ! isalnum(ch) && '_' != ch ) { + if ( ! isalnum(ch) && '_' != ch && '.' != ch ) { rval++; } buf += l; From 73481cebcb5fd7a54f67259abbf8deebd51ee71a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 17 Oct 2019 20:10:41 -0700 Subject: [PATCH 189/281] appveyor reorder and prune Newer MSVC are more interesting, build them first. Skip 64-bit for older, and 32-bit for newer, MSVC versions. --- .appveyor.yml | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 00c27ab60..bba0292e8 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -40,16 +40,16 @@ configuration: # Environment variables: compiler toolchain environment: matrix: - - TOOLCHAIN: 10.0 - - TOOLCHAIN: 11.0 - - TOOLCHAIN: 12.0 - - TOOLCHAIN: 14.0 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLCHAIN: 2017 - - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLCHAIN: 2019 - TOOLCHAIN: mingw APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLCHAIN: 2019 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLCHAIN: 2017 + - TOOLCHAIN: 14.0 + - TOOLCHAIN: 12.0 + - TOOLCHAIN: 11.0 + - TOOLCHAIN: 10.0 # Platform: architecture platform: @@ -62,6 +62,19 @@ matrix: # VS Express installs don't have the 64 bit compiler - platform: x64 TOOLCHAIN: 10.0 + # Exclude to reduce total job runtime + # skip 64-bit for older and 32-bit for newer + - platform: x64 + TOOLCHAIN: 11.0 + - platform: x86 + TOOLCHAIN: mingw + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - platform: x86 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + TOOLCHAIN: 2019 + - platform: x86 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + TOOLCHAIN: 2017 #---------------------------------# From a34a84f19fb6c9f1e13aac95c9224059e9fffe13 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 9 Oct 2019 15:33:14 -0700 Subject: [PATCH 190/281] libcom: win32 poison TLS value --- modules/libcom/src/osi/epicsThread.cpp | 5 ++--- modules/libcom/src/osi/os/WIN32/osdThread.c | 22 ++++----------------- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/modules/libcom/src/osi/epicsThread.cpp b/modules/libcom/src/osi/epicsThread.cpp index 312d0f0fb..813f2dfd9 100644 --- a/modules/libcom/src/osi/epicsThread.cpp +++ b/modules/libcom/src/osi/epicsThread.cpp @@ -227,9 +227,8 @@ epicsThread::~epicsThread () throw () char nameBuf [256]; this->getName ( nameBuf, sizeof ( nameBuf ) ); fprintf ( stderr, - "epicsThread::~epicsThread(): " - "blocking for thread \"%s\" to exit\n", - nameBuf ); + "epicsThread::~epicsThread(): \"%s\" blocking for thread \"%s\" to exit\n", + getNameSelf(), nameBuf ); fprintf ( stderr, "was epicsThread object destroyed before thread exit ?\n"); } diff --git a/modules/libcom/src/osi/os/WIN32/osdThread.c b/modules/libcom/src/osi/os/WIN32/osdThread.c index 980d5b563..67a64bb9a 100644 --- a/modules/libcom/src/osi/os/WIN32/osdThread.c +++ b/modules/libcom/src/osi/os/WIN32/osdThread.c @@ -174,7 +174,6 @@ static win32ThreadGlobal * fetchWin32ThreadGlobal ( void ) static win32ThreadGlobal * pWin32ThreadGlobal = 0; static LONG initStarted = 0; static LONG initCompleted = 0; - int crtlStatus; LONG started; LONG done; @@ -231,7 +230,9 @@ static void epicsParmCleanupWIN32 ( win32ThreadParam * pParm ) } if ( pParm ) { - if(epicsAtomicDecrIntT(&pParm->refcnt) > 0) return; + int cnt = epicsAtomicDecrIntT(&pParm->refcnt); + if(cnt > 0) return; + assert(cnt==0); /* fprintf ( stderr, "thread %s is exiting\n", pParm->pName ); */ EnterCriticalSection ( & pGbl->mutex ); @@ -439,21 +440,6 @@ epicsShareFunc unsigned int epicsShareAPI return stackSizeTable[stackSizeClass]; } -void epicsThreadCleanupWIN32 () -{ - win32ThreadGlobal * pGbl = fetchWin32ThreadGlobal (); - win32ThreadParam * pParm; - - if ( ! pGbl ) { - fprintf ( stderr, "epicsThreadCleanupWIN32: unable to find ctx\n" ); - return; - } - - pParm = ( win32ThreadParam * ) - TlsGetValue ( pGbl->tlsIndexThreadLibraryEPICS ); - epicsParmCleanupWIN32 ( pParm ); -} - /* * epicsWin32ThreadEntry() */ @@ -487,7 +473,7 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter ) /* * CAUTION: !!!! the thread id might continue to be used after this thread exits !!!! */ - TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, 0 ); + TlsSetValue ( pGbl->tlsIndexThreadLibraryEPICS, (void*)0xdeadbeef ); epicsParmCleanupWIN32 ( pParm ); return retStat; /* this indirectly closes the thread handle */ From 370b38e4c99057b579db94123071eaf69ac52445 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 8 Oct 2019 16:51:57 -0700 Subject: [PATCH 191/281] update PVA modules --- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/pvAccess b/modules/pvAccess index 710bcde7b..7bc5bc2cb 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 710bcde7be1a10c5ca3223c9657cc5892008d39d +Subproject commit 7bc5bc2cbc41c795de242c55d56eac32d8a28116 diff --git a/modules/pvData b/modules/pvData index bff2dc9cd..df8913545 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit bff2dc9cd28fcff57fde287b3305f5f9666ee48a +Subproject commit df89135455d9d92dfd0523a950ea4ab131c320b0 diff --git a/modules/pvDatabase b/modules/pvDatabase index d33d03189..3c3f0ab7f 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit d33d03189e905f25b26f5d4faddb9baec5ee851f +Subproject commit 3c3f0ab7f13e5ae66a7396ae48fb187e7c4010d9 diff --git a/modules/pva2pva b/modules/pva2pva index c7a54de46..9c6fb5c53 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit c7a54de4697842049d3f79da6752afc3ea8d962c +Subproject commit 9c6fb5c53919b1ac29e25566989440e24745af04 diff --git a/modules/pvaClient b/modules/pvaClient index b92a3ddaa..71181afc9 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit b92a3ddaa45cea2f1cdbb061a5c62fb6f422a2b9 +Subproject commit 71181afc937cc36c9ea8339a611e762a6f00a487 From b34859fb86f22e24e52ef87aee6108a66e7ca749 Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Thu, 5 Sep 2019 17:35:00 +0200 Subject: [PATCH 192/281] rename .dbd to .dpd.pod for mbbiDirect --- src/std/rec/{mbbiDirectRecord.dbd => mbbiDirectRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{mbbiDirectRecord.dbd => mbbiDirectRecord.dbd.pod} (100%) diff --git a/src/std/rec/mbbiDirectRecord.dbd b/src/std/rec/mbbiDirectRecord.dbd.pod similarity index 100% rename from src/std/rec/mbbiDirectRecord.dbd rename to src/std/rec/mbbiDirectRecord.dbd.pod From 3ff62f4ddb3dd4c1fc8146fca5f29e7d84731b1c Mon Sep 17 00:00:00 2001 From: Joao Paulo Martins Date: Thu, 5 Sep 2019 17:36:51 +0200 Subject: [PATCH 193/281] Add converted mbbiDirect POD --- src/std/rec/mbbiDirectRecord.dbd.pod | 406 ++++++++++++++++++++++++++- 1 file changed, 405 insertions(+), 1 deletion(-) diff --git a/src/std/rec/mbbiDirectRecord.dbd.pod b/src/std/rec/mbbiDirectRecord.dbd.pod index 3fa3d8823..724cbfb55 100644 --- a/src/std/rec/mbbiDirectRecord.dbd.pod +++ b/src/std/rec/mbbiDirectRecord.dbd.pod @@ -6,8 +6,158 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 B + +The mbbiDirect record retrieves a sixteen-bit hardware value and converts it to +an array of sixteen unsigned characters, each representing a bit of the word. +These fields (B0-B9, BA-BF) are set to 1 if a bit is set, and 0 if not. + +This record's operation is similar to that of the multi-bit binary input record, +and it has many fields in common with it. This record also has two available +soft device support modules: C and C. + +=head1 L + +=over + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=back + +=item * L + +=over + +=item * L + +=item * L + +=item * L + +=back + +=back + +=begin html + +


+ +=end html + +=recordtype mbbiDirect + +=cut + recordtype(mbbiDirect) { - include "dbCommon.dbd" + +=head2 Parameter Fields + +The fields fall into the following categories: + +=over + +=item * L + +=item * L + +=item * L + +=item * L + +=item * L + +=back + +=cut + +=head3 Scan Parameters + +The mbbiDirect record has the standard fields for specifying under what +circumstances the record will be processed. These fields are listed in L. In addition, L explains how these fields are +used. Note that I/O event scanning is only supported for those card types +that interrupt. + +=cut + +=head3 Read and Convert Parameters + +The device support routines obtain the record's input from the device or link +specified in the INP field. For records that obtain their input from devices, +the INP field must contain the address of the I/O card, and the DTYP field +must specify the proper device support module. Be aware that the address format +differs according to the I/O bus used. See L
for +information on the format of hardware addresses. + +Two soft device support modules can be specified in DTYP C and +C<<< Raw Soft Channel >>>. + +C<<< Raw Soft Channel >>> reads the value into RVAL, +upon which the normal conversion process is undergone. C<<< Soft Channel >>> +reads any unsigned integer directly into VAL. For a soft mbbiDirect record, the +INP field can be a constant, a database, or a channel access link. If INP is a +constant, then the VAL is initialized to the INP value but can be changed at +run-time via dbPutField or dbPutLink. See L
for +information on how to database links. + +For records that don't use C<<< Soft Channel >>> device support, RVAL is used to +determine VAL as follows: + +=over + +=item 1. RVAL is assigned to a temporary variable I = RVAL + +=item 2. I is shifted right SHFT number of bits. + +=item 3. VAL is set equal to I. + +=back + +Each of the fields, B0-BF, represents one bit of the word. + +=fields VAL, INP, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF + +=cut + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC + +=cut + + include "dbCommon.dbd" field(VAL,DBF_USHORT) { prompt("Current Value") promptgroup("40 - Input") @@ -49,6 +199,27 @@ recordtype(mbbiDirect) { promptgroup("40 - Input") interest(1) } + +=head3 Run-time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the mbbi direct +record. They are not configurable prior to run-time. + +MASK is used by device support routine to read hardware register. Record support +sets low order NOBT bits in MASK. Device support can shift this value. + +MLST holds the value when the last monitor for value change was triggered. + +=fields NOBT, ORAW, MASK, MLST + +The following fields are used to operate the mbbiDirect record in the simulation +mode. See L for more information on these +fields. + +=fields SIOL, SVAL, SIML, SIMM, SIMS + +=cut + field(SIOL,DBF_INLINK) { prompt("Sim Input Specifctn") promptgroup("90 - Simulate") @@ -67,6 +238,20 @@ recordtype(mbbiDirect) { interest(1) menu(menuSimm) } + +=head3 Alarm Parameters + +The possible alarm conditions for multi-bit binary input direct records are the +SCAN and READ alarms. These alarms are not configurable by the user since they +are always of MAJOR severity. See L for a complete +explanation of Scan and Read alarms. No fields exist for the mbbi direct record +to have state alarms. + +L lists other fields related to a alarms that are common to all +record types. + +=cut + field(SIMS,DBF_MENU) { prompt("Sim mode Alarm Svrty") promptgroup("90 - Simulate") @@ -153,4 +338,223 @@ recordtype(mbbiDirect) { pp(TRUE) interest(1) } + +=begin html + +


+ +=end html + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM with the value of SIML if SIML type is CONSTANT +link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise +initialized if SIOL is CONSTANT or PV_LINK. + +This routine next checks to see that device support is available and a device +support read routine is defined. If either does not exist, an error message is +issued and processing is terminated. + +Clears MASK and then sets the NOBT low order bits. + +If device support includes C, it is called. + +refresh_bits is then called to refresh all the bit fields based on a hardware +value. + +=head4 process + +See next section. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will no longer be called for this +record. Thus error storms will not occur. + +=item 2. + +readValue is called. See L for information. + +=item 3. + +If PACT has been changed to TRUE, the device support read routine has started +but has not completed reading a new input value. In this case, the processing +routine merely returns, leaving PACT TRUE. + +=item 4. + +Convert. + +=over + +=item * status = read_mbbiDirect + +=item * PACT = TRUE + +=item * C is called. + +=item * If status is 0, then determine VAL + +=over + +=item * Set rval = RVAL + +=item * Shift rval right SHFT bits + +=item * Set VAL = RVAL + +=back + +=item * If status is 1, return 0 + +=item * If status is 2, set status = 0 + +=back + +=item 5. + +Check to see if monitors should be invoked. + +=over + +=item * Alarm monitors are invoked if the alarm status or severity has changed. + +=item * Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * Monitors for RVAL are checked whenever other monitors are invoked. + +=item * NSEV and NSTA are reset to 0. + +=back + +=item 6. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + +=begin html + +


+ +=end html + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each input record must have an associated set of device support routines. + +The primary responsibility of the device support routines is to obtain a new raw +input value whenever read_mbbiDirect is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, VAL, INP, RVAL, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support +C routine. If it uses MASK, it should shift it as necessary and +also give SHFT a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an IEO event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an IEO event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 read_mbbiDirect + + read_mbbiDirect(precord) + +This routine must provide a new input value. It returns the following values: + +=over + +=item * + +0: Success. A new raw value is placed in RVAL. The record support module +determines VAL from RVAL and SHFT. + +=item * + +2: Success, but don't modify VAL. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +Two soft device support modules, C<<< Soft Channel >>> and C<<< Raw Soft Channel +>>>, are provided for multi-bit binary input direct records not related to +actual hardware devices. The INP link type must be either CONSTANT, DB_LINK, or +CA_LINK. + +=head4 Soft Channel + +For this module, read_mbbiDirect always returns a value of 2, which means that +no conversion is performed. + +If the INP link type is constant, then the constant value is stored into VAL by +C, and UDF is set to FALSE. VAL can be changed via dbPut +requests. If the INP link type is PV_LINK, then dbCaAddInlink is called by +C. + +read_mbbiDirect calls recGblGetLinkValue to read the current value of VAL. + +See L for a further explanation. + +If the return status of recGblGetLinkValue is zero, then read_mbbi sets UDF to +FALSE. The status of recGblGetLinkValue is returned. + +=head4 Raw Soft Channel + +This module is like the previous except that values are read into RVAL, VAL is +computed from RVAL, and read_mbbiDirect returns a value of 0. Thus the record +processing routine will determine VAL in the normal way. + +=cut + } From c7db681e25bfc71a7407b1960ae2ad0d55e6b34b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 14 Oct 2019 15:19:41 -0400 Subject: [PATCH 194/281] rename .dbd to .dpd.pod for mbbo --- src/std/rec/{mbboRecord.dbd => mbboRecord.dbd.pod} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/std/rec/{mbboRecord.dbd => mbboRecord.dbd.pod} (100%) diff --git a/src/std/rec/mbboRecord.dbd b/src/std/rec/mbboRecord.dbd.pod similarity index 100% rename from src/std/rec/mbboRecord.dbd rename to src/std/rec/mbboRecord.dbd.pod From 5b5fd8004c517fa4221d8492f23209a31a5776e9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 19 Oct 2019 23:17:18 -0500 Subject: [PATCH 195/281] Add converted mbbo POD --- src/std/rec/mbboRecord.dbd.pod | 445 ++++++++++++++++++++++++++++++++- 1 file changed, 444 insertions(+), 1 deletion(-) diff --git a/src/std/rec/mbboRecord.dbd.pod b/src/std/rec/mbboRecord.dbd.pod index f841ba018..a71829906 100644 --- a/src/std/rec/mbboRecord.dbd.pod +++ b/src/std/rec/mbboRecord.dbd.pod @@ -6,8 +6,173 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=title Multi-Bit Binary Output Record (mbbo) + +The normal use for the mbbo record type is to send a binary value (representing +one of up to 16 states) to a Digital Output module. It is used for any device +that uses more than one contiguous bit to control it. The mbbo record can also +be used to write discrete values to other records via database or channel access +links. + +=recordtype mbbo + +=cut + recordtype(mbbo) { - include "dbCommon.dbd" + +=head2 Parameter Fields + +The record-specific fields are described below, grouped by functionality. + +=head3 Scan Parameters + +The mbbo record has the standard fields for specifying under what circumstances +it will be processed. These fields are listed in L. In addition, +L explains how these fields are used. Note that I/O +event scanning is only supported for those card types that interrupt. + +=head3 Desired Output Parameters + +The multi-bit binary output record, like all output records, must specify where +its output originates. The output mode select (OMSL) field determines whether +the output originates from another record or from database access (i.e., the +operator). When set to C<<< closed_loop >>>, the desired output is retrieved +from the link specified in the desired output (DOL) field--which can specify +either a database or channel access link--and placed into the VAL field. When +set to C<<< supervisory >>>, the DOL field is ignored and the current value of +VAL is simply written. VAL can be changed via dpPuts at run-time when OMSL is +C<<< supervisory >>>. The DOL field can also be a constant, in which case the +VAL field is initialized to the constant value. If DOL is a constant, OMSL +cannot be set to C<<< closed_loop >>>. + +The VAL field itself usually consists of an index that specifies one of the +states. The actual output written is the value of RVAL, which is converted from +VAL following the routine explained in the next section. However, records that +use the C<<< Soft Channel >>> device support module write the VAL field's value +without any conversion. + +=fields OMSL, DOL, VAL + +=head3 Convert and Write Parameters + +The device support routines write the desired output to the location specified +in the OUT field. If the record uses soft device support, OUT can contain a +constant, a database link, or a channel access link; however, if OUT is a +constant, no value will be written. + +For records that write their values to hardware devices, the OUT output link +must specify the address of the I/O card, and the DTYP field must specify +the corresponding device support module. Be aware that the address format +differs according to the I/O bus used. See L
for +information on the format of hardware addresses. + +For mbbo records that write to hardware, the value written to the output +location is the value contained in RVAL, which is converted from VAL, VAL +containing an index of one of the 16 states (0-15). RVAL is then set to the +corresponding state value, the value in one of the fields ZRVL through FFVL. +Then this value is shifted left according to the number in the SHFT field so +that the value is in the correct position for the bits being used (the SHFT +value is set by device support and is not configurable by the user). + +The state value fields ZRVL through FFVL must be configured by the user before +run-time. When the state values are not defined, the states defined (SDEF) field +is set to FALSE at initialization time by the record routines. When SDEF is +FALSE, then the record processing routine does not try to find a match, RVAL is +set equal to VAL, the bits are shifted using the number in SHFT, and the value +is written thus. + +If the OUT output link specifies a database link, channel access link, or +constant, then the DTYP field must specify either one of the two soft device +support modules-- C<<< Soft Channel >>> or C<<< Raw Soft Channel >>>. C<<< Soft +>>> C<<< Channel >>> writes the value of VAL to the output link, without any +conversion, while C<<< Raw Soft Channel >>> writes the value from RVAL after it +has undergone the above conversion. See L
for information +on specifying links. + +Note also that when a string is retrieved as the desired output, a record +support routine is provided (C<<< put_enum_str() >>>) that will check to see +if the string matches one of the strings in the ZRST through FFST fields. If a +match is found, RVAL is set equal to the corresponding state value of that +string. + +=fields OUT, DTYP, RVAL, SHFT, SDEF, ZRVL, ONVL, TWVL, THVL, FRVL, FVVL, SXVL, SVVL, EIVL, NIVL, TEVL, ELVL, TVVL, TTVL, FTVL, FFVL + +=head3 Operator Display Parameters + +These parameters are used to present meaningful data to the operator. These +fields are used to display the value and other parameters of the mbbo record +either textually or graphically. The ZRST-FFST fields contain strings describing +each of the corresponding states. The C<<< get_enum_str() >>> and +C<<< get_enum_strs() >>> record routines retrieve these strings for the +operator. C<<< get_enum_str() >>> gets the string corresponding to the value in +VAL, and C<<< get_enum_strs() >>> retrieves all the strings. + +See L for more on the record name (NAME) and +description (DESC) fields. + +=fields NAME, DESC, ZRST, ONST, TWST, THST, FRST, FVST, SXST, SVST, EIST, NIST, TEST, ELST, TVST, TTST, FTST, FFST + +=head3 Alarm Parameters + +The possible alarm conditions for multi-bit binary outputs are the SCAN, READ, +INVALID, and state alarms. The SCAN and READ alarms are called by the support +modules and are not configurable by the user, as their severity is always MAJOR. + +The IVOA field specifies an action to take from a number of possible choices +when the INVALID alarm is triggered. The IVOV field contains a value to be +written once the INVALID alarm has been triggered if C<<< Set output to IVOV >>> +has been chosen in the IVOA field. The severity of the INVALID alarm is not +configurable by the user. + +The state alarms are configured in the below severity fields. These fields have +the usual possible values for severity fields: NO_ALARM, MINOR, and MAJOR. + +The unknown state severity field (UNSV), if set to MINOR or MAJOR, triggers an +alarm when the record support routine cannot find a matching value in the state +value fields for VAL or when VAL is out of range. + +The change of state severity field (COSV) triggers an alarm when the record's +state changes, if set to MAJOR or MINOR. + +The state severity (ZRSV-FFSV) fields, when set to MAJOR or MINOR, trigger an +alarm when VAL equals the corresponding field. + +See L for a complete explanation of discrete alarms and +these fields. See L for an explanation of the IVOA +and IVOV fields. L lists other fields related to a alarms that are +common to all record types. + +=fields UNSV, COSV, IVOA, IVOV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV + +=head3 Run-Time and Simulation Mode Parameters + +These parameters are used by the run-time code for processing the multi-bit +binary output. + +MASK is used by device support routine to read the hardware register. Record +support sets low order of MASK the number of bits specified in NOBT. Device +support can shift this value. + +The LALM field implements the change of state alarm severity by holding the +value of VAL when the previous change of state alarm was issued. + +MLST holds the value when the last monitor for value change was triggered. + +SDEF is used by record support to save time if no states are defined; it is used +for converting VAL to RVAL. + +=fields NOBT, ORAW, MASK, LALM, MLST, SDEF + +The following fields are used to operate the mbbo record in the simulation mode. +See L for more information on the simulation +mode fields. + +=fields SIOL, SIML, SIMM, SIMS + +=cut + + include "dbCommon.dbd" field(VAL,DBF_ENUM) { prompt("Desired Value") promptgroup("50 - Output") @@ -497,3 +662,281 @@ recordtype(mbbo) { interest(2) } } + +=head2 Record Support + +=head3 Record Support Routines + +=head4 init_record + +This routine initializes SIMM if SIML is a constant or creates a channel access +link if SIML is PV_LINK. If SIOL is PV_LINK a channel access link is created. + +This routine next checks to see that device support is available. The routine +next checks to see if the device support write routine is defined. If either +device support or the device support write routine does not exist, an error +message is issued and processing is terminated. + +If DOL is a constant, then VAL is initialized to its value and UDF is set to +FALSE. + +MASK is cleared and then the NOBT low order bits are set. + +If device support includes C, it is called. + +init_common is then called to determine if any states are defined. If states are +defined, SDEF is set to TRUE. + +If device support returns success, VAL is then set from RVAL and UDF is set to +FALSE. + +=head4 process + +See next section. + +=head4 special + +Computes SDEF when any of the fields ZRVL,...FFVL change value. + +=head4 get_value + +Fills in the values of struct valueDes so that they refer to VAL. + +=head4 get_enum_str + +Retrieves ASCII string corresponding to VAL. + +=head4 get_enum_strs + +Retrieves ASCII strings for ZRST,...FFST. + +=head4 put_enum_str + +Checks if string matches ZRST,...FFST and if it does, sets VAL. + +=head3 Record Processing + +Routine process implements the following algorithm: + +=over + +=item 1. + +Check to see that the appropriate device support module exists. If it doesn't, +an error message is issued and processing is terminated with the PACT field +still set to TRUE. This ensures that processes will not longer be called for +this record. Thus error storms will not occur. + +=item 2. + +If PACT is FALSE + +=over + +=item * + +If DOL is DB_LINK and OMSL is CLOSED_LOOP + +=over + +=item * + +Get value from DOL + +=item * + +Set UDF to FALSE + +=item * + +Check for link alarm + +=back + +=item * + +If any state values are defined + +=over + +=item * + +If VAL E 15, then raise alarm and go to 4 + +=item * + +Else using VAL as index set RVAL = one of ZRVL,...FFVL + +=back + +=item * + +Else set RVAL = VAL + +=item * + +Shift RVAL left SHFT bits + +=back + +=item 3. + +Convert + +=over + +=item * + +If PACT is FALSE, compute RVAL + +=over + +=item * + +If VAL is 0,...,15, set RVAL from ZRVL,...,FFVL + +=item * + +If VAL out of range, set RVAL = undefined + +=back + +=item * + +Status = write_mbbo + +=back + +=item 4. + +Check alarms. This routine checks to see if the new VAL causes the alarm status +and severity to change. If so, NSEV, NSTA and LALM are set. + +=item 5. + +Check severity and write the new value. See L and L for more information. + +=item 6. + +If PACT has been changed to TRUE, the device support write output routine has +started but has not completed writing the new value. In this case, the +processing routine merely returns, leaving PACT TRUE. + +=item 7. + +Check to see if monitors should be invoked. + +=over + +=item * + +Alarm monitors are invoked if the alarm status or severity has changed. + +=item * + +Archive and value change monitors are invoked if MLST is not equal to VAL. + +=item * + +Monitors for RVAL and RBV are checked whenever other monitors are invoked. + +=item * + +NSEV and NSTA are reset to 0. + +=back + +=item 8. + +Scan forward link if necessary, set PACT FALSE, and return. + +=back + + +=head2 Device Support + +=head3 Fields Of Interest To Device Support + +Each mbbo record must have an associated set of device support routines. The +primary responsibility of the device support routines is to obtain a new raw +mbbo value whenever write_mbbo is called. The device support routines are +primarily interested in the following fields: + +=fields PACT, DPVT, NSEV, NSTA, NOBT, OUT, RVAL, RBV, MASK, SHFT + +=head3 Device Support Routines + +Device support consists of the following routines: + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 init_record + + init_record(precord) + +This routine is optional. If provided, it is called by the record support's +C routine. If MASK is used, it should be shifted if necessary and SHFT +given a value. + +=head4 get_ioint_info + + get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt) + +This routine is called by the ioEventScan system each time the record is added +or deleted from an I/O event scan list. cmd has the value (0,1) if the +record is being (added to, deleted from) an I/O event list. It must be +provided for any device type that can use the ioEvent scanner. + +=head4 write_mbbo + + write_mbbo(precord) + +This routine must output a new value. It returns the following values: + +=over + +=item * + +0: Success. + +=item * + +Other: Error. + +=back + +=head3 Device Support For Soft Records + +=head4 Soft Channel + +The C<<< Soft Channel >>> module writes the current value of VAL. + +If the OUT link type is PV_LINK, then dbCaAddInlink is called by +C. + +write_mbbo calls recGblPutLinkValue to write the current value of VAL. See +L for more information. + +=head4 Raw Soft Channel + +This module writes RVAL to the location specified in the output link. It returns +a 0. + +=cut From 00334c981c60515dad5d1ea0025314ed01897114 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 20 Oct 2019 00:20:42 -0500 Subject: [PATCH 196/281] Perl-generated HTML is UTF-8; mark it so --- src/tools/dbdToHtml.pl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/dbdToHtml.pl b/src/tools/dbdToHtml.pl index 636292a52..adf2f004a 100644 --- a/src/tools/dbdToHtml.pl +++ b/src/tools/dbdToHtml.pl @@ -130,10 +130,11 @@ my $idify; if ($::XHTML) { $podHtml = Pod::Simple::XHTML->new(); $podHtml->html_doctype(<< '__END_DOCTYPE'); - + __END_DOCTYPE + $podHtml->html_charset('UTF-8'); $podHtml->html_header_tags($podHtml->html_header_tags . "\n"); @@ -142,6 +143,8 @@ __END_DOCTYPE return $podHtml->idify($title, 1); } } else { # Fall back to HTML + $Pod::Simple::HTML::Content_decl = + q{}; $podHtml = Pod::Simple::HTML->new(); $podHtml->html_css('style.css'); From 178d5779a201a3cd28a6ee3dadc98e604bd07313 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 20 Oct 2019 00:41:50 -0500 Subject: [PATCH 197/281] Cleanup of POD documentation, unifying some things Incomplete, still lots to do in these files. --- src/std/rec/aiRecord.dbd.pod | 16 ++--- src/std/rec/biRecord.dbd.pod | 34 +++++----- src/std/rec/compressRecord.dbd.pod | 97 +++++----------------------- src/std/rec/longinRecord.dbd.pod | 80 ++--------------------- src/std/rec/longoutRecord.dbd.pod | 64 ++---------------- src/std/rec/mbbiDirectRecord.dbd.pod | 84 +----------------------- src/std/rec/mbbiRecord.dbd.pod | 96 ++------------------------- src/std/rec/mbboDirectRecord.dbd.pod | 70 +------------------- src/std/rec/permissiveRecord.dbd.pod | 46 ++----------- src/std/rec/selRecord.dbd.pod | 63 ++---------------- src/std/rec/seqRecord.dbd.pod | 60 +---------------- src/std/rec/stateRecord.dbd.pod | 42 ++---------- src/std/rec/stringinRecord.dbd.pod | 68 ++----------------- src/std/rec/stringoutRecord.dbd.pod | 62 ++---------------- src/std/rec/subArrayRecord.dbd.pod | 70 ++------------------ src/std/rec/subRecord.dbd.pod | 73 ++++----------------- src/std/rec/waveformRecord.dbd.pod | 70 ++------------------ 17 files changed, 111 insertions(+), 984 deletions(-) diff --git a/src/std/rec/aiRecord.dbd.pod b/src/std/rec/aiRecord.dbd.pod index 2973ec831..0673447ff 100644 --- a/src/std/rec/aiRecord.dbd.pod +++ b/src/std/rec/aiRecord.dbd.pod @@ -4,7 +4,7 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# in file LICENSE that is included with this distribution. #************************************************************************* =title Analog Input Record (ai) @@ -214,7 +214,7 @@ monitoring functionality. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_DOUBLE) { prompt("Current EGU Value") promptgroup("40 - Input") @@ -520,7 +520,7 @@ The individual routines are described below. =head3 Device Support Routines -=head4 long report(int level) + long report(int level) This optional routine is called by the IOC command C and is passed the report level that was requested by the user. @@ -530,7 +530,7 @@ information at higher levels, or to select different types of information with different levels. Level zero should print no more than a small summary. -=head4 long init(int after) + long init(int after) This optional routine is called twice at IOC initialization time. The first call happens before any of the C calls are made, with @@ -538,7 +538,7 @@ the integer parameter C set to 0. The second call happens after all of the C calls have been made, with C set to 1. -=head4 long init_record(aiRecord *prec) + long init_record(aiRecord *prec) This optional routine is called by the record initialization code for each ai record instance that has its DTYP field set to use this device support. @@ -555,7 +555,7 @@ C, but it is not necessary to check that condition first. This same calculation takes place in the C routine, so the implementation can usually just call that routine to perform the task. -=head4 long get_ioint_info(int cmd, aiRecord *prec, IOSCANPVT *piosl) + long get_ioint_info(int cmd, aiRecord *prec, IOSCANPVT *piosl) This optional routine is called whenever the record's SCAN field is being changed to or from the value C to find out which I/O Interrupt Scan @@ -584,7 +584,7 @@ thread. The C routine is safe to call from an interrupt service routine on embedded architectures (vxWorks and RTEMS). -=head4 long read_ai(aiRecord *prec) + long read_ai(aiRecord *prec) This essential routine is called when the record wants a new value from the addressed device. @@ -595,7 +595,7 @@ It is responsible for performing (or at least initiating) a read operation, and ... return value ... -=head4 long special_linconv(aiRecord *prec, int after) + long special_linconv(aiRecord *prec, int after) This optional routine should be provided if the record type's unit conversion features are used by the device support's C routine returning a diff --git a/src/std/rec/biRecord.dbd.pod b/src/std/rec/biRecord.dbd.pod index 2d4cc0c51..2ff7b1a93 100644 --- a/src/std/rec/biRecord.dbd.pod +++ b/src/std/rec/biRecord.dbd.pod @@ -162,7 +162,7 @@ these fields. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(INP,DBF_INLINK) { prompt("Input Specification") promptgroup("40 - Input") @@ -264,7 +264,7 @@ these fields. =head3 Record Support Routines -=head2 C + long init_record(struct dbCommon *precord, int pass); This routine initializes SIMM with the value of SIML if SIML type is a CONSTANT link or creates a channel access link if SIML type is PV_LINK. @@ -276,19 +276,19 @@ processing is terminated. If device support includes C, it is called. -=head2 C + long process(struct dbCommon *precord); -See next section. +See L below. -=head2 C + long get_enum_str(const struct dbAddr *paddr, char *pbuffer); Retrieves ASCII string corresponding to VAL. -=head2 C + long get_enum_strs(const struct dbAddr *paddr, struct dbr_enumStrs *p); Retrieves ASCII strings for ZNAM and ONAM. -=head2 C + long put_enum_str(const struct dbAddr *paddr, const char *pbuffer); Check if string matches ZNAM or ONAM, and if it does, sets VAL. @@ -296,7 +296,7 @@ Check if string matches ZNAM or ONAM, and if it does, sets VAL. Routine process implements the following algorithm: -=over 1 +=over =item 1. Check to see that the appropriate device support module exists. If it @@ -317,7 +317,7 @@ Convert. =back -=over 1 +=over =item * status = read_bi @@ -336,7 +336,7 @@ if status is 2, set status = 0 =back -=over 1 +=over =item 5. Check alarms: This routine checks to see if the new VAL causes the alarm @@ -348,7 +348,7 @@ Check if monitors should be invoked: =back -=over 1 +=over =item * Alarm monitors are invoked if the alarm status or severity has changed. @@ -364,7 +364,7 @@ NSEV and NSTA are reset to 0. =back -=over 1 +=over =item 7. Scan forward link if necessary, set PACT FALSE, and return. @@ -386,7 +386,7 @@ support routines are primarily interested in the following fields: Device support consists of the following routines: -=head4 long report(int level) + long report(int level); This optional routine is called by the IOC command C and is passed the report level that was requested by the user. @@ -396,7 +396,7 @@ information at higher levels, or to select different types of information with different levels. Level zero should print no more than a small summary. -=head4 long init(int after) + long init(int after); This optional routine is called twice at IOC initialization time. The first call happens before any of the C calls are made, with @@ -404,19 +404,19 @@ the integer parameter C set to 0. The second call happens after all of the C calls have been made, with C set to 1. -=head2 C + long init_record(struct dbCommon *precord); This routine is optional. If provided, it is called by the record support C routine. -=head2 C + long get_ioint_info(int cmd, struct dbCommon *precord, IOSCANPVT *ppvt); This routine is called by the ioEventScan system each time the record is added or deleted from an I/O event scan list. C has the value (0,1) if the record is being (added to, deleted from) and I/O event list. It must be provided for any device type that can use the ioEvent scanner. -=head2 C + long read_bi(struct dbCommon *precord); This routine must provide a new input value. It returns the following values: diff --git a/src/std/rec/compressRecord.dbd.pod b/src/std/rec/compressRecord.dbd.pod index 209e8d1f8..76a82abfe 100644 --- a/src/std/rec/compressRecord.dbd.pod +++ b/src/std/rec/compressRecord.dbd.pod @@ -4,7 +4,7 @@ # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# in file LICENSE that is included with this distribution. #************************************************************************* =title Compression Record (compress) @@ -35,46 +35,10 @@ menu(compressALG) { } recordtype(compress) { -=head2 Contents - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=back - -=back - -=begin html - -
-
-
- -=end html - =head2 Parameter Fields +The record-specific fields are described below, grouped by functionality. + =head3 Scanning Parameters The compression record has the standard fields for specifying under what @@ -232,80 +196,52 @@ SPTR points to an array that is used for array averages. WPTR is used by the dbGetlinks routines. -=begin html - -
-
-
- -=end html - =head2 Record Support -=head3 Record Support Routines (compressRecord.c) +=head3 Record Support Routines -=head4 init_record - - long (*init_record)(struct dbCommon *precord, int pass) + long init_record(struct dbCommon *precord, int pass) Space for all necessary arrays is allocated. The addresses are stored in the appropriate fields in the record. -=head4 process + long process(struct dbCommon *precord) - long (*process)(struct dbCommon *precord) +See L below. -See L - -=head4 special - - long (*special)(struct dbAddr *paddr, int after) + long special(struct dbAddr *paddr, int after) This routine is called when RSET, ALG, or N are set. It performs a reset. -=head4 cvt_dbaddr - - long (*cvt_dbaddr)(struct dbAddr *paddr) + long cvt_dbaddr(struct dbAddr *paddr) This is called by dbNameToAddr. It makes the dbAddr structure refer to the actual buffer holding the result. -=head4 get_array_info - - long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset) + long get_array_info(struct dbAddr *paddr, long *no_elements, long *offset) Obtains values from the circular buffer referenced by VAL. -=head4 put_array_info - - long (*put_array_info)(struct dbAddr *paddr, long nNew); + long put_array_info(struct dbAddr *paddr, long nNew); Writes values into the circular buffer referenced by VAL. -=head4 get_units - - long (*get_units)(struct dbAddr *paddr, char *units); + long get_units(struct dbAddr *paddr, char *units); Retrieves EGU. -=head4 get_precision - - long (*get_precision)(const struct dbAddr *paddr, long *precision); + long get_precision(const struct dbAddr *paddr, long *precision); Retrieves PREC. -=head4 get_graphic_double - - long (*get_graphic_double)(struct dbAddr *paddr, struct dbr_grDouble *p); + long get_graphic_double(struct dbAddr *paddr, struct dbr_grDouble *p); Sets the upper display and lower display limits for a field. If the field is VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower limits defined they will be used, else the upper and lower maximum values for the field type will be used. -=head4 get_control_double - - long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p); + long get_control_double(struct dbAddr *paddr, struct dbr_ctrlDouble *p); Sets the upper control and the lower control limits for a field. If the field is VAL, the limits are set to HOPR and LOPR, else if the field has upper and lower @@ -391,7 +327,7 @@ Scan forward link if necessary, set PACT FALSE, and return. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_NOACCESS) { prompt("Value") asl(ASL0) @@ -515,4 +451,3 @@ Scan forward link if necessary, set PACT FALSE, and return. interest(3) } } - diff --git a/src/std/rec/longinRecord.dbd.pod b/src/std/rec/longinRecord.dbd.pod index cbc5f5b54..4981a991f 100644 --- a/src/std/rec/longinRecord.dbd.pod +++ b/src/std/rec/longinRecord.dbd.pod @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=head1 Long Input Record (longin) +=title Long Input Record (longin) The normal use for the long input record or "longin" record is to retrieve a long integer value of up to 32 bits. Device support routines are provided to @@ -15,56 +15,6 @@ support direct interfaces to hardware. In addition, the C<<< Soft Channel >>> device module is provided to obtain input via database or channel access links or via dbPutField or dbPutLink requests. -=head1 Contents - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=back - -=back - -=begin html - -


- -=end html - =recordtype longin =cut @@ -73,21 +23,7 @@ recordtype(longin) { =head2 Parameter Fields -The fields in this record fall into the following categories: - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back +The record-specific fields are described below, grouped by functionality. =head3 Scan Parameters @@ -174,17 +110,11 @@ See L for more information on these fields. =fields SIOL, SVAL, SIML, SIMM, SIMS -=begin html - -


- -=end html - =head2 Record Support -=head3 Record Support Routines +=head3 Record Support Routines -=head4 init_record +=head4 init_record This routine initializes SIMM with the value of SIML if SIML type is CONSTANT link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise @@ -374,7 +304,7 @@ sets UDF to FALSE. read_longin returns the status of C. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_LONG) { prompt("Current value") promptgroup("40 - Input") diff --git a/src/std/rec/longoutRecord.dbd.pod b/src/std/rec/longoutRecord.dbd.pod index 5d8dd9320..d627b76ea 100644 --- a/src/std/rec/longoutRecord.dbd.pod +++ b/src/std/rec/longoutRecord.dbd.pod @@ -7,69 +7,15 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=head1 B +=title Long Output Record (longout) The normal use for the long output or "longout" record type is to store long -integer values of up to 32 bits and write them to hardware devices. The C<<< -Soft Channel >>> device support routine can also be used to write values to +integer values of up to 32 bits and write them to hardware devices. The C<<< +Soft Channel >>> device support layer can also be used to write values to other records via database or channel access links. The OUT field determines how the record is used. The record supports alarm limits and graphics and control limits. -=head1 L - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=back - -=back - -=begin html - -


- -=end html - =recordtype longout =cut @@ -149,7 +95,7 @@ and database links. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_LONG) { prompt("Desired Output") promptgroup("50 - Output") @@ -243,7 +189,7 @@ HYST field contains the alarm deadband around each limit alarm. See the See L for a complete explanation of alarms and these fields. For an explanation of the IVOA and IVOV fields, see L. L lists other fields related to a alarms that are common -to all record types. +to all record types. =fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV diff --git a/src/std/rec/mbbiDirectRecord.dbd.pod b/src/std/rec/mbbiDirectRecord.dbd.pod index 724cbfb55..082f609cf 100644 --- a/src/std/rec/mbbiDirectRecord.dbd.pod +++ b/src/std/rec/mbbiDirectRecord.dbd.pod @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=head1 B +=title Multi-Bit Binary Input Direct Record (mbbiDirect) The mbbiDirect record retrieves a sixteen-bit hardware value and converts it to an array of sixteen unsigned characters, each representing a bit of the word. @@ -17,60 +17,6 @@ This record's operation is similar to that of the multi-bit binary input record, and it has many fields in common with it. This record also has two available soft device support modules: C and C. -=head1 L - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=back - -=back - -=begin html - -


- -=end html - =recordtype mbbiDirect =cut @@ -79,23 +25,7 @@ recordtype(mbbiDirect) { =head2 Parameter Fields -The fields fall into the following categories: - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=cut +The record-specific fields are described below, grouped by functionality. =head3 Scan Parameters @@ -105,8 +35,6 @@ Fields>. In addition, L explains how these fields are used. Note that I/O event scanning is only supported for those card types that interrupt. -=cut - =head3 Read and Convert Parameters The device support routines obtain the record's input from the device or link @@ -144,8 +72,6 @@ Each of the fields, B0-BF, represents one bit of the word. =fields VAL, INP, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF -=cut - =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator. @@ -339,12 +265,6 @@ record types. interest(1) } -=begin html - -


- -=end html - =head2 Record Support =head3 Record Support Routines diff --git a/src/std/rec/mbbiRecord.dbd.pod b/src/std/rec/mbbiRecord.dbd.pod index 2bbda6686..5fa977714 100644 --- a/src/std/rec/mbbiRecord.dbd.pod +++ b/src/std/rec/mbbiRecord.dbd.pod @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=head1 B +=title Multi-Bit Binary Input Record (mbbi) The normal use for the multi-bit binary input record is to read contiguous, multiple bit inputs from hardware. The binary value represents a state from a @@ -25,58 +25,6 @@ are provided: C<<< Soft Channel >>> allows VAL to be an arbitrary unsigned short integer. C<<< Raw Soft Channel >>> reads the value into RVAL just like normal device support modules. -=head1 L - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=back - -=back - -=begin html - -


- -=end html - =recordtype mbbi =cut @@ -85,23 +33,7 @@ recordtype(mbbi) { =head2 Parameter Fields -The multi-bit binary input fields fall into the following categories: - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back +The record-specific fields are described below, grouped by functionality. =head3 Scan Parameters @@ -121,7 +53,7 @@ differs according to the I/O bus used. See L
for information on the format of hardware addresses. Two soft device support modules can be specified in DTYP C and -C<<< Raw Soft Channel >>>. +C<<< Raw Soft Channel >>>. C<<< Raw Soft Channel >>> reads the value into RVAL, upon which the normal conversion process is undergone. C<<< Soft Channel >>> @@ -165,7 +97,7 @@ Each of the fields, ZRVL-FFVL, represents one of the possible sixteen states Alternatively, the input value can be read as a string, in which case, a match is sought with one of the strings specified in the ZRST-FFST fields. Then RVAL is set equal to the corresponding value for that string, and the conversion -process occurs. +process occurs. =fields VAL, INP, MASK, NOBT, RVAL, SHFT, ZRVL, ONVL, TWVL, THVL, FRVL, FVVL, SXVL, SVVL, EIVL, NIVL, TEVL, ELVL, TVVL, TTVL, FTVL, FFVL @@ -186,7 +118,7 @@ description (DESC) fields. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_ENUM) { prompt("Current Value") promptgroup("40 - Input") @@ -478,7 +410,7 @@ state occurs, if set to MAJOR or MINOR. The other fields, when set to MAJOR or MINOR, trigger an alarm when VAL equals the corresponding state. See the See L for a complete explanation of discrete alarms and these fields. L lists other -fields related to a alarms that are common to all record types. +fields related to a alarms that are common to all record types. =fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV @@ -709,14 +641,6 @@ See L for more information on these fields. menu(menuAlarmSevr) } -=pod - -=begin html - -


- -=end html - =head2 Record Support =head3 Record Support Routines @@ -869,7 +793,6 @@ Scan forward link if necessary, set PACT FALSE, and return. =back - =head2 Device Support =head3 Fields Of Interest To Device Support @@ -882,12 +805,6 @@ primarily interested in the following fields: =fields PACT, DPVT, UDF, NSEV, NSTA, NOBT, VAL, INP, RVAL, MASK, SHFT -=begin html - -


- -=end html - =head3 Device Support Routines Device support consists of the following routines: @@ -979,7 +896,6 @@ This module is like the previous except that values are read into RVAL, VAL is computed from RVAL, and read_mbbi returns a value of 0. Thus the record processing routine will determine VAL in the normal way. - =cut } diff --git a/src/std/rec/mbboDirectRecord.dbd.pod b/src/std/rec/mbboDirectRecord.dbd.pod index e730bc854..40a5532e9 100644 --- a/src/std/rec/mbboDirectRecord.dbd.pod +++ b/src/std/rec/mbboDirectRecord.dbd.pod @@ -7,7 +7,7 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=head1 B +=title Multi-Bit Binary Output Direct Record (mbboDirect) The mbboDirect record performs the opposite function to that of the mbbiDirect record. It accumulates bits (in the fields B0 - BF) as unsigned characters, and @@ -15,56 +15,6 @@ converts them to a word which is then written out to hardware. If a bit field is non-zero, it is interpreted as a binary 1. On the other hand, if it is zero, it is interpreted as a binary 0. -=head1 L - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=back - -=back - -=begin html - -


- -=end html - =recordtype mbboDirect =cut @@ -73,21 +23,7 @@ recordtype(mbboDirect) { =head2 Parameter Fields -The mbboDirect record's fields fall into the following categories: - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back +The record-specific fields are described below, grouped by functionality. =head3 Scan Parameters @@ -153,7 +89,7 @@ description (DESC) fields. =cut - include "dbCommon.dbd" + include "dbCommon.dbd" field(VAL,DBF_USHORT) { prompt("Word") promptgroup("50 - Output") diff --git a/src/std/rec/permissiveRecord.dbd.pod b/src/std/rec/permissiveRecord.dbd.pod index bdcecb5e7..5ad979f74 100644 --- a/src/std/rec/permissiveRecord.dbd.pod +++ b/src/std/rec/permissiveRecord.dbd.pod @@ -7,52 +7,14 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=head1 Permissive Record (permissive) +=title Permissive Record (permissive) The permissive record is for communication between a server and a client. An example would be a sequence program server and an operator interface client. By using multiple permissive records a sequence program can communicate its current state to the client. -B - -=head2 Contents - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L - -=item * L - -=item * L - -=back - -=item * L - -=over - -=item * L - -=back - -=back - -=begin html - -
-
-
- -=end html +B =recordtype permissive @@ -63,6 +25,8 @@ recordtype(permissive) { =head2 Parameter Fields +The record-specific fields are described below, grouped by functionality. + =head3 Scan Parameters The permissive record has the standard fields for specifying under what @@ -150,7 +114,7 @@ OLFG. =head2 Record Support -=head3 Record Support Routines (permissiveRecord.c) +=head3 Record Support Routines =head4 process diff --git a/src/std/rec/selRecord.dbd.pod b/src/std/rec/selRecord.dbd.pod index 9e49745cc..fe8301db6 100644 --- a/src/std/rec/selRecord.dbd.pod +++ b/src/std/rec/selRecord.dbd.pod @@ -7,59 +7,13 @@ # in file LICENSE that is included with this distribution. #************************************************************************* -=pod - -=head1 Select Record (sel) +=title Select Record (sel) The select record computes a value based on input obtained from up to 12 locations. The selection algorithm can be one of the following: C<<< Specified >>>, C<<< High Signal >>>, C<<< Low Signal >>>, C<<< Median Signal >>>. Each input can be a constant, a database link, or a channel access link. -=head2 Contents - -=over - -=item * L - -=over - -=item * L - -=item * L - -=item * L Release Manager -

For each external submodule, check if the module's release version - number (and SHRLIB_VERSION setting) has been updated if appropriate, - and that its Release Notes have been updated to cover any changes. - Commit any fixes and tag the module if that hasn't already been - done.

-

Update all external submodules on the Base-7.0 branch and - commit.

+

For each external submodule in turn (assuming it has not been tagged + yet):

+
    +
  1. Check that the module's Release Notes have been updated to cover + all changes; add items as necessary, and set the module version + number and release date if appropriate. Convert to HTML and view in + a browser to check the formatting: +
    + cd base-7.0/modules/<module>/documentation
    + pandoc -f gfm -t html -o RELEASE_NOTES.html RELEASE_NOTES.md +
    + Commit changes (don't push yet).
  2. + +
  3. 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).
  4. + +
  5. Tag the module: +
    + git tag -m 'ANJ: Tag for EPICS 7.0.3.1' <module-version> +
    +
  6. + +
  7. Update the git submodule on the Base-7.0 branch to the + newly-tagged version, but don't commit yet: +
    + cd base-7.0/modules
    + git add <module>
    + git submodule status --cached +
    +
  8. + +
  9. Edit the module's release version file + configure/CONFIG_module_VERSION and its top-level + Doxyfile; increment the MAINTENANCE_VERSION, set + the DEVELOPMENT_FLAG value to 1, and update the + PROJECT_NUMBER string, appending -dev to the new + module version number. Commit changes.
  10. + +
  11. Push commits and the new tag to the submodule's GitHub repository: +
    + cd base-7.0/modules/<module>
    + git push --follow-tags upstream master +
    +
  12. + +
+

Commit all the submodule updates to the 7.0 branch.

+ Release Manager - Edit and commit changes to the EPICS Base version number file and - these embedded module version files: + + Edit the main EPICS Base version file and the built-in module version + files:
    -
  • configure/CONFIG_BASE_VERSION
  • -
  • modules/libcom/configure/CONFIG_LIBCOM_VERSION
  • -
  • modules/ca/configure/CONFIG_CA_VERSION
  • -
  • modules/database/configure/CONFIG_DATABASE_VERSION
  • +
  • configure/CONFIG_BASE_VERSION
  • +
  • configure/CONFIG_LIBCOM_VERSION
  • +
  • configure/CONFIG_CA_VERSION
  • +
  • configure/CONFIG_DATABASE_VERSION
-

Version numbers should be set according to the level of changes - made since the last release. Note that the MAINTENANCE_VERSION or - PATCH_LEVEL value should have been incremented after the previous - release tag was applied.

-

Set all DEVELOPMENT_FLAG values to 0 and EPICS_DEV_SNAPSHOT to the - empty string.

- +

Version numbers should be set according to the level of changes made + since the last release. Note that the MAINTENANCE_VERSION or + PATCH_LEVEL value should have been incremented after the + previous release tag was applied. Set all DEVELOPMENT_FLAG + values to 0 and EPICS_DEV_SNAPSHOT to the empty string.

+

Commit these changes (don't push).

+ @@ -310,27 +355,28 @@ starting at Release Approval.

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

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

+ Release Manager - Edit and commit changes to the EPICS Base version number file and - the embedded module version files as follows: + Edit the main EPICS Base version file and the built-in module version + files:
    -
  • configure/CONFIG_BASE_VERSION
  • -
  • modules/libcom/configure/CONFIG_LIBCOM_VERSION
  • -
  • modules/ca/configure/CONFIG_CA_VERSION
  • -
  • modules/database/configure/CONFIG_DATABASE_VERSION
  • +
  • configure/CONFIG_BASE_VERSION
  • +
  • configure/CONFIG_LIBCOM_VERSION
  • +
  • configure/CONFIG_CA_VERSION
  • +
  • configure/CONFIG_DATABASE_VERSION

Version numbers should be set for the next expected patch/maintenance - release by incrementing the MAINTENANCE_VERSION or PATCH_LEVEL - value in each file.

-

Set all DEVELOPMENT_FLAG values to 1 and EPICS_DEV_SNAPSHOT to - "-DEV".

+ release by incrementing the MAINTENANCE_VERSION or PATCH_LEVEL value + in each file. Set all DEVELOPMENT_FLAG values to 1 and + EPICS_DEV_SNAPSHOT to "-DEV".

+

Commit these changes (don't push).

From 34834dfe973a577f342503441e7b33b7fe322de5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Nov 2019 14:08:44 -0500 Subject: [PATCH 219/281] Clear development flags for 7.0.3.1 --- configure/CONFIG_BASE_VERSION | 4 ++-- configure/CONFIG_CA_VERSION | 2 +- configure/CONFIG_DATABASE_VERSION | 2 +- configure/CONFIG_LIBCOM_VERSION | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 4e61e48cd..4351a13bb 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -56,8 +56,8 @@ 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 +EPICS_DEV_SNAPSHOT= +#EPICS_DEV_SNAPSHOT=-DEV #EPICS_DEV_SNAPSHOT=-pre1 #EPICS_DEV_SNAPSHOT=-pre1-DEV #EPICS_DEV_SNAPSHOT=-pre2 diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index 57bcd89ac..2ab2f1d0f 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -6,7 +6,7 @@ EPICS_CA_MAINTENANCE_VERSION = 5 # Development flag, set to zero for release versions -EPICS_CA_DEVELOPMENT_FLAG = 1 +EPICS_CA_DEVELOPMENT_FLAG = 0 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION index ebf04180a..bd44581e8 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -6,7 +6,7 @@ EPICS_DATABASE_MAINTENANCE_VERSION = 5 # 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 5953c7175..1a9e56cb0 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -6,7 +6,7 @@ EPICS_LIBCOM_MAINTENANCE_VERSION = 6 # Development flag, set to zero for release versions -EPICS_LIBCOM_DEVELOPMENT_FLAG = 1 +EPICS_LIBCOM_DEVELOPMENT_FLAG = 0 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 From 8734863f69aa2b16bdc2752e3cb662fd186aee4b Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Nov 2019 14:11:29 -0500 Subject: [PATCH 220/281] Incr version and set snapshot/development flags --- configure/CONFIG_BASE_VERSION | 6 +++--- configure/CONFIG_CA_VERSION | 4 ++-- configure/CONFIG_DATABASE_VERSION | 4 ++-- configure/CONFIG_LIBCOM_VERSION | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/configure/CONFIG_BASE_VERSION b/configure/CONFIG_BASE_VERSION index 4351a13bb..fbe1545a2 100644 --- a/configure/CONFIG_BASE_VERSION +++ b/configure/CONFIG_BASE_VERSION @@ -52,12 +52,12 @@ EPICS_MODIFICATION = 3 # 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 = 2 # 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 +#EPICS_DEV_SNAPSHOT= +EPICS_DEV_SNAPSHOT=-DEV #EPICS_DEV_SNAPSHOT=-pre1 #EPICS_DEV_SNAPSHOT=-pre1-DEV #EPICS_DEV_SNAPSHOT=-pre2 diff --git a/configure/CONFIG_CA_VERSION b/configure/CONFIG_CA_VERSION index 2ab2f1d0f..c75b4e421 100644 --- a/configure/CONFIG_CA_VERSION +++ b/configure/CONFIG_CA_VERSION @@ -2,11 +2,11 @@ EPICS_CA_MAJOR_VERSION = 4 EPICS_CA_MINOR_VERSION = 13 -EPICS_CA_MAINTENANCE_VERSION = 5 +EPICS_CA_MAINTENANCE_VERSION = 6 # Development flag, set to zero for release versions -EPICS_CA_DEVELOPMENT_FLAG = 0 +EPICS_CA_DEVELOPMENT_FLAG = 1 # Immediately after a release the MAINTENANCE_VERSION # will be incremented and the DEVELOPMENT_FLAG set to 1 diff --git a/configure/CONFIG_DATABASE_VERSION b/configure/CONFIG_DATABASE_VERSION index bd44581e8..21ac836b0 100644 --- a/configure/CONFIG_DATABASE_VERSION +++ b/configure/CONFIG_DATABASE_VERSION @@ -2,11 +2,11 @@ EPICS_DATABASE_MAJOR_VERSION = 3 EPICS_DATABASE_MINOR_VERSION = 17 -EPICS_DATABASE_MAINTENANCE_VERSION = 5 +EPICS_DATABASE_MAINTENANCE_VERSION = 6 # 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 1a9e56cb0..3def716cb 100644 --- a/configure/CONFIG_LIBCOM_VERSION +++ b/configure/CONFIG_LIBCOM_VERSION @@ -2,11 +2,11 @@ EPICS_LIBCOM_MAJOR_VERSION = 3 EPICS_LIBCOM_MINOR_VERSION = 17 -EPICS_LIBCOM_MAINTENANCE_VERSION = 6 +EPICS_LIBCOM_MAINTENANCE_VERSION = 7 # 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 From 98e53671260b50b66ff31d8181ae123342097dd7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Nov 2019 14:11:51 -0500 Subject: [PATCH 221/281] Update submodules after release --- modules/normativeTypes | 2 +- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pvDatabase | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/normativeTypes b/modules/normativeTypes index 1250a3c23..6d41566b4 160000 --- a/modules/normativeTypes +++ b/modules/normativeTypes @@ -1 +1 @@ -Subproject commit 1250a3c236f0aa92e0b5bd73647fd71d8a09360d +Subproject commit 6d41566b40a3f20582f1b37dbf4557bfdf5da674 diff --git a/modules/pvAccess b/modules/pvAccess index 47e6f61f0..a01869bbd 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 47e6f61f049c273ee74dac7a6142ed2734b79140 +Subproject commit a01869bbd0d4783346f8fd61072e8816b074ea73 diff --git a/modules/pvData b/modules/pvData index 828506720..ca2ae0d0e 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 828506720c5204301f71078652ab799ef2d7b2b9 +Subproject commit ca2ae0d0e7784f38f1f584431b7a6518c91bcc42 diff --git a/modules/pvDatabase b/modules/pvDatabase index 0c92f0774..80baccfd9 160000 --- a/modules/pvDatabase +++ b/modules/pvDatabase @@ -1 +1 @@ -Subproject commit 0c92f077498aee1b3d4340f60398e88e1054dee2 +Subproject commit 80baccfd9cef394771bde679cee8e047e86cca0f diff --git a/modules/pva2pva b/modules/pva2pva index 3024f9fb0..21ae75486 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 3024f9fb0cabee6469ad2f1d685a1a38b8c43cbf +Subproject commit 21ae7548696f27b5333e3d669da908bd41afd3a5 diff --git a/modules/pvaClient b/modules/pvaClient index b724b7262..5961c8347 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit b724b726249f297f800ec0649da987036da68fce +Subproject commit 5961c834773d6aecc51ac33601a93f04658a1adb From 6d8bf7c8ef02e9dfe024f2632ea27de11f583f46 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 1 Nov 2019 14:36:34 -0500 Subject: [PATCH 222/281] Update checklist for next release --- documentation/ReleaseChecklist.html | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/documentation/ReleaseChecklist.html b/documentation/ReleaseChecklist.html index 260b765e4..0a80c7cba 100644 --- a/documentation/ReleaseChecklist.html +++ b/documentation/ReleaseChecklist.html @@ -147,17 +147,17 @@ starting at Release Approval.

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

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

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

    Tag the epics-base module in Git:
    cd base-7.0
    - git tag -m 'ANJ: Tagged for 7.0.3.1' R7.0.3.1 + git tag -m 'ANJ: Tagged for 7.0.3.2' R7.0.3.2

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

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

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

    Upload the tar file and its .asc signature file to the epics-controls web-server.
    - scp base-7.0.3.1.tar.gz base-7.0.3.1.tar.gz.asc epics-controls:download/base
    + scp base-7.0.3.2.tar.gz base-7.0.3.2.tar.gz.asc epics-controls:download/base
    From 961dd2bc5de9f197d7df3b8d23487b4a99df33c9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 11 Nov 2019 11:29:03 -0600 Subject: [PATCH 223/281] Don't check empty (overridden) RELEASE definitions Bug reported by Dirk Zimoch --- src/tools/convertRelease.pl | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/tools/convertRelease.pl b/src/tools/convertRelease.pl index b80ae6ff7..97fbc1899 100644 --- a/src/tools/convertRelease.pl +++ b/src/tools/convertRelease.pl @@ -242,24 +242,26 @@ sub checkRelease { my $latest = AbsPath($macros{$app}); my %paths = ($latest => $app); foreach $app (@modules) { - my $path = AbsPath($macros{$app}); + my $val = $macros{$app}; + next if $val eq ''; + my $path = AbsPath($val); if ($path ne $latest && exists $paths{$path}) { my $prev = $paths{$path}; print "\n" unless ($status); print "This application's RELEASE file(s) define\n"; - print "\t$app = $macros{$app}\n"; - print "after but not adjacent to\n\t$prev = $macros{$prev}\n"; + print "\t$app = $val\n"; + print "and\n\t$prev = $macros{$prev}\n"; print "both of which resolve to $path\n" - if $path ne $macros{$app} || $path ne $macros{$prev}; + if $path ne $val || $path ne $macros{$prev}; $status = 2; } $paths{$path} = $app; $latest = $path; } if ($status == 2) { - print "Module definitions that share paths must be grouped together.\n"; - print "Either remove a definition, or move it to a line immediately\n"; - print "above or below the other(s).\n"; + print "Module definitions that share the same path must have their\n"; + print "first definitions grouped together. Either remove a module,\n"; + print "or arrange them so all those with that path are adjacent.\n"; print "Any non-module definitions belong in configure/CONFIG_SITE.\n"; $status = 1; } From 41d86ecd7a1577ac227963fb96203c34a7b72c16 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 11 Nov 2019 11:30:46 -0600 Subject: [PATCH 224/281] Add a document containing Record Reference links --- documentation/RecordReference.md | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 documentation/RecordReference.md diff --git a/documentation/RecordReference.md b/documentation/RecordReference.md new file mode 100644 index 000000000..941d6d97b --- /dev/null +++ b/documentation/RecordReference.md @@ -0,0 +1,48 @@ +# Record Reference Documentation + +The following documentation for the record types and menus include with Base was converted from the old EPICS Wiki pages and updated. This list does not include all of the available record types as some have not been documented yet. + +## Record Types + +* [Analog Input Record (ai)](aiRecord.html) +* [Analog Output Record (ao)](aoRecord.html) +* [Array Subroutine Record (aSub)](aSubRecord.html) +* [Binary Input Record (bi)](biRecord.html) +* [Binary Output Record (bo)](boRecord.html) +* [Calculation Output Record (calcout)](calcoutRecord.html) +* [Calculation Record (calc)](calcRecord.html) +* [Compression Record (compress)](compressRecord.html) +* [Data Fanout Record (dfanout)](dfanoutRecord.html) +* [Event Record (event)](eventRecord.html) +* [Fanout Record (fanout)](fanoutRecord.html) +* [Long Input Record (longin)](longinRecord.html) +* [Long Output Record (longout)](longoutRecord.html) +* [Multi-Bit Binary Input Direct Record (mbbiDirect)](mbbiDirectRecord.html) +* [Multi-Bit Binary Input Record (mbbi)](mbbiRecord.html) +* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html) +* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html) +* [Permissive Record (permissive)](permissiveRecord.html) +* [Select Record (sel)](selRecord.html) +* [Sequence Record (seq)](seqRecord.html) +* [State Record (state)](stateRecord.html) +* [String Input Record (stringin)](stringinRecord.html) +* [String Output Record (stringout)](stringoutRecord.html) +* [Sub-Array Record (subArray)](subArrayRecord.html) +* [Subroutine Record (sub)](subRecord.html) +* [Waveform Record (waveform)](waveformRecord.html) + +## Menu Definitions + +* [Alarm Severity Menu](menuAlarmSevr.html) +* [Alarm Status Menu](menuAlarmStat.html) +* [Analog Conversions Menu](menuConvert.html) +* [Field Type Menu](menuFtype.html) +* [Invalid Value Output Action Menu](menuIvoa.html) +* [Output Mode Select Menu](menuOmsl.html) +* [Scan Menu](menuScan.html) +* [Simulation Mode Menu](menuSimm.html) +* [Yes/No Menu](menuYesNo.html) + +## Corrections and Updates + +Corrections to these documents can be submitted as patch files to the EPICS core developers, or as merge requests or pull requests to the 3.15 branch of epics-base. The document sources can be found in the `src/std/rec` and `src/ioc/db` directories in files with extension `.dbd.pod`. The documentation format is an extended version of Perl POD, run `perldoc pod` for details. From b37bfe3ed0d2f272efc1f88cf3e3020967756b01 Mon Sep 17 00:00:00 2001 From: Martin Konrad Date: Tue, 12 Nov 2019 12:12:47 -0500 Subject: [PATCH 225/281] Retire unused epicsExcept.h Due to a syntax error this header has been unusable since 2001 (since 34ea7db15bacb70ed34a556619c30dbecc453ee1), and no one noticed. Let's remove it. --- src/libCom/cppStd/Makefile | 1 - src/libCom/cppStd/epicsExcept.h | 71 --------------------------------- 2 files changed, 72 deletions(-) delete mode 100644 src/libCom/cppStd/epicsExcept.h diff --git a/src/libCom/cppStd/Makefile b/src/libCom/cppStd/Makefile index 989b87eb0..23834e75a 100644 --- a/src/libCom/cppStd/Makefile +++ b/src/libCom/cppStd/Makefile @@ -9,6 +9,5 @@ SRC_DIRS += $(LIBCOM)/cppStd INC += epicsAlgorithm.h -INC += epicsExcept.h INC += epicsMemory.h diff --git a/src/libCom/cppStd/epicsExcept.h b/src/libCom/cppStd/epicsExcept.h deleted file mode 100644 index e68999735..000000000 --- a/src/libCom/cppStd/epicsExcept.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ -// Author: Andrew Johnson & Jeff Hill -// Date: December 2000 - -#ifndef __EPICS_EXCEPT_H__ -#define __EPICS_EXCEPT_H__ - -#define epicsThrowHere(exc) \ - throw locationException(exc, __FILE__, __LINE__) - -class sourceLocation { -public: // Functions - sourceLocation(const char *fileName, int lineNumber); -// sourceLocation(const sourceLocation&); Copy constructable -// sourceLocation& operator=(const sourceLocation&); Assignable - - const char *fileName() const; - int lineNumber() const; - -private: // Hide compiler-generated member functions - sourceLocation(); // default constructor - -private: // Data - const char *file; - int line; -}; - -template -class locationException : public T, public sourceLocation { -public: - locationException(const T& exc, const char *fileName, int lineNumber); -}; - - -/* Example: - * if (status) epicsThrowHere(std::logic_error("operation failed!")); - * try { ... } catch(sourceLocation& where) { ... } - */ - -// END OF DECLARATIONS - -// INLINE FUNCTIONS - -// sourceFileLocation -inline sourceLocation::sourceLocation (const char *fileName, int lineNumber) : - file(fileName), line(lineNumber) {} - -inline const char* sourceLocation::fileName () const { - return this->file; -} - -inline int sourceLocation::lineNumber () const { - return this->line; -} - -// locationException -template -inline locationException::locationException - (const char *fileName, int lineNumber, const E& exc) : - T(exc), sourceLocation(fileName, lineNumber) {} - - -#endif // __EPICS_EXCEPT_H__ From a10379327c921e72cd22b3a2441a04456b9b4be9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 12 Nov 2019 16:14:39 -0600 Subject: [PATCH 226/281] Replace broken cleandirs recipe --- configure/RULES_TOP | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/configure/RULES_TOP b/configure/RULES_TOP index 3d60b5af8..4db1ace66 100644 --- a/configure/RULES_TOP +++ b/configure/RULES_TOP @@ -24,24 +24,19 @@ UNINSTALL_DIRS += $(INSTALL_DBD) $(INSTALL_INCLUDE) $(INSTALL_DOC) \ uninstallDirs: $(RMDIR) $(UNINSTALL_DIRS) +EMPTY_INSTALL_DIRS = \ + $(if $(wildcard $(INSTALL_LOCATION_BIN)/*),,$(INSTALL_LOCATION_BIN)) \ + $(if $(wildcard $(INSTALL_LOCATION_LIB)/*),,$(INSTALL_LOCATION_LIB)) uninstall: archuninstall uninstallDirs + $(RMDIR) $(EMPTY_INSTALL_DIRS) -archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS)) | cleandirs +archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS)) archPart = $(word 2, $(subst $(DIVIDER), ,$@)) uninstall$(DIVIDER)%: $(RMDIR) $(INSTALL_LOCATION_BIN)/$(archPart) $(RMDIR) $(INSTALL_LOCATION_LIB)/$(archPart) -cleandirs: - @$(NOP) -ifeq ($(wildcard $(INSTALL_LOCATION_BIN)/*),) - $(RMDIR) $(INSTALL_LOCATION_BIN) -endif -ifeq ($(wildcard $(INSTALL_LOCATION_LIB)/*),) - $(RMDIR) $(INSTALL_LOCATION_LIB) -endif - help: @echo "Usage: gnumake [options] [target] ..." @@ -75,7 +70,7 @@ help: @echo "Indiv. object targets are supported by O. level Makefile .e.g" @echo " xxxRecord.o" -.PHONY: cleandirs distclean cvsclean realuninstall archuninstall uninstallDirs +.PHONY: distclean cvsclean realuninstall archuninstall uninstallDirs .PHONY: uninstall help # Include /cfg/TOP_RULES* files from tops defined in RELEASE* files From 7eee262486a9adef9dbb26b6ab59c2145a8bf43d Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 12 Nov 2019 16:16:02 -0600 Subject: [PATCH 227/281] Shorten/simplify uninstall recipes --- configure/RULES_TOP | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/configure/RULES_TOP b/configure/RULES_TOP index 4db1ace66..176454187 100644 --- a/configure/RULES_TOP +++ b/configure/RULES_TOP @@ -16,8 +16,7 @@ cvsclean: $(PERL) $(CVSCLEAN) realuninstall: uninstallDirs - $(RMDIR) $(INSTALL_LOCATION_BIN) - $(RMDIR) $(INSTALL_LOCATION_LIB) + $(RMDIR) $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB) UNINSTALL_DIRS += $(INSTALL_DBD) $(INSTALL_INCLUDE) $(INSTALL_DOC) \ $(INSTALL_HTML) $(INSTALL_TEMPLATES) $(INSTALL_DB) $(DIRECTORY_TARGETS) @@ -32,10 +31,9 @@ uninstall: archuninstall uninstallDirs archuninstall: $(addprefix uninstall$(DIVIDER),$(BUILD_ARCHS)) -archPart = $(word 2, $(subst $(DIVIDER), ,$@)) uninstall$(DIVIDER)%: - $(RMDIR) $(INSTALL_LOCATION_BIN)/$(archPart) - $(RMDIR) $(INSTALL_LOCATION_LIB)/$(archPart) + $(RMDIR) $(addsuffix /$(subst uninstall$(DIVIDER),,$@), \ + $(INSTALL_LOCATION_BIN) $(INSTALL_LOCATION_LIB)) help: From 76b9461ee82a65d7cdd28b487febe20df018cae2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 12 Nov 2019 18:42:02 -0800 Subject: [PATCH 228/281] logClient windows needs SOCK_E* --- modules/libcom/src/log/logClient.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/log/logClient.c b/modules/libcom/src/log/logClient.c index 9a09ef7b7..44883e3ed 100644 --- a/modules/libcom/src/log/logClient.c +++ b/modules/libcom/src/log/logClient.c @@ -246,7 +246,7 @@ void epicsShareAPI logClientFlush ( logClientId id ) /* NOOP on Windows, fails on vxWorks */ errno = 0; status = send ( pClient->sock, NULL, 0, 0 ); - if (!(errno == ECONNRESET || errno == EPIPE)) status = 0; + if (!(errno == SOCK_ECONNRESET || errno == SOCK_EPIPE)) status = 0; } if ( status < 0 ) { From 3e7ad9a86fa1bceb40ea7e470c996d7245c7ad8a Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 5 Dec 2018 09:22:32 -0800 Subject: [PATCH 229/281] rtems_init cleanup Remove unnecessary (as of RTEMS 4.9) prototypes Remove unused *Fatal constify string contant --- modules/libcom/RTEMS/rtems_init.c | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/modules/libcom/RTEMS/rtems_init.c b/modules/libcom/RTEMS/rtems_init.c index 8b4ab38b0..808aeac9d 100644 --- a/modules/libcom/RTEMS/rtems_init.c +++ b/modules/libcom/RTEMS/rtems_init.c @@ -52,8 +52,6 @@ /* * Prototypes for some functions not in header files */ -void tzset(void); -int fileno(FILE *); int main(int argc, char **argv); static void @@ -103,26 +101,6 @@ LogFatal (const char *msg, ...) delayedPanic (msg); } -/* - * Log RTEMS error and terminate - */ -void -LogRtemsFatal (const char *msg, rtems_status_code sc) -{ - errlogPrintf ("%s: %s\n", msg, rtems_status_text (sc)); - delayedPanic (msg); -} - -/* - * Log network error and terminate - */ -void -LogNetFatal (const char *msg, int err) -{ - errlogPrintf ("%s: %d\n", msg, err); - delayedPanic (msg); -} - void * mustMalloc(int size, const char *msg) { @@ -370,7 +348,7 @@ initialize_remote_filesystem(char **argv, int hasLocalFilesystem) } static -char rtems_etc_hosts[] = "127.0.0.1 localhost\n"; +const char rtems_etc_hosts[] = "127.0.0.1 localhost\n"; /* If it doesn't already exist, create /etc/hosts with an entry for 'localhost' */ static From bef9a08f6d32923540353ace567728ca7218b797 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 23 Jun 2019 07:27:39 -0700 Subject: [PATCH 230/281] asLib minor --- modules/libcom/src/as/asLibRoutines.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/as/asLibRoutines.c b/modules/libcom/src/as/asLibRoutines.c index 3011d0a37..e19b63990 100644 --- a/modules/libcom/src/as/asLibRoutines.c +++ b/modules/libcom/src/as/asLibRoutines.c @@ -1212,7 +1212,7 @@ static long asHagAddHost(HAG *phag,const char *host) if (!phag) return 0; if(!asCheckClientIP) { size_t i, len = strlen(host); - phagname = asCalloc(1, sizeof(HAGNAME) + len); + phagname = asCalloc(1, sizeof(*phagname) + len); for (i = 0; i < len; i++) { phagname->host[i] = (char)tolower((int)host[i]); } @@ -1226,13 +1226,13 @@ static long asHagAddHost(HAG *phag,const char *host) errlogPrintf("ACF: Unable to resolve host '%s'\n", host); - phagname = asCalloc(1, sizeof(HAGNAME) + sizeof(unresolved)-1+strlen(host)); + phagname = asCalloc(1, sizeof(*phagname) + sizeof(unresolved)-1+strlen(host)); strcpy(phagname->host, unresolved); strcat(phagname->host, host); } else { ip = ntohl(addr.sin_addr.s_addr); - phagname = asCalloc(1, sizeof(HAGNAME) + 24); + phagname = asCalloc(1, sizeof(*phagname) + 24); epicsSnprintf(phagname->host, 24, "%u.%u.%u.%u", (ip>>24)&0xff, From 05c93e954f7844dcf29ccd1f5ba2e183c85a14b9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 28 Jun 2019 08:48:21 -0700 Subject: [PATCH 231/281] makeRPath.py nicer error on mis-configuation --- src/tools/makeRPath.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/makeRPath.py b/src/tools/makeRPath.py index 000b8b450..89590e8df 100644 --- a/src/tools/makeRPath.py +++ b/src/tools/makeRPath.py @@ -54,7 +54,8 @@ for root in roots: if froot is None: sys.stderr.write("makeRPath: Final location %s\nNot under any of: %s\n"%(fdir, roots)) - sys.exit(1) + # skip $ORIGIN handling below... + roots = [] output = OrderedDict() for path in args.path: From 7acd7c61450e2ecc5880cd7d12f12a59ee9d02e4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 12 Nov 2019 17:36:10 -0800 Subject: [PATCH 232/281] minor epicsTimerTest --- modules/libcom/test/epicsTimerTest.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/libcom/test/epicsTimerTest.cpp b/modules/libcom/test/epicsTimerTest.cpp index 6743d0160..12e5eaeb2 100644 --- a/modules/libcom/test/epicsTimerTest.cpp +++ b/modules/libcom/test/epicsTimerTest.cpp @@ -112,10 +112,9 @@ double delayVerify::checkError () const double actualDelay = this->expireStamp - this->beginStamp; double measuredError = actualDelay - this->expectedDelay; double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay; - if ( ! testOk ( percentError < messageThresh, "%f < %f", percentError, messageThresh ) ) { - testDiag ( "delay = %f s, error = %f s (%.1f %%)", - this->expectedDelay, measuredError, percentError ); - } + testOk ( percentError < messageThresh, "%f < %f, delay = %f s, error = %f s (%.1f %%)", + percentError, messageThresh, + this->expectedDelay, measuredError, percentError ); return measuredError; } From 905ca4b7ac2aa78dd0fbb83736b2ed2580cf2999 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 12 Nov 2019 18:15:32 -0800 Subject: [PATCH 233/281] quiet some warnings --- modules/ca/src/client/udpiiu.cpp | 7 ++----- modules/database/src/ioc/rsrv/caserverio.c | 2 +- modules/database/src/ioc/rsrv/caservertask.c | 2 +- modules/libcom/src/error/errSymLib.c | 2 +- modules/libcom/src/fdmgr/fdManager.cpp | 2 +- 5 files changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/ca/src/client/udpiiu.cpp b/modules/ca/src/client/udpiiu.cpp index c378881f7..fe15f1b69 100644 --- a/modules/ca/src/client/udpiiu.cpp +++ b/modules/ca/src/client/udpiiu.cpp @@ -1162,7 +1162,7 @@ void udpiiu :: show ( unsigned level ) const } } if ( level > 2u ) { - ::printf ("\tsocket identifier %d\n", this->sock ); + ::printf ("\tsocket identifier %d\n", int(this->sock) ); ::printf ("\tbytes in xmit buffer %u\n", this->nBytesInXmitBuf ); ::printf ("\tshut down command bool %u\n", this->shutdownCmd ); ::printf ( "\trecv thread exit signal:\n" ); @@ -1195,10 +1195,7 @@ bool udpiiu::wakeupMsg () // send a wakeup msg so the UDP recv thread will exit int status = sendto ( this->sock, reinterpret_cast < char * > ( &msg ), sizeof (msg), 0, &addr.sa, sizeof ( addr.sa ) ); - if ( status == sizeof (msg) ) { - return true; - } - return false; + return status == sizeof (msg); } void udpiiu::beaconAnomalyNotify ( diff --git a/modules/database/src/ioc/rsrv/caserverio.c b/modules/database/src/ioc/rsrv/caserverio.c index 20a1c1c5b..afce46e25 100644 --- a/modules/database/src/ioc/rsrv/caserverio.c +++ b/modules/database/src/ioc/rsrv/caserverio.c @@ -56,7 +56,7 @@ void cas_send_bs_msg ( struct client *pclient, int lock_needed ) if ( pclient->disconnect ) { if ( CASDEBUG > 2 ) { errlogPrintf ( "CAS: msg Discard for sock %d addr %x\n", - pclient->sock, (unsigned) pclient->addr.sin_addr.s_addr ); + (int)pclient->sock, (unsigned) pclient->addr.sin_addr.s_addr ); } pclient->send.stk = 0u; if(lock_needed) diff --git a/modules/database/src/ioc/rsrv/caservertask.c b/modules/database/src/ioc/rsrv/caservertask.c index c51a06db6..629b7b0b5 100644 --- a/modules/database/src/ioc/rsrv/caservertask.c +++ b/modules/database/src/ioc/rsrv/caservertask.c @@ -335,7 +335,7 @@ void rsrv_build_addr_lists(void) char sockErrBuf[64]; epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) ); - errlogPrintf("rsrv: failed to set mcast ttl %d\n", ttl); + errlogPrintf("rsrv: failed to set mcast ttl %d\n", (int)ttl); } } #endif diff --git a/modules/libcom/src/error/errSymLib.c b/modules/libcom/src/error/errSymLib.c index b220f2bc0..8f59718c8 100644 --- a/modules/libcom/src/error/errSymLib.c +++ b/modules/libcom/src/error/errSymLib.c @@ -192,7 +192,7 @@ void errSymLookup(long status, char * pBuf, size_t bufLength) { const char* msg = errSymLookupInternal(status); if(msg) { - strncpy(pBuf, msg, bufLength); + strncpy(pBuf, msg, bufLength-1); pBuf[bufLength-1] = '\0'; return; } diff --git a/modules/libcom/src/fdmgr/fdManager.cpp b/modules/libcom/src/fdmgr/fdManager.cpp index f43fab25d..3bbc64876 100644 --- a/modules/libcom/src/fdmgr/fdManager.cpp +++ b/modules/libcom/src/fdmgr/fdManager.cpp @@ -249,7 +249,7 @@ void fdRegId::show ( unsigned level ) const static_cast ( this ) ); if ( level > 1u ) { printf ( "\tfd = %d, type = %d\n", - this->fd, this->type ); + int(this->fd), this->type ); } } From b43aafae701b4b4fd835117cf63b2e563482184b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 13 Nov 2019 10:18:00 -0800 Subject: [PATCH 234/281] VCS version instead of __DATE__ Use reproducable VCS version instead of date. Of course, this falls back to a date if not version controlled. --- modules/database/src/ioc/Makefile | 5 +++++ modules/database/src/ioc/misc/epicsRelease.c | 3 ++- modules/libcom/src/osi/epicsTime.cpp | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/Makefile b/modules/database/src/ioc/Makefile index 3ff0990c5..70b1b5558 100644 --- a/modules/database/src/ioc/Makefile +++ b/modules/database/src/ioc/Makefile @@ -36,6 +36,9 @@ include $(IOCDIR)/misc/Makefile include $(IOCDIR)/registry/Makefile include $(IOCDIR)/rsrv/Makefile +GENVERSION = epicsVCS.h +GENVERSIONMACRO = EPICS_VCS_VERSION + EXPANDVARS += EPICS_DATABASE_MAJOR_VERSION EXPANDVARS += EPICS_DATABASE_MINOR_VERSION EXPANDVARS += EPICS_DATABASE_MAINTENANCE_VERSION @@ -55,3 +58,5 @@ include $(IOCDIR)/dbtemplate/RULES ../O.Common/databaseVersionNum.h: ../databaseVersionNum.h@ $(MKDIR) $(COMMON_DIR) $(EXPAND_TOOL) $(EXPANDFLAGS) $($@_EXPANDFLAGS) $< $@ + +epicsRelease$(DEP): $(COMMON_DIR)/$(GENVERSION) diff --git a/modules/database/src/ioc/misc/epicsRelease.c b/modules/database/src/ioc/misc/epicsRelease.c index 5eb55960c..90056d99f 100644 --- a/modules/database/src/ioc/misc/epicsRelease.c +++ b/modules/database/src/ioc/misc/epicsRelease.c @@ -16,12 +16,13 @@ #define epicsExportSharedSymbols #include "epicsRelease.h" +#include "epicsVCS.h" epicsShareFunc int coreRelease(void) { printf ( "############################################################################\n" ); printf ( "## %s\n", epicsReleaseVersion ); - printf ( "## %s\n", "EPICS Base built " __DATE__ ); + printf ( "## %s\n", "Rev. " EPICS_VCS_VERSION ); printf ( "############################################################################\n" ); return 0; } diff --git a/modules/libcom/src/osi/epicsTime.cpp b/modules/libcom/src/osi/epicsTime.cpp index e3a32968e..f80d1738b 100644 --- a/modules/libcom/src/osi/epicsTime.cpp +++ b/modules/libcom/src/osi/epicsTime.cpp @@ -38,7 +38,7 @@ #include "epicsStdio.h" static const char pEpicsTimeVersion[] = - "@(#) " EPICS_VERSION_STRING ", Common Utilities Library " __DATE__; + "@(#) " EPICS_VERSION_STRING ", Common Utilities Library"; // // useful public constants From a4e5b9c52801708bd5c24ab8d5f00b33f7abdf36 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 12 Nov 2019 18:35:21 -0800 Subject: [PATCH 235/281] minor --- modules/database/src/ioc/db/dbContext.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/database/src/ioc/db/dbContext.cpp b/modules/database/src/ioc/db/dbContext.cpp index 832820206..36cc66538 100644 --- a/modules/database/src/ioc/db/dbContext.cpp +++ b/modules/database/src/ioc/db/dbContext.cpp @@ -384,7 +384,7 @@ void dbContext::show ( this->mutex.show ( level - 2u ); } if ( this->pNetContext.get() ) { - this->pNetContext.get()->show ( guard, level ); + this->pNetContext->show ( guard, level ); } } @@ -393,7 +393,7 @@ void dbContext::flush ( { guard.assertIdenticalMutex ( this->mutex ); if ( this->pNetContext.get() ) { - this->pNetContext.get()->flush ( guard ); + this->pNetContext->flush ( guard ); } } @@ -402,7 +402,7 @@ unsigned dbContext::circuitCount ( { guard.assertIdenticalMutex ( this->mutex ); if ( this->pNetContext.get() ) { - return this->pNetContext.get()->circuitCount ( guard ); + return this->pNetContext->circuitCount ( guard ); } else { return 0u; @@ -416,7 +416,7 @@ void dbContext::selfTest ( this->ioTable.verify (); if ( this->pNetContext.get() ) { - this->pNetContext.get()->selfTest ( guard ); + this->pNetContext->selfTest ( guard ); } } @@ -425,7 +425,7 @@ unsigned dbContext::beaconAnomaliesSinceProgramStart ( { guard.assertIdenticalMutex ( this->mutex ); if ( this->pNetContext.get() ) { - return this->pNetContext.get()->beaconAnomaliesSinceProgramStart ( guard ); + return this->pNetContext->beaconAnomaliesSinceProgramStart ( guard ); } else { return 0u; From f3d63da77b236f3d484e605727c6412843db23c3 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 15 Nov 2019 13:16:35 -0600 Subject: [PATCH 236/281] Remove two long-unused environment parameters --- configure/CONFIG_ENV | 10 ++-------- modules/libcom/src/env/envDefs.h | 2 -- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/configure/CONFIG_ENV b/configure/CONFIG_ENV index 59e72d883..6d0d52a79 100644 --- a/configure/CONFIG_ENV +++ b/configure/CONFIG_ENV @@ -3,9 +3,8 @@ # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found -# in file LICENSE that is included with this distribution. +# EPICS BASE is distributed subject to a Software License Agreement found +# in file LICENSE that is included with this distribution. #************************************************************************* # Author: Andrew Johnson # Date: 20 April 1995 @@ -54,8 +53,3 @@ EPICS_IOC_IGNORE_SERVERS="" # EPICS_IOC_LOG_PORT Log server port number etc. EPICS_IOC_LOG_PORT=7004 -# Other services: - -EPICS_CMD_PROTO_PORT= -EPICS_AR_PORT=7002 - diff --git a/modules/libcom/src/env/envDefs.h b/modules/libcom/src/env/envDefs.h index 001d932e2..2490702a6 100644 --- a/modules/libcom/src/env/envDefs.h +++ b/modules/libcom/src/env/envDefs.h @@ -71,8 +71,6 @@ epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_INET; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_LIMIT; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_NAME; epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_FILE_COMMAND; -epicsShareExtern const ENV_PARAM EPICS_CMD_PROTO_PORT; -epicsShareExtern const ENV_PARAM EPICS_AR_PORT; epicsShareExtern const ENV_PARAM IOCSH_PS1; epicsShareExtern const ENV_PARAM IOCSH_HISTSIZE; epicsShareExtern const ENV_PARAM IOCSH_HISTEDIT_DISABLE; From 019c20476a66fb7d9e22c5b7d49ea8c6a707ffdd Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 14 Nov 2019 16:50:51 -0800 Subject: [PATCH 237/281] test include public Com and db headers Ensure that headers which are meant to be included actually can be. --- modules/database/test/std/rec/Makefile | 7 + modules/database/test/std/rec/dbHeaderTest.c | 245 ++++++++++++++++++ .../database/test/std/rec/dbHeaderTestxx.cpp | 2 + 3 files changed, 254 insertions(+) create mode 100644 modules/database/test/std/rec/dbHeaderTest.c create mode 100644 modules/database/test/std/rec/dbHeaderTestxx.cpp diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile index 872087521..d2eff5504 100644 --- a/modules/database/test/std/rec/Makefile +++ b/modules/database/test/std/rec/Makefile @@ -148,6 +148,13 @@ asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db TESTS += asyncproctest +# dbHeader* is only a compile test +# no need to actually run +TESTPROD += dbHeaderTest +dbHeaderTest_SRCS += dbHeaderTest.cpp +TESTPROD += dbHeaderTestxx +dbHeaderTestxx_SRCS += dbHeaderTestxx.cpp + ifeq ($(T_A),$(EPICS_HOST_ARCH)) # Host-only tests of softIoc/softIocPVA, caget and pvget (if present) TESTS += netget diff --git a/modules/database/test/std/rec/dbHeaderTest.c b/modules/database/test/std/rec/dbHeaderTest.c new file mode 100644 index 000000000..260287888 --- /dev/null +++ b/modules/database/test/std/rec/dbHeaderTest.c @@ -0,0 +1,245 @@ +/*************************************************************************\ +* Copyright (c) 2019 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +/* This test includes all public headers from libCom and database modules + * to ensure they are all syntaxtically correct in C and C++ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __rtems__ +# include +#endif +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef __cplusplus +# include +# include +# include +# include +#endif +#include +#include +#include +#include +#include +#include + +/* must be last */ +#include + +MAIN(dbHeaderTest) +{ + testPlan(1); + testPass("Compiled successfully"); + return testDone(); +} diff --git a/modules/database/test/std/rec/dbHeaderTestxx.cpp b/modules/database/test/std/rec/dbHeaderTestxx.cpp new file mode 100644 index 000000000..7e2632ef0 --- /dev/null +++ b/modules/database/test/std/rec/dbHeaderTestxx.cpp @@ -0,0 +1,2 @@ +// just compile as c++ +#include "dbHeaderTest.c" From fab9c5285847e2e7644151ead722686c32212796 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 14 Nov 2019 16:51:18 -0800 Subject: [PATCH 238/281] missing includes Need definition of FILE --- modules/database/src/ioc/as/asCa.h | 2 ++ modules/database/src/ioc/as/asDbLib.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/modules/database/src/ioc/as/asCa.h b/modules/database/src/ioc/as/asCa.h index 360296fe2..a99cb544a 100644 --- a/modules/database/src/ioc/as/asCa.h +++ b/modules/database/src/ioc/as/asCa.h @@ -11,6 +11,8 @@ #ifndef INCasCah #define INCasCah +#include + #include "shareLib.h" #ifdef __cplusplus diff --git a/modules/database/src/ioc/as/asDbLib.h b/modules/database/src/ioc/as/asDbLib.h index 1e0f6756e..235bbbd4b 100644 --- a/modules/database/src/ioc/as/asDbLib.h +++ b/modules/database/src/ioc/as/asDbLib.h @@ -12,6 +12,8 @@ #ifndef INCdbAsLibh #define INCdbAsLibh +#include + #include "callback.h" #include "shareLib.h" From 156b137af01576ada0c1cfd272b9943d2b282bf9 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 14 Nov 2019 17:52:10 -0800 Subject: [PATCH 239/281] avoid 'struct dset' doesn't work if -DUSE_TYPED_DSET --- modules/database/src/ioc/db/dbAccess.c | 4 ++-- modules/database/src/ioc/db/dbAccessDefs.h | 9 +++++---- modules/database/src/ioc/db/dbCommon.dbd | 3 ++- modules/database/src/ioc/db/dbTest.c | 2 +- modules/database/src/ioc/dbStatic/dbBase.h | 3 ++- modules/database/src/ioc/dbStatic/devSup.h | 3 +++ modules/database/src/ioc/misc/iocInit.c | 4 ++-- .../database/src/ioc/registry/registryDeviceSupport.c | 4 ++-- .../database/src/ioc/registry/registryDeviceSupport.h | 4 ++-- modules/database/test/std/rec/Makefile | 1 + modules/database/test/std/rec/dbHeaderTest.c | 1 - 11 files changed, 22 insertions(+), 16 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c index be81d22ed..19f60381d 100644 --- a/modules/database/src/ioc/db/dbAccess.c +++ b/modules/database/src/ioc/db/dbAccess.c @@ -1010,7 +1010,7 @@ devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) { return (devSup *)ellNth(&prdes->devList, dtyp+1); } -devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset) { +devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) { devSup *pdevSup = (devSup *)ellFirst(&prdes->devList); while (pdevSup) { if (pdset == pdevSup->pdset) return pdevSup; @@ -1032,7 +1032,7 @@ static long dbPutFieldLink(DBADDR *paddr, struct link *plink = (struct link *)paddr->pfield; const char *pstring = (const char *)pbuffer; struct dsxt *old_dsxt = NULL; - struct dset *new_dset = NULL; + dset *new_dset = NULL; struct dsxt *new_dsxt = NULL; devSup *new_devsup = NULL; long status; diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h index 52ac4016d..805dfd41f 100644 --- a/modules/database/src/ioc/db/dbAccessDefs.h +++ b/modules/database/src/ioc/db/dbAccessDefs.h @@ -18,15 +18,16 @@ #include "epicsTypes.h" #include "epicsTime.h" -#include "dbBase.h" -#include "dbAddr.h" -#include "recSup.h" #ifdef INCLdb_accessh_epicsExportSharedSymbols # define epicsExportSharedSymbols # include "shareLib.h" #endif +#include "dbBase.h" +#include "dbAddr.h" +#include "recSup.h" + #ifdef __cplusplus extern "C" { #endif @@ -239,7 +240,7 @@ epicsShareFunc void dbInitEntryFromRecord(struct dbCommon *prec, struct dbEntry *pdbentry); epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp); -epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, struct dset *pdset); +epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset); epicsShareFunc long dbGetField( struct dbAddr *,short dbrType,void *pbuffer,long *options, long *nRequest,void *pfl); diff --git a/modules/database/src/ioc/db/dbCommon.dbd b/modules/database/src/ioc/db/dbCommon.dbd index 1b093e6a8..aa6a63345 100644 --- a/modules/database/src/ioc/db/dbCommon.dbd +++ b/modules/database/src/ioc/db/dbCommon.dbd @@ -199,11 +199,12 @@ interest(4) extra("struct typed_rset *rset") } + %#include "devSup.h" field(DSET,DBF_NOACCESS) { prompt("DSET address") special(SPC_NOMOD) interest(4) - extra("struct dset *dset") + extra("unambiguous_dset *dset") } field(DPVT,DBF_NOACCESS) { prompt("Device Private") diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c index e23220503..11939545b 100644 --- a/modules/database/src/ioc/db/dbTest.c +++ b/modules/database/src/ioc/db/dbTest.c @@ -712,7 +712,7 @@ long dbior(const char *pdrvName,int interest_level) for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) { - struct dset *pdset = pdevSup->pdset; + dset *pdset = pdevSup->pdset; const char *pname = pdevSup->name; if (!pdset || !pname) diff --git a/modules/database/src/ioc/dbStatic/dbBase.h b/modules/database/src/ioc/dbStatic/dbBase.h index df3be4352..9e61211c6 100644 --- a/modules/database/src/ioc/dbStatic/dbBase.h +++ b/modules/database/src/ioc/dbStatic/dbBase.h @@ -19,6 +19,7 @@ #include "ellLib.h" #include "dbDefs.h" #include "recSup.h" +#include "devSup.h" typedef struct dbMenu { ELLNODE node; @@ -40,7 +41,7 @@ typedef struct devSup { char *choice; int link_type; /*Following only available on run time system*/ - struct dset *pdset; + dset *pdset; struct dsxt *pdsxt; /* Extended device support */ }devSup; diff --git a/modules/database/src/ioc/dbStatic/devSup.h b/modules/database/src/ioc/dbStatic/devSup.h index 73dba198c..dc55a35dd 100644 --- a/modules/database/src/ioc/dbStatic/devSup.h +++ b/modules/database/src/ioc/dbStatic/devSup.h @@ -153,6 +153,9 @@ typedef struct dset { /* device support entry table */ typedef typed_dset dset; #endif /* USE_TYPED_DSET */ +/* exists only to disambiguate dset dbCommon::dset */ +typedef dset unambiguous_dset; + /** Fetch INP or OUT link (or NULL if record type has neither). * * Recommended for use in device support init_record() diff --git a/modules/database/src/ioc/misc/iocInit.c b/modules/database/src/ioc/misc/iocInit.c index 05bf7880e..b8aa438a2 100644 --- a/modules/database/src/ioc/misc/iocInit.c +++ b/modules/database/src/ioc/misc/iocInit.c @@ -433,7 +433,7 @@ static void initDevSup(void) for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) { - struct dset *pdset = registryDeviceSupportFind(pdevSup->name); + dset *pdset = registryDeviceSupportFind(pdevSup->name); if (!pdset) { errlogPrintf("device support %s not found\n",pdevSup->name); @@ -456,7 +456,7 @@ static void finishDevSup(void) for (pdevSup = (devSup *)ellFirst(&pdbRecordType->devList); pdevSup; pdevSup = (devSup *)ellNext(&pdevSup->node)) { - struct dset *pdset = pdevSup->pdset; + dset *pdset = pdevSup->pdset; if (pdset && pdset->init) pdset->init(1); diff --git a/modules/database/src/ioc/registry/registryDeviceSupport.c b/modules/database/src/ioc/registry/registryDeviceSupport.c index 4310c923d..ab3584ecd 100644 --- a/modules/database/src/ioc/registry/registryDeviceSupport.c +++ b/modules/database/src/ioc/registry/registryDeviceSupport.c @@ -18,12 +18,12 @@ static void *registryID = "device support"; epicsShareFunc int registryDeviceSupportAdd( - const char *name, const struct dset *pdset) + const char *name, const dset *pdset) { return registryAdd(registryID, name, (void *)pdset); } -epicsShareFunc struct dset * registryDeviceSupportFind( +epicsShareFunc dset * registryDeviceSupportFind( const char *name) { return registryFind(registryID, name); diff --git a/modules/database/src/ioc/registry/registryDeviceSupport.h b/modules/database/src/ioc/registry/registryDeviceSupport.h index 52a269863..78cdea6f0 100644 --- a/modules/database/src/ioc/registry/registryDeviceSupport.h +++ b/modules/database/src/ioc/registry/registryDeviceSupport.h @@ -18,8 +18,8 @@ extern "C" { #endif epicsShareFunc int registryDeviceSupportAdd( - const char *name, const struct dset *pdset); -epicsShareFunc struct dset * registryDeviceSupportFind( + const char *name, const dset *pdset); +epicsShareFunc dset * registryDeviceSupportFind( const char *name); #ifdef __cplusplus diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile index d2eff5504..357dd5306 100644 --- a/modules/database/test/std/rec/Makefile +++ b/modules/database/test/std/rec/Makefile @@ -11,6 +11,7 @@ TOP = ../../../../.. include $(TOP)/configure/CONFIG USR_CPPFLAGS += -DUSE_TYPED_RSET +USR_CPPFLAGS += -DUSE_TYPED_DSET TESTLIBRARY = dbRecStdTest diff --git a/modules/database/test/std/rec/dbHeaderTest.c b/modules/database/test/std/rec/dbHeaderTest.c index 260287888..0e2785a8f 100644 --- a/modules/database/test/std/rec/dbHeaderTest.c +++ b/modules/database/test/std/rec/dbHeaderTest.c @@ -98,7 +98,6 @@ # include #endif #include -#include #include #include #include From 13234afc405e15fde56e4ca3840f87f350aea75d Mon Sep 17 00:00:00 2001 From: Martin Konrad Date: Tue, 12 Nov 2019 13:35:49 -0500 Subject: [PATCH 240/281] Simplify definition of compiler-specific macros Remove conditionals for older compiler versions that aren't supported by EPICS Base anymore. --- .../src/osi/compiler/gcc/compilerSpecific.h | 22 +++++-------------- .../src/osi/compiler/msvc/compilerSpecific.h | 13 ++--------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h index 13d91193c..e140d8b05 100644 --- a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h @@ -24,11 +24,7 @@ # error compiler/gcc/compilerSpecific.h is not for use with the clang compiler #endif -#if __GNUC__ > 2 -# define EPICS_ALWAYS_INLINE __inline__ __attribute__((always_inline)) -#else -# define EPICS_ALWAYS_INLINE __inline__ -#endif +#define EPICS_ALWAYS_INLINE __inline__ __attribute__((always_inline)) /* Expands to a 'const char*' which describes the name of the current function scope */ #define EPICS_FUNCTION __PRETTY_FUNCTION__ @@ -46,14 +42,8 @@ * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ - -#if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 95 ) -# define CXX_THROW_SPECIFICATION -#endif - -#if __GNUC__ > 2 || ( __GNUC__ == 2 && __GNUC_MINOR__ >= 96 ) -# define CXX_PLACEMENT_DELETE -#endif +#define CXX_THROW_SPECIFICATION +#define CXX_PLACEMENT_DELETE #endif /* __cplusplus */ @@ -63,11 +53,9 @@ #define EPICS_PRINTF_STYLE(f,a) __attribute__((format(__printf__,f,a))) /* - * Deprecation marker if possible + * Deprecation marker */ -#if (__GNUC__ > 2) -# define EPICS_DEPRECATED __attribute__((deprecated)) -#endif +#define EPICS_DEPRECATED __attribute__((deprecated)) /* * Unused marker diff --git a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h index 75bfa83fb..4e282db4b 100644 --- a/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/msvc/compilerSpecific.h @@ -20,11 +20,7 @@ # error compiler/msvc/compilerSpecific.h is only for use with the Microsoft compiler #endif -#if _MSC_VER >= 1200 #define EPICS_ALWAYS_INLINE __forceinline -#else -#define EPICS_ALWAYS_INLINE __inline -#endif /* Expands to a 'const char*' which describes the name of the current function scope */ #define EPICS_FUNCTION __FUNCTION__ @@ -42,13 +38,8 @@ * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ -#if _MSC_VER >= 1200 /* visual studio 6.0 or later */ -# define CXX_PLACEMENT_DELETE -#endif - -#if _MSC_VER > 1300 /* some release after visual studio 7 we hope */ -# define CXX_THROW_SPECIFICATION -#endif +#define CXX_PLACEMENT_DELETE +#define CXX_THROW_SPECIFICATION #endif /* __cplusplus */ From 218459f454b263f02518ed22f8375cc040c9116d Mon Sep 17 00:00:00 2001 From: Martin Konrad Date: Tue, 22 Oct 2019 13:48:33 -0400 Subject: [PATCH 241/281] Remove epicsThrows() macro Exception specifications are deprecated: http://isocpp.github.io/ CppCoreGuidelines/CppCoreGuidelines.html#e30-dont-use-exception- specifications . They will be removed from the C++ standard with C++20. Modern compilers are warning about them since years. Thus it's unlikely that anyone is still using the epicsThrows() macro. Even if that's the case the fix is trivial: Simply remove the macro. --- .../libcom/src/osi/compiler/clang/compilerSpecific.h | 2 -- .../libcom/src/osi/compiler/gcc/compilerSpecific.h | 2 -- modules/libcom/src/osi/compilerDependencies.h | 12 ------------ 3 files changed, 16 deletions(-) diff --git a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h index 2053227e7..0498f6e27 100644 --- a/modules/libcom/src/osi/compiler/clang/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/clang/compilerSpecific.h @@ -33,10 +33,8 @@ /* * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete - * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ #define CXX_PLACEMENT_DELETE -#define CXX_THROW_SPECIFICATION #endif /* __cplusplus */ diff --git a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h index e140d8b05..3342308a9 100644 --- a/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h +++ b/modules/libcom/src/osi/compiler/gcc/compilerSpecific.h @@ -40,9 +40,7 @@ /* * CXX_PLACEMENT_DELETE - defined if compiler supports placement delete - * CXX_THROW_SPECIFICATION - defined if compiler supports throw specification */ -#define CXX_THROW_SPECIFICATION #define CXX_PLACEMENT_DELETE #endif /* __cplusplus */ diff --git a/modules/libcom/src/osi/compilerDependencies.h b/modules/libcom/src/osi/compilerDependencies.h index 3bd835c91..0b333d74e 100644 --- a/modules/libcom/src/osi/compilerDependencies.h +++ b/modules/libcom/src/osi/compilerDependencies.h @@ -20,18 +20,6 @@ #ifdef __cplusplus -/* - * usage: void func () epicsThrows (( std::bad_alloc, std::logic_error )) - * - * Note: now a widely accepted concensus (ref Meyers and C++ faq) is that - * one should avoid using throw specifications in C++ code - */ -#if defined ( CXX_THROW_SPECIFICATION ) -# define epicsThrows(X) throw X -#else -# define epicsThrows(X) -#endif - /* * usage: epicsPlacementDeleteOperator (( void *, myMemoryManager & )) */ From 3c0d4ccf4931b696c82ae678f7dd45740f4eac8c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 15 Nov 2019 21:25:37 -0800 Subject: [PATCH 242/281] remove another __DATE__ --- modules/ca/src/client/cac.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ca/src/client/cac.cpp b/modules/ca/src/client/cac.cpp index 485b83d89..476d1c380 100644 --- a/modules/ca/src/client/cac.cpp +++ b/modules/ca/src/client/cac.cpp @@ -53,7 +53,7 @@ static const char pVersionCAC[] = "@(#) " EPICS_VERSION_STRING - ", CA Client Library " __DATE__; + ", CA Client Library"; // TCP response dispatch table const cac::pProtoStubTCP cac::tcpJumpTableCAC [] = From a85967caeac8a6fef3be471fe7b06abde3ec8523 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 21 Nov 2019 12:20:13 -0600 Subject: [PATCH 243/281] Cross-builds of 64-bit MinGW should inherit from 32-bit Don't duplicate, this file missed an important change as a result. --- .../os/CONFIG.linux-x86.windows-x64-mingw | 20 ++----------------- 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/configure/os/CONFIG.linux-x86.windows-x64-mingw b/configure/os/CONFIG.linux-x86.windows-x64-mingw index 3becd0045..78f1f31de 100644 --- a/configure/os/CONFIG.linux-x86.windows-x64-mingw +++ b/configure/os/CONFIG.linux-x86.windows-x64-mingw @@ -4,21 +4,5 @@ # Override these definitions in CONFIG_SITE.linux-x86.windows-x64-mingw #------------------------------------------------------- -# Include common gnu compiler definitions -include $(CONFIG)/CONFIG.gnuCommon - -# Add resource compiler -RCCMD = $(GNU_BIN)/$(CMPLR_PREFIX)windres$(CMPLR_SUFFIX) $(INCLUDES) $< $@ - -# Remove -fPIC flags, add out-implib -SHRLIB_CFLAGS = -SHRLIB_LDFLAGS = -shared \ - -Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX) -LOADABLE_SHRLIB_LDFLAGS = -shared \ - -Wl,--out-implib,$(DLLSTUB_PREFIX)$*$(DLLSTUB_SUFFIX) - -# No need to explicitly link with gcc library -GNU_LDLIBS_YES = - -# Link with winsock2 -OP_SYS_LDLIBS = -lws2_32 +# Use the definitions from the win32-x86-mingw target +include $(CONFIG)/os/CONFIG.linux-x86.win32-x86-mingw From 1d18aa3e6cd3a90339388b44d5f0febc518b86a9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 21 Nov 2019 12:20:56 -0600 Subject: [PATCH 244/281] Disable printf() format warnings on MinGW, they're broken --- configure/os/CONFIG.Common.win32-x86-mingw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure/os/CONFIG.Common.win32-x86-mingw b/configure/os/CONFIG.Common.win32-x86-mingw index 936b1d954..cb3f53978 100644 --- a/configure/os/CONFIG.Common.win32-x86-mingw +++ b/configure/os/CONFIG.Common.win32-x86-mingw @@ -30,7 +30,7 @@ ARCH_DEP_LDFLAGS += -m32 # Compiler does not define __unix __unix__ unix # Override for -DUNIX from CONFIG.Common.UnixCommon -OP_SYS_CPPFLAGS = -D_MINGW +OP_SYS_CPPFLAGS = -D_MINGW -Wno-format EXE = .exe RES = .coff From 37ed77006c8cad52ad395bec7307225e804ed00f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 21 Nov 2019 12:47:02 -0600 Subject: [PATCH 245/281] Fix release headers in Release Notes --- documentation/RELEASE_NOTES.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 6e6bf13d3..2adeacf24 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -12,7 +12,7 @@ The external PVA submodules each have their own separate set of release notes which should also be read to understand what has changed since an earlier release. -# EPICS Release 7.0.3.1 +## EPICS Release 7.0.3.1 **IMPORTANT NOTE:** *Some record types in this release will not be compatible with device support binaries compiled against earlier versions of those record @@ -205,7 +205,7 @@ necessary, all RTEMS targets should now link although the IOC won't be able to be used with the VME I/O on those systems (that we don't have VMEbus I/O support for in libCom). -# EPICS Release 7.0.3 +## EPICS Release 7.0.3 ### `epicsTimeGetCurrent()` optimization @@ -225,7 +225,7 @@ This may result in slightly fewer, but larger frames being sent. Report NOBT as "precision" through the dbAccess API. This is not accessible through CA, but is planned to be used through QSRV. -# EPICS Release 7.0.2.2 +## EPICS Release 7.0.2.2 ### Build System changes @@ -259,7 +259,7 @@ substantial than bug fixes. Turns out this is ~10x slower to query than `CLOCK_MONOTONIC`. -# EPICS Release 7.0.2.1 +## EPICS Release 7.0.2.1 ### Linking shared libraries on macOS @@ -310,7 +310,7 @@ rewrite of the link address parser code in dbStaticLib. This release fixes that issue, although in some cases the output may be slightly different than it used to be. -# EPICS Release 7.0.2 +## EPICS Release 7.0.2 ### Launchpad Bugs @@ -327,7 +327,7 @@ modules. The layout of the source files has not changed at all however, so the source code for libcom, ca and the database are still found separately under the module subdirectory. -# EPICS Release 7.0.1.1 +## EPICS Release 7.0.1.1 ### Changed SIML failure behavior From 1290ab7c6c30392f04058537cabee6a95d39f18c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 24 Nov 2019 14:10:46 -0800 Subject: [PATCH 246/281] dbInitEntry() w/o matching dbFinishEntry() --- modules/database/src/ioc/registry/registryCommon.c | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/database/src/ioc/registry/registryCommon.c b/modules/database/src/ioc/registry/registryCommon.c index 56664c5bb..dbd10d8f9 100644 --- a/modules/database/src/ioc/registry/registryCommon.c +++ b/modules/database/src/ioc/registry/registryCommon.c @@ -46,6 +46,7 @@ void registerRecordTypes(DBBASE *pbase, int nRecordTypes, } else { sizeOffset(dbEntry.precordType); } + dbFinishEntry(&dbEntry); } } From 90ef40e62b3aedff41a3886845b5045027bff903 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 24 Nov 2019 15:54:57 -0800 Subject: [PATCH 247/281] iocshFindVariable() safety --- modules/libcom/src/iocsh/iocsh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/iocsh/iocsh.cpp b/modules/libcom/src/iocsh/iocsh.cpp index a795c9b70..8e4d365f9 100644 --- a/modules/libcom/src/iocsh/iocsh.cpp +++ b/modules/libcom/src/iocsh/iocsh.cpp @@ -223,7 +223,7 @@ void epicsShareAPI iocshRegisterVariable (const iocshVarDef *piocshVarDef) const iocshVarDef * epicsShareAPI iocshFindVariable(const char *name) { struct iocshVariable *temp = (iocshVariable *) registryFind(iocshVarID, name); - return temp->pVarDef; + return temp ? temp->pVarDef : 0; } /* From a7cb9524c2761f03c6e5a0538d16dde9162547fa Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 22 Nov 2019 21:05:13 -0800 Subject: [PATCH 248/281] softIoc re-add -D --- modules/database/src/std/softIoc/softMain.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/modules/database/src/std/softIoc/softMain.cpp b/modules/database/src/std/softIoc/softMain.cpp index bc945c80e..9d9f080cb 100644 --- a/modules/database/src/std/softIoc/softMain.cpp +++ b/modules/database/src/std/softIoc/softMain.cpp @@ -96,10 +96,11 @@ void errIf(int ret, const std::string& msg) throw std::runtime_error(msg); } +bool lazy_dbd_loaded; + void lazy_dbd(const std::string& dbd_file) { - static bool loaded; - if(loaded) return; - loaded = true; + if(lazy_dbd_loaded) return; + lazy_dbd_loaded = true; errIf(dbLoadDatabase(dbd_file.c_str(), NULL, NULL), std::string("Failed to load DBD file: ")+dbd_file); @@ -142,7 +143,7 @@ int main(int argc, char *argv[]) int opt; - while ((opt = getopt(argc, argv, "ha:d:m:Ssx:")) != -1) { + while ((opt = getopt(argc, argv, "ha:D:d:m:Ssx:")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(argv[0], dbd_file); @@ -164,6 +165,12 @@ int main(int argc, char *argv[]) throw std::bad_alloc(); std::cout<<"asSetFilename(\""< Date: Fri, 22 Nov 2019 21:17:16 -0800 Subject: [PATCH 249/281] softIoc use correct path sep --- modules/database/src/std/softIoc/softMain.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/database/src/std/softIoc/softMain.cpp b/modules/database/src/std/softIoc/softMain.cpp index 9d9f080cb..85a3b730d 100644 --- a/modules/database/src/std/softIoc/softMain.cpp +++ b/modules/database/src/std/softIoc/softMain.cpp @@ -37,12 +37,12 @@ extern "C" int softIoc_registerRecordDeviceDriver(struct dbBase *pdbbase); # error -DEPICS_BASE required #endif -#define DBD_BASE "dbd/softIoc.dbd" -#define EXIT_BASE "db/softIocExit.db" -#define DBD_FILE_REL "../../" DBD_BASE -#define EXIT_FILE_REL "../../" EXIT_BASE -#define DBD_FILE EPICS_BASE "/" DBD_BASE -#define EXIT_FILE EPICS_BASE "/" EXIT_BASE +#define DBD_BASE "dbd" OSI_PATH_SEPARATOR "softIoc.dbd" +#define EXIT_BASE "db" OSI_PATH_SEPARATOR "softIocExit.db" +#define DBD_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR DBD_BASE +#define EXIT_FILE_REL ".." OSI_PATH_SEPARATOR ".." OSI_PATH_SEPARATOR EXIT_BASE +#define DBD_FILE EPICS_BASE OSI_PATH_SEPARATOR DBD_BASE +#define EXIT_FILE EPICS_BASE OSI_PATH_SEPARATOR EXIT_BASE namespace { From f6d8a1ab6cb685c5ba4e68bf4a5f2e2261e08eed Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 26 Nov 2019 14:31:29 -0600 Subject: [PATCH 250/281] Sort DIRECTORY_TARGETs to de-duplicate, avoids make warning --- configure/RULES_BUILD | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 0735f5598..3df3052b4 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -173,9 +173,9 @@ ifdef RES @$(RM) *$(RES) endif -# Sort mkdir targets to remove duplicates & make parents first -$(DIRECTORY_TARGETS): - $(MKDIR) $(sort $@) +# Sort directories to remove duplicates & make parents first +$(sort $(DIRECTORY_TARGETS)): + $(MKDIR) $@ # Install LIB_INSTALLS libraries before linking executables $(TESTPRODNAME) $(PRODNAME): | $(INSTALL_LIB_INSTALLS) From 70e9d46d755edb70826260600bbd251f6c3fd776 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 5 Dec 2019 16:44:59 +0100 Subject: [PATCH 251/281] libcom: import some C99 math (isnan etc.) into global namespace --- src/libCom/osi/os/posix/epicsMath.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libCom/osi/os/posix/epicsMath.h b/src/libCom/osi/os/posix/epicsMath.h index 4e558676c..13f25e520 100644 --- a/src/libCom/osi/os/posix/epicsMath.h +++ b/src/libCom/osi/os/posix/epicsMath.h @@ -14,6 +14,14 @@ #include #ifdef __cplusplus + +#include + +using std::isfinite; +using std::isinf; +using std::isnan; +using std::isnormal; + extern "C" { #endif From 09ec3af3371020278d5c41ca19e170468dc2fc02 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Fri, 6 Dec 2019 10:52:38 +0100 Subject: [PATCH 252/281] libcom: fix colliding isnan/isinf between C99 and C++0x for gcc-4 This fix can be removed once support for gcc-4 is dropped in 2038 --- src/libCom/osi/os/posix/epicsMath.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libCom/osi/os/posix/epicsMath.h b/src/libCom/osi/os/posix/epicsMath.h index 13f25e520..1ef96d76f 100644 --- a/src/libCom/osi/os/posix/epicsMath.h +++ b/src/libCom/osi/os/posix/epicsMath.h @@ -18,8 +18,10 @@ #include using std::isfinite; +#ifndef __GXX_EXPERIMENTAL_CXX0X__ using std::isinf; using std::isnan; +#endif using std::isnormal; extern "C" { From 2e89a60c2dd405f4891e6d8e6f1b24747ee5790c Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 11 Dec 2019 14:51:16 +0100 Subject: [PATCH 253/281] libcom: properly declare isnan() in C++ code --- src/libCom/cppStd/epicsAlgorithm.h | 4 +++- src/libCom/iocsh/iocsh.cpp | 3 +++ src/libCom/test/epicsAlgorithmTest.cpp | 4 ++++ src/libCom/test/epicsCalcTest.cpp | 4 ++++ 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libCom/cppStd/epicsAlgorithm.h b/src/libCom/cppStd/epicsAlgorithm.h index 20850242d..54dec91e9 100644 --- a/src/libCom/cppStd/epicsAlgorithm.h +++ b/src/libCom/cppStd/epicsAlgorithm.h @@ -13,7 +13,9 @@ #ifndef __EPICS_ALGORITHM_H__ #define __EPICS_ALGORITHM_H__ -#include "epicsMath.h" +#include + +using std::isnan; // The C++ standard only requires types to be less-than comparable, so // the epicsMin and epicsMax templates only use operator < diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index 03d4c28b4..307fabfbf 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #define epicsExportSharedSymbols #include "errlog.h" @@ -31,6 +32,8 @@ #include "cantProceed.h" #include "iocsh.h" +using std::isinf; + extern "C" { /* diff --git a/src/libCom/test/epicsAlgorithmTest.cpp b/src/libCom/test/epicsAlgorithmTest.cpp index fa8c0c03f..108c15d62 100644 --- a/src/libCom/test/epicsAlgorithmTest.cpp +++ b/src/libCom/test/epicsAlgorithmTest.cpp @@ -9,11 +9,15 @@ // epicsAlgorithmTest.cpp // Authors: Jeff Hill & Andrew Johnson +#include + #include "epicsUnitTest.h" #include "epicsAlgorithm.h" #include "epicsMath.h" #include "testMain.h" +using std::isnan; + MAIN(epicsAlgorithm) { testPlan(22); diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 2492c95ba..aae412262 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -8,6 +8,7 @@ #include #include +#include #include "epicsUnitTest.h" #include "epicsTypes.h" @@ -16,6 +17,9 @@ #include "postfix.h" #include "testMain.h" +using std::isnan; +using std::isinf; + /* Infrastructure for running tests */ double doCalc(const char *expr) { From b0418e5274eae8a632c5d3bc9b87811a828ac5de Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 16 Dec 2019 10:25:11 -0800 Subject: [PATCH 254/281] epicsSockResolveTest add detail --- src/libCom/test/epicsSockResolveTest.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libCom/test/epicsSockResolveTest.c b/src/libCom/test/epicsSockResolveTest.c index 8131d9dbf..04b2973fa 100644 --- a/src/libCom/test/epicsSockResolveTest.c +++ b/src/libCom/test/epicsSockResolveTest.c @@ -75,8 +75,11 @@ MAIN(epicsSockResolveTest) testSkip(2, " aToIPAddr() failed"); } else { - testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP), " IP correct"); - testOk(addr.sin_port == htons(okdata[i].port), " Port correct"); + testOk(addr.sin_addr.s_addr == htonl(okdata[i].IP), + " IP correct 0x%08x == 0x%08x", (unsigned)ntohl(addr.sin_addr.s_addr), + (unsigned)okdata[i].IP); + testOk(addr.sin_port == htons(okdata[i].port), " Port correct %u == %u", + ntohs(addr.sin_port), okdata[i].port); } } From 87229fdef0a255b8551ecd4119f0ed847b2e318f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 16 Dec 2019 10:05:19 -0800 Subject: [PATCH 255/281] redo travis-ci with matrix add mix of Ubuntu versions --- .travis.yml | 72 +++++++++++++++++++++++++++++++------------- ci/travis-build.sh | 4 +-- ci/travis-prepare.sh | 33 +++----------------- 3 files changed, 56 insertions(+), 53 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5079bff0c..b68a94223 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,54 @@ -sudo: false -dist: trusty language: c -compiler: - - gcc -env: - - CMPLR=gcc - - CMPLR=gcc EXTRA=CMD_CXXFLAGS=-std=c++11 - - CMPLR=gcc STATIC=YES - - CMPLR=clang - - CMPLR=clang STATIC=YES - - WINE=32 TEST=NO STATIC=YES - - WINE=32 TEST=NO STATIC=NO - - RTEMS=4.10 TEST=NO - - RTEMS=4.9 TEST=NO + +matrix: + include: + - sudo: false + dist: bionic + compiler: gcc + env: CMPLR=gcc + - sudo: false + dist: xenial + compiler: gcc + env: CMPLR=gcc + - sudo: false + dist: bionic + compiler: gcc + env: CMPLR=gcc CMD_CXXFLAGS=-std=c++11 + - sudo: false + dist: trusty + compiler: gcc + env: CMPLR=gcc STATIC=YES + - sudo: false + dist: bionic + compiler: gcc + env: CMPLR=clang + - sudo: false + dist: xenial + compiler: gcc + env: CMPLR=clang + - sudo: false + dist: trusty + compiler: gcc + env: CMPLR=clang STATIC=YES + - sudo: false + dist: trusty + compiler: gcc + env: WINE=32 TEST=NO STATIC=YES + - sudo: false + dist: trusty + compiler: gcc + env: WINE=32 TEST=NO STATIC=NO + - sudo: false + dist: trusty + compiler: gcc + env: RTEMS=4.10 TEST=NO + - sudo: false + dist: trusty + compiler: gcc + env: RTEMS=4.9 TEST=NO + - os: osx + env: CMD_CFLAGS="-mmacosx-version-min=10.7" CMD_CXXFLAGS="-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++" CMD_LDXFLAGS="-mmacosx-version-min=10.7 -std=c++11 -stdlib=libc++" + addons: apt: packages: @@ -21,12 +57,6 @@ addons: - perl - clang - g++-mingw-w64-i686 - - bison - - flex - - texinfo - - install-info -cache: - directories: - - $HOME/.cache + install: sh ci/travis-prepare.sh "$HOME/.cache/qemu/built" - fi + echo "==== /etc/hosts" + cat /etc/hosts + echo "====" fi - -cd "$CURDIR" From 8a9637568ebd2b69e733983cbd3ce61d5a66710c Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 16 Dec 2019 11:06:34 -0800 Subject: [PATCH 256/281] travis-ci /etc/hosts workaround --- ci/travis-prepare.sh | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ci/travis-prepare.sh b/ci/travis-prepare.sh index 9797b0faa..393bd80b6 100644 --- a/ci/travis-prepare.sh +++ b/ci/travis-prepare.sh @@ -6,9 +6,18 @@ die() { exit 1 } - if [ -f /etc/hosts ] then + # The travis-ci "bionic" image throws us a curveball in /etc/hosts + # by including two entries for localhost. The first for 127.0.1.1 + # which causes epicsSockResolveTest to fail. + # cat /etc/hosts + # ... + # 127.0.1.1 localhost localhost ip4-loopback + # 127.0.0.1 localhost nettuno travis vagrant travis-job-.... + + sudo sed -i -e '/^127\.0\.1\.1/ s|localhost\s*||g' /etc/hosts + echo "==== /etc/hosts" cat /etc/hosts echo "====" From 247fea0fa9dfcde109d74b1b836fe6b37b5d4a0b Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 16 Dec 2019 10:25:55 -0800 Subject: [PATCH 257/281] Revert "libcom: properly declare isnan() in C++ code" This reverts commit 2e89a60c2dd405f4891e6d8e6f1b24747ee5790c. --- src/libCom/cppStd/epicsAlgorithm.h | 4 +--- src/libCom/iocsh/iocsh.cpp | 3 --- src/libCom/test/epicsAlgorithmTest.cpp | 4 ---- src/libCom/test/epicsCalcTest.cpp | 4 ---- 4 files changed, 1 insertion(+), 14 deletions(-) diff --git a/src/libCom/cppStd/epicsAlgorithm.h b/src/libCom/cppStd/epicsAlgorithm.h index 54dec91e9..20850242d 100644 --- a/src/libCom/cppStd/epicsAlgorithm.h +++ b/src/libCom/cppStd/epicsAlgorithm.h @@ -13,9 +13,7 @@ #ifndef __EPICS_ALGORITHM_H__ #define __EPICS_ALGORITHM_H__ -#include - -using std::isnan; +#include "epicsMath.h" // The C++ standard only requires types to be less-than comparable, so // the epicsMin and epicsMax templates only use operator < diff --git a/src/libCom/iocsh/iocsh.cpp b/src/libCom/iocsh/iocsh.cpp index 307fabfbf..03d4c28b4 100644 --- a/src/libCom/iocsh/iocsh.cpp +++ b/src/libCom/iocsh/iocsh.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #define epicsExportSharedSymbols #include "errlog.h" @@ -32,8 +31,6 @@ #include "cantProceed.h" #include "iocsh.h" -using std::isinf; - extern "C" { /* diff --git a/src/libCom/test/epicsAlgorithmTest.cpp b/src/libCom/test/epicsAlgorithmTest.cpp index 108c15d62..fa8c0c03f 100644 --- a/src/libCom/test/epicsAlgorithmTest.cpp +++ b/src/libCom/test/epicsAlgorithmTest.cpp @@ -9,15 +9,11 @@ // epicsAlgorithmTest.cpp // Authors: Jeff Hill & Andrew Johnson -#include - #include "epicsUnitTest.h" #include "epicsAlgorithm.h" #include "epicsMath.h" #include "testMain.h" -using std::isnan; - MAIN(epicsAlgorithm) { testPlan(22); diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index aae412262..2492c95ba 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -8,7 +8,6 @@ #include #include -#include #include "epicsUnitTest.h" #include "epicsTypes.h" @@ -17,9 +16,6 @@ #include "postfix.h" #include "testMain.h" -using std::isnan; -using std::isinf; - /* Infrastructure for running tests */ double doCalc(const char *expr) { From 24f08460bbca3311db150dffd3275b12e964309d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 16 Dec 2019 10:26:00 -0800 Subject: [PATCH 258/281] Revert "libcom: fix colliding isnan/isinf between C99 and C++0x for gcc-4" This reverts commit 09ec3af3371020278d5c41ca19e170468dc2fc02. --- src/libCom/osi/os/posix/epicsMath.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libCom/osi/os/posix/epicsMath.h b/src/libCom/osi/os/posix/epicsMath.h index 1ef96d76f..13f25e520 100644 --- a/src/libCom/osi/os/posix/epicsMath.h +++ b/src/libCom/osi/os/posix/epicsMath.h @@ -18,10 +18,8 @@ #include using std::isfinite; -#ifndef __GXX_EXPERIMENTAL_CXX0X__ using std::isinf; using std::isnan; -#endif using std::isnormal; extern "C" { From 60a092fa50e36a4843c3b441557d810a828fc333 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 16 Dec 2019 10:28:27 -0800 Subject: [PATCH 259/281] posix/epicsMath.h Include "" for c++11 and pull in non-namespace versions of isnan() and friends. --- src/libCom/osi/os/posix/epicsMath.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libCom/osi/os/posix/epicsMath.h b/src/libCom/osi/os/posix/epicsMath.h index 13f25e520..a8e9b815f 100644 --- a/src/libCom/osi/os/posix/epicsMath.h +++ b/src/libCom/osi/os/posix/epicsMath.h @@ -15,12 +15,14 @@ #ifdef __cplusplus +#if __cplusplus>=201103L #include using std::isfinite; using std::isinf; using std::isnan; using std::isnormal; +#endif extern "C" { #endif From 33f2d8c4aaffae02297397be899714635e468e47 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 4 May 2018 20:27:51 -0700 Subject: [PATCH 260/281] debug epicsTimerTest (cherry picked from commit 2af0c1047067401b01be8c0ad055fb58c21c50f4) --- src/libCom/test/epicsTimerTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsTimerTest.cpp b/src/libCom/test/epicsTimerTest.cpp index f2a510819..d820e64be 100644 --- a/src/libCom/test/epicsTimerTest.cpp +++ b/src/libCom/test/epicsTimerTest.cpp @@ -112,7 +112,7 @@ double delayVerify::checkError () const double actualDelay = this->expireStamp - this->beginStamp; double measuredError = actualDelay - this->expectedDelay; double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay; - if ( ! testOk1 ( percentError < messageThresh ) ) { + if ( ! testOk ( percentError < messageThresh, "%f < %f", percentError, messageThresh ) ) { testDiag ( "delay = %f s, error = %f s (%.1f %%)", this->expectedDelay, measuredError, percentError ); } From e068191684617232b4112eff31abb07f32760046 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 8 Aug 2018 14:36:28 -0700 Subject: [PATCH 261/281] epicsTimerTest loosen test threshold (cherry picked from commit f955199805dc1987cc72f0d2691bf2a80fe796e3) --- src/libCom/test/epicsTimerTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libCom/test/epicsTimerTest.cpp b/src/libCom/test/epicsTimerTest.cpp index d820e64be..aebf3f066 100644 --- a/src/libCom/test/epicsTimerTest.cpp +++ b/src/libCom/test/epicsTimerTest.cpp @@ -108,7 +108,7 @@ inline double delayVerify::delay () const double delayVerify::checkError () const { - const double messageThresh = 2.0; // percent + const double messageThresh = 5.0; // percent double actualDelay = this->expireStamp - this->beginStamp; double measuredError = actualDelay - this->expectedDelay; double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay; From feb938fae2515eb3ad245f51847edfddf6f06706 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Tue, 12 Nov 2019 17:36:10 -0800 Subject: [PATCH 262/281] minor epicsTimerTest (cherry picked from commit 7acd7c61450e2ecc5880cd7d12f12a59ee9d02e4) --- src/libCom/test/epicsTimerTest.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libCom/test/epicsTimerTest.cpp b/src/libCom/test/epicsTimerTest.cpp index aebf3f066..55870ed2d 100644 --- a/src/libCom/test/epicsTimerTest.cpp +++ b/src/libCom/test/epicsTimerTest.cpp @@ -112,10 +112,9 @@ double delayVerify::checkError () const double actualDelay = this->expireStamp - this->beginStamp; double measuredError = actualDelay - this->expectedDelay; double percentError = 100.0 * fabs ( measuredError ) / this->expectedDelay; - if ( ! testOk ( percentError < messageThresh, "%f < %f", percentError, messageThresh ) ) { - testDiag ( "delay = %f s, error = %f s (%.1f %%)", - this->expectedDelay, measuredError, percentError ); - } + testOk ( percentError < messageThresh, "%f < %f, delay = %f s, error = %f s (%.1f %%)", + percentError, messageThresh, + this->expectedDelay, measuredError, percentError ); return measuredError; } From df519ce1a203ac21057d4e9588e50740ee53e1cf Mon Sep 17 00:00:00 2001 From: Martin Konrad Date: Tue, 17 Dec 2019 15:53:41 -0500 Subject: [PATCH 263/281] Fix typos in calcoutRecord.dbd.pod --- src/std/rec/calcoutRecord.dbd.pod | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/std/rec/calcoutRecord.dbd.pod b/src/std/rec/calcoutRecord.dbd.pod index 176f1d25f..a59eaa348 100644 --- a/src/std/rec/calcoutRecord.dbd.pod +++ b/src/std/rec/calcoutRecord.dbd.pod @@ -366,7 +366,7 @@ C<:=> : assigns a value (right hand side) to a variable (i.e. field) =back -=head3 Parantheses, Comma, and Semicolon +=head3 Parentheses, Comma, and Semicolon The open and close parentheses are supported. Nested parentheses are supported. @@ -437,7 +437,7 @@ Result is E if (A + B)<(C + D) =item Result is unchanged if (A + B)>=(C + D) -From 3.14.9 onwards, this expresion must be written as +From 3.14.9 onwards, this expression must be written as C<(A + B) < (C + D) ? E : VAL> =back @@ -505,7 +505,7 @@ C -- write output every time VAL changes, i.e., every time the result of the expression changes. =item * -C -- when record is preocessed, write output if VAL is zero. +C -- when record is processed, write output if VAL is zero. =item * C -- when record is processed, write output if VAL is @@ -531,9 +531,9 @@ output is executed. The field is a menu field with two options: If C is specified, when the record writes its output it will write the result of the expression in the CALC field, that is, it will write the value of the VAL field. If C is specified, -the record will instead write the result of the expresion in the OCAL +the record will instead write the result of the expression in the OCAL field, which is contained in the OVAL field. The OCAL field is exactly like -the CALC field and has the same fuctionality it can contain the string +the CALC field and has the same functionality it can contain the string representation of an expression which is evaluated at run-time. Thus, if necessary, the record can use the result of the CALC expression to determine if data should be written and can use the result of the OCAL @@ -548,7 +548,7 @@ the wait is over. The field DLYA is equal to 1 during the delay period. The resolution of the delay entry system dependent. The IVOA field specifies what action to take with the OUT link if the -Calcout record eneters an INVALID alarm status. The options are +Calcout record enters an INVALID alarm status. The options are C, C, and C. If the IVOA field is C, the data entered into the IVOV field is written to the OUT link if the record alarm severity is @@ -602,7 +602,7 @@ The CLCV and OLCV fields indicate the validity of the expression in the CALC and OCAL fields respectfully. If the expression in invalid, the field is set to one. -The DYLA field is set to one during the delay specified in ODLY. +The DLYA field is set to one during the delay specified in ODLY. See L for more information on the record name (NAME) and description (DESC) fields. @@ -617,7 +617,7 @@ record support routines. The Calculation alarm is called by the record processing routine when the CALC expression is an invalid one, upon which an error message is generated. -The following alarm parametersi, which are configured by the user, define the +The following alarm parameters, which are configured by the user, define the limit alarms for the VAL field and the severity corresponding to those conditions. @@ -633,7 +633,7 @@ common to all record types. These parameters are used to determine when to send monitors for the value fields. These monitors are sent when the value field exceeds the last monitored field by the appropriate deadband, the ADEL for archiver monitors -and the MDEL field for all aother types of monitors. If these fields have a +and the MDEL field for all other types of monitors. If these fields have a value of zero, every time the value changes, monitors are triggered; if they have a value of -1, every time the record is scanned, monitors are triggered. See L for a complete explanation of @@ -1193,13 +1193,13 @@ Retrieves PREC. Sets the upper display and lower display limits for a field. If the field is VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the field has upper and lower limits defined they will be used, else the -upper and lower macimum values for the field type will be used. +upper and lower maximum values for the field type will be used. =head2 C Sets the upper control and lower control limits for a field. If the VAL, HIHI, HIGH, LOW, or LOLO, the limits are set to HOPR and LOPR, else if the -field has upper and lower limits defimed they will be used, else the upper +field has upper and lower limits defined they will be used, else the upper and lower maximum values for the field will be used. =head2 C @@ -1241,7 +1241,7 @@ honors the alarm hysteresis factor (HYST). Thus the value must change by at least HYST before the alarm status and severity changes. =item 4. -Determin if the Output Execution Option (OOPT) is met. If it met, either +Determine if the Output Execution Option (OOPT) is met. If it met, either execute the output link (and output event) immediately (if ODLY = 0), or schedule a callback after the specified interval. See the explanation for the C routine below. @@ -1267,7 +1267,7 @@ NSEV and NSTA are reset to 0 =back =item 6. -If no output delay was specified, scan forwark link if necessaru, set PACT +If no output delay was specified, scan forward link if necessary, set PACT FALSE, and return. =back @@ -1290,7 +1290,7 @@ put the value of OVAL to the OUT link and post the event in OEVT (if non-zero). =item 4. -If an output delay was implemented, process the forwark link. +If an output delay was implemented, process the forward link. =back From d97a12f09556f5aecb9916493f28aaed4b195635 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 18 Dec 2019 19:09:38 -0800 Subject: [PATCH 264/281] travis-ci test trusty w/ c++11 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b68a94223..0ae572504 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,7 +17,7 @@ matrix: - sudo: false dist: trusty compiler: gcc - env: CMPLR=gcc STATIC=YES + env: CMPLR=gcc STATIC=YES CMD_CXXFLAGS=-std=c++11 - sudo: false dist: bionic compiler: gcc From f64f84744e86ee194f29390852bfe7aa0fd096fc Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Wed, 18 Dec 2019 20:02:20 -0800 Subject: [PATCH 265/281] more fun with isinf() and friends. GNU libstdc++ prior to GCC 6.1.0, the overlay math.h always includes math.h from glibc, which defines isinf() and friends. GCC 6.1.0 includes a change (6c8ced3f4f867b72a623fe2f23efa204c5786a28) so that the overlay math.h never includes the glibc math.h when compiling c++. The overlay math.h sometimes includes "using std::isinf" Determined by inspecting libc math.h when building gcc. --- src/libCom/osi/os/posix/epicsMath.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libCom/osi/os/posix/epicsMath.h b/src/libCom/osi/os/posix/epicsMath.h index a8e9b815f..6a76f0afb 100644 --- a/src/libCom/osi/os/posix/epicsMath.h +++ b/src/libCom/osi/os/posix/epicsMath.h @@ -18,11 +18,13 @@ #if __cplusplus>=201103L #include +#if __GLIBCXX__>20160427 using std::isfinite; using std::isinf; using std::isnan; using std::isnormal; #endif +#endif /* c++11 */ extern "C" { #endif From 71278477bc720a89bd0a36c4f2289b8dce842d34 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 Dec 2019 00:08:18 -0600 Subject: [PATCH 266/281] Update submodules --- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pva2pva | 2 +- modules/pvaClient | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/pvAccess b/modules/pvAccess index a01869bbd..7903a736d 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit a01869bbd0d4783346f8fd61072e8816b074ea73 +Subproject commit 7903a736d4dfdfec44fa8d02681efaf74b7137ea diff --git a/modules/pvData b/modules/pvData index ca2ae0d0e..07b75e454 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit ca2ae0d0e7784f38f1f584431b7a6518c91bcc42 +Subproject commit 07b75e45439f9d4416f2512094c3c11b95b6d70a diff --git a/modules/pva2pva b/modules/pva2pva index 21ae75486..536f4dd02 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 21ae7548696f27b5333e3d669da908bd41afd3a5 +Subproject commit 536f4dd02f7fb3f117fda6bdbe1bbe51ca1257ca diff --git a/modules/pvaClient b/modules/pvaClient index 5961c8347..9add9daf8 160000 --- a/modules/pvaClient +++ b/modules/pvaClient @@ -1 +1 @@ -Subproject commit 5961c834773d6aecc51ac33601a93f04658a1adb +Subproject commit 9add9daf85bc5cc970bf43be798f013d64263332 From cb0d8d1297d1efc17b52064141f0e8ca9cd5aef8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 19 Dec 2019 19:31:21 -0800 Subject: [PATCH 267/281] update PVA --- modules/pvAccess | 2 +- modules/pvData | 2 +- modules/pva2pva | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/pvAccess b/modules/pvAccess index 7903a736d..9a02377b3 160000 --- a/modules/pvAccess +++ b/modules/pvAccess @@ -1 +1 @@ -Subproject commit 7903a736d4dfdfec44fa8d02681efaf74b7137ea +Subproject commit 9a02377b3d5e1cbdce619ffeeeed9240748aa3af diff --git a/modules/pvData b/modules/pvData index 07b75e454..94eff54fa 160000 --- a/modules/pvData +++ b/modules/pvData @@ -1 +1 @@ -Subproject commit 07b75e45439f9d4416f2512094c3c11b95b6d70a +Subproject commit 94eff54fa99879bfaa2020806f18b169acc7f764 diff --git a/modules/pva2pva b/modules/pva2pva index 536f4dd02..1d9fbbea0 160000 --- a/modules/pva2pva +++ b/modules/pva2pva @@ -1 +1 @@ -Subproject commit 536f4dd02f7fb3f117fda6bdbe1bbe51ca1257ca +Subproject commit 1d9fbbea0b2abba9cf41439be618580e4cf95d89 From 5dc79954770834214523fa2aac8629746426565e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 27 Dec 2019 17:36:37 -0600 Subject: [PATCH 268/281] Enable IOC debug output in netget.plt --- modules/database/test/std/rec/netget.plt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/test/std/rec/netget.plt b/modules/database/test/std/rec/netget.plt index 75a4f4565..fcc75442e 100644 --- a/modules/database/test/std/rec/netget.plt +++ b/modules/database/test/std/rec/netget.plt @@ -28,7 +28,7 @@ my $exe = ($^O =~ m/^(MSWin32|cygwin)$/x) ? '.exe' : ''; my $prefix = "test-$$"; my $ioc = EPICS::IOC->new(); -#$ioc->debug(1); +$ioc->debug(1); $SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub { $ioc->kill; From 70ea8d5476bb2bdd2bad7d6ec45d5106e3f22855 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 31 Dec 2019 22:15:22 -0600 Subject: [PATCH 269/281] Make EPICS::IOC->_geterrors() return on EOF from IOC's stderr --- modules/database/src/tools/EPICS/IOC.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/database/src/tools/EPICS/IOC.pm b/modules/database/src/tools/EPICS/IOC.pm index 9eae9d4fd..1cdae3d14 100644 --- a/modules/database/src/tools/EPICS/IOC.pm +++ b/modules/database/src/tools/EPICS/IOC.pm @@ -266,7 +266,8 @@ sub _geterrors { my @errors; while ($self->{select}->can_read(0.01)) { - sysread $self->{stderr}, my $errbuf, 1024; + my $n = sysread $self->{stderr}, my $errbuf, 1024; + return @errors unless $n; # $n is 0 on EOF push @errors, split m/\n/, $self->{errbuf} . $errbuf, -1; last unless @errors; $self->{errbuf} = pop @errors; From b62ab817c64daaf6873b83a7b083146415f51b23 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 31 Dec 2019 22:21:03 -0600 Subject: [PATCH 270/281] Replace EPICS::IOC->kill() with exit() and close() methods --- modules/database/src/tools/EPICS/IOC.pm | 61 ++++++++++++++++-------- modules/database/test/std/rec/netget.plt | 6 +-- 2 files changed, 43 insertions(+), 24 deletions(-) diff --git a/modules/database/src/tools/EPICS/IOC.pm b/modules/database/src/tools/EPICS/IOC.pm index 1cdae3d14..157aea0ca 100644 --- a/modules/database/src/tools/EPICS/IOC.pm +++ b/modules/database/src/tools/EPICS/IOC.pm @@ -29,7 +29,7 @@ EPICS::IOC - Manage an EPICS IOC my @records = $ioc->dbl; my @values = map { $ioc->dbgf($_); } @records; - $ioc->kill; + $ioc->exit; =head1 DESCRIPTION @@ -58,7 +58,8 @@ use IO::Select; Calling C creates an C object that can be used to start and interact with a single IOC. After this IOC has been shut down (by calling its -C method) the C object may be reused for another IOC. +C or C methods) the C object may be reused for another +IOC. =back @@ -162,9 +163,9 @@ sub pid { =item started () -Returns a true value if the IOC has been started and not yet killed. This state -will not change if the IOC dies by itself, it indicates that the start method -has been called without the kill method. +Returns a true value if the IOC has been started and not yet closed. This state +will not change if the IOC dies by itself, it indicates that the C +method has been called but not the C method. =cut @@ -253,7 +254,7 @@ sub _getlines { =item _geterrors ( ) Returns a list of lines output by the IOC to stderr since last called. Only -complete lines are included, and trailing newlines have been removed. +complete lines are included, with trailing newline char's removed. NOTE: This doesn't work on Windows because it uses select which Perl doesn't support on that OS, but it doesn't seem to cause any problems for short-lived @@ -324,25 +325,43 @@ sub cmd { return @response; } -=item kill () +=item exit () -The C method attempts to stop an IOC that is still running in several -ways. First it sends an C command to the IOC shell. Next it closes the -IOC's stdin stream which will trigger an end-of-file on that stream, and it -fetches any remaining lines from the IOC's stdout stream before closing both -that and the stderr stream. Finally (unless running on MS-Windows) it sends a -SIGTERM signal to the child process and waits for it to clean up. +The C method attempts to stop and clean up after an IOC that is still +running. It sends an C command to the IOC shell (without waiting for a +response), then calls the C method to finish the task of shutting down +the IOC process and tidying up after it. =cut -sub kill { - my $self = shift; +sub exit { + my $self = $_[0]; return () unless $self->started; $self->_send("exit\n"); # Don't wait + goto &close; +} + +=item close () + +The C method first closes the IOC's stdin stream, which will trigger an +end-of-file to the IOC shell, then it fetches any remaining lines from the +IOC's stdout stream before closing both that and the stderr stream. Finally +(unless we're running on MS-Windows) it sends a SIGTERM signal to the child +process and waits for it to clean up. A list containing the final output from +the IOC's stdout stream is returned. + +=cut + +sub close { + my $self = shift; + + return () + unless $self->started; + close $self->{stdin}; $self->{stdin} = gensym; @@ -354,7 +373,7 @@ sub kill { close $self->{stderr}; $self->{stderr} = gensym; - if ($^O ne "MSWin32") { + if ($^O ne 'MSWin32') { kill 'TERM', $self->{pid}; waitpid $self->{pid}, 0; } @@ -365,15 +384,15 @@ sub kill { =item DESTROY () -C objects have a destructor which calls the C method, but it -is not recommended that this be relied on to terminate an IOC process. Better to -use an C block and/or trap the necessary signals to explicitly kill the -IOC. +C objects have a destructor which calls the C method, but it +is not recommended that this be relied on to terminate an IOC process. Better +to use an C block and/or trap the necessary signals and explicitly +C or C the IOC. =cut sub DESTROY { - shift->kill; + shift->exit; } diff --git a/modules/database/test/std/rec/netget.plt b/modules/database/test/std/rec/netget.plt index fcc75442e..f050aa5c6 100644 --- a/modules/database/test/std/rec/netget.plt +++ b/modules/database/test/std/rec/netget.plt @@ -31,7 +31,7 @@ my $ioc = EPICS::IOC->new(); $ioc->debug(1); $SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub { - $ioc->kill; + $ioc->exit; BAIL_OUT('Caught signal'); }; @@ -41,7 +41,7 @@ $SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub { sub kill_bail { my $doing = shift; return sub { - $ioc->kill; + $ioc->exit; BAIL_OUT("Timeout $doing"); } } @@ -137,4 +137,4 @@ SKIP: { } 10, kill_bail('doing pvget'); } -$ioc->kill; +$ioc->exit; From 83d29414054efc2144fa129400cbed02d22a22ba Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 31 Dec 2019 22:28:43 -0600 Subject: [PATCH 271/281] netget: Run caget and pvget using EPICS::IOC instead of `back-ticks` This lets us collect and echo their stderr streams, and if they hang up without responding we can kill them directly instead of just giving up and bailing out. Left debug output turned on for now. --- modules/database/test/std/rec/netget.plt | 40 ++++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/modules/database/test/std/rec/netget.plt b/modules/database/test/std/rec/netget.plt index f050aa5c6..3c4ae0411 100644 --- a/modules/database/test/std/rec/netget.plt +++ b/modules/database/test/std/rec/netget.plt @@ -8,6 +8,9 @@ use lib '@TOP@/lib/perl'; use Test::More tests => 3; use EPICS::IOC; +# Set to 1 to echo all IOC and client communications +my $debug = 1; + $ENV{HARNESS_ACTIVE} = 1 if scalar @ARGV && shift eq '-tap'; # Keep traffic local and avoid duplicates over multiple interfaces @@ -23,12 +26,12 @@ $ENV{EPICS_PVAS_SERVER_PORT} = 55075; $ENV{EPICS_PVA_BROADCAST_PORT} = 55076; $ENV{EPICS_PVAS_INTF_ADDR_LIST} = 'localhost'; -my $bin = "@TOP@/bin/@ARCH@"; +my $bin = '@TOP@/bin/@ARCH@'; my $exe = ($^O =~ m/^(MSWin32|cygwin)$/x) ? '.exe' : ''; my $prefix = "test-$$"; my $ioc = EPICS::IOC->new(); -$ioc->debug(1); +$ioc->debug($debug); $SIG{__DIE__} = $SIG{INT} = $SIG{QUIT} = sub { $ioc->exit; @@ -87,6 +90,19 @@ like($version, qr/^ \d+ \. \d+ \. \d+ /x, "Got BaseVersion '$version' from iocsh"); +# Client Tests + +my $client = EPICS::IOC->new; +$client->debug($debug); + +sub close_client { + my $doing = shift; + return sub { + $client->close; + fail("Timeout $doing"); + } +} + # Channel Access SKIP: { @@ -104,10 +120,16 @@ SKIP: { # CA Client test watchdog { - my $caVersion = `$caget -w5 $pv`; + $client->start($caget, '-w5', $pv); + my $caVersion = $client->_getline; like($caVersion, qr/^ $pv \s+ \Q$version\E $/x, 'Got same BaseVersion from caget'); - } 10, kill_bail('doing caget'); + my @errors = $client->_geterrors; + note("Errors from caget:\n", + map(" $_\n", @errors)) + if scalar @errors; + $client->close; + } 10, close_client('doing caget'); } @@ -131,10 +153,16 @@ SKIP: { # PVA Client test watchdog { - my $pvaVersion = `$pvget -w5 $pv`; + $client->start($pvget, '-w5', $pv); + my $pvaVersion = $client->_getline; like($pvaVersion, qr/^ $pv \s .* \Q$version\E \s* $/x, 'Got same BaseVersion from pvget'); - } 10, kill_bail('doing pvget'); + my @errors = $client->_geterrors; + note("Errors from pvget:\n", + map(" $_\n", @errors)) + if scalar @errors; + $client->close; + } 10, close_client('doing pvget'); } $ioc->exit; From aad8a96b0d7834debe2576e18dbc4fed3d743e4c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 1 Jan 2020 00:08:06 -0600 Subject: [PATCH 272/281] Increase timeout for caget to 15 seconds --- modules/database/test/std/rec/netget.plt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/database/test/std/rec/netget.plt b/modules/database/test/std/rec/netget.plt index 3c4ae0411..376057702 100644 --- a/modules/database/test/std/rec/netget.plt +++ b/modules/database/test/std/rec/netget.plt @@ -129,7 +129,7 @@ SKIP: { map(" $_\n", @errors)) if scalar @errors; $client->close; - } 10, close_client('doing caget'); + } 15, close_client('doing caget'); } From 81df1b2892f5a3c8e32dbaf371f7c59d1dde58e3 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 1 Jan 2020 00:14:08 -0600 Subject: [PATCH 273/281] Rearrange EPICS::IOC->close() to be more robust --- modules/database/src/tools/EPICS/IOC.pm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/modules/database/src/tools/EPICS/IOC.pm b/modules/database/src/tools/EPICS/IOC.pm index 157aea0ca..05c90b59c 100644 --- a/modules/database/src/tools/EPICS/IOC.pm +++ b/modules/database/src/tools/EPICS/IOC.pm @@ -363,21 +363,25 @@ sub close { unless $self->started; close $self->{stdin}; - $self->{stdin} = gensym; my @response = $self->_getlines; # No terminator close $self->{stdout}; - $self->{stdout} = gensym; $self->{select}->remove($self->{stderr}); close $self->{stderr}; + + my $pid = $self->{pid}; + + # Reset these before we call waitpid in case of timeout + $self->{pid} = undef; + $self->{stdin} = gensym; + $self->{stdout} = gensym; $self->{stderr} = gensym; if ($^O ne 'MSWin32') { - kill 'TERM', $self->{pid}; - waitpid $self->{pid}, 0; + kill 'TERM', $pid; + waitpid $pid, 0; } - $self->{pid} = undef; return @response; } From 3b20e71da5d7681c545d7588d7f1dc9238b167bf Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 1 Jan 2020 15:03:40 -0600 Subject: [PATCH 274/281] EPICS::IOC.pm Save parms, more debug annotations --- modules/database/src/tools/EPICS/IOC.pm | 25 +++++++++++++++++------- modules/database/test/std/rec/netget.plt | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/modules/database/src/tools/EPICS/IOC.pm b/modules/database/src/tools/EPICS/IOC.pm index 05c90b59c..611d906e6 100644 --- a/modules/database/src/tools/EPICS/IOC.pm +++ b/modules/database/src/tools/EPICS/IOC.pm @@ -210,17 +210,24 @@ undef value will be returned. sub _getline { my $self = shift; + my $pid = $self->pid; + return undef + unless $self->started; - my $line = readline $self->{stdout}; + # Save, could be closed by a timeout during readline + my $stdout = $self->{stdout}; + my $debug = $self->{debug}; + + my $line = readline $stdout; if (defined $line) { $line =~ s/[\r\n]+ $//x; # chomp broken on Windows? - printf "#%d >> %s\n", $self->{pid}, $line if $self->{debug}; + printf "#%d >> %s\n", $pid, $line if $debug; } - elsif (eof($self->{stdout})) { - printf "#%d >> \n", $self->{pid} if $self->{debug}; + elsif (eof($stdout)) { + printf "#%d >> \n", $pid if $debug; } else { - printf "#%d Error: %s\n", $self->{pid}, $! if $self->{debug}; + printf "#%d Error: %s\n", $pid, $! if $debug; } return $line; } @@ -362,6 +369,10 @@ sub close { return () unless $self->started; + my $pid = $self->{pid}; + my $debug = $self->{debug}; + + printf "#%d << \n", $pid if $debug; close $self->{stdin}; my @response = $self->_getlines; # No terminator @@ -370,8 +381,6 @@ sub close { $self->{select}->remove($self->{stderr}); close $self->{stderr}; - my $pid = $self->{pid}; - # Reset these before we call waitpid in case of timeout $self->{pid} = undef; $self->{stdin} = gensym; @@ -379,8 +388,10 @@ sub close { $self->{stderr} = gensym; if ($^O ne 'MSWin32') { + printf "#%d killing ... ", $pid if $debug; kill 'TERM', $pid; waitpid $pid, 0; + printf "%d dead.\n", $pid if $debug; } return @response; diff --git a/modules/database/test/std/rec/netget.plt b/modules/database/test/std/rec/netget.plt index 376057702..075717d78 100644 --- a/modules/database/test/std/rec/netget.plt +++ b/modules/database/test/std/rec/netget.plt @@ -98,8 +98,8 @@ $client->debug($debug); sub close_client { my $doing = shift; return sub { + diag("Timeout $doing"); $client->close; - fail("Timeout $doing"); } } From 06728e0e0be5e0a0183e6408f083c208f8bd1584 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 2 Jan 2020 16:22:35 -0600 Subject: [PATCH 275/281] Run epicsThreadTest::testJoining with different priorities A problem in the VxWorks epicsThreadMustJoin() only occurs when the joining thread runs at a higher priority than its supervisor. --- modules/libcom/test/epicsThreadTest.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/modules/libcom/test/epicsThreadTest.cpp b/modules/libcom/test/epicsThreadTest.cpp index 4796438a1..46f116f9c 100644 --- a/modules/libcom/test/epicsThreadTest.cpp +++ b/modules/libcom/test/epicsThreadTest.cpp @@ -151,18 +151,26 @@ void joinTests(void *arg) void testJoining() { - epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + epicsThreadOpts opts1 = EPICS_THREAD_OPTS_INIT; + epicsThreadOpts opts2 = EPICS_THREAD_OPTS_INIT; epicsEvent finished, trigger; struct joinStuff stuff = { - &opts, &trigger, &finished + &opts1, &trigger, &finished }; - opts.priority = 50; - opts.joinable = 1; - epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts); + opts1.priority = 50; + opts2.priority = 40; + opts1.joinable = 1; + opts2.joinable = 1; + epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts2); - // as selfjoin joins itself, we can't. - testOk(finished.wait(10.0), "Join tests completed"); + // Thread 'parent' joins itself, so we can't. + testOk(finished.wait(10.0), "Join tests #1 completed"); + + // Repeat with opposite thread priorities + stuff.opts = &opts2; + epicsThreadCreateOpt("parent", &joinTests, &stuff, &opts1); + testOk(finished.wait(10.0), "Join tests #2 completed"); } } // namespace @@ -211,7 +219,7 @@ static void testOkToBlock() MAIN(epicsThreadTest) { - testPlan(13); + testPlan(15); unsigned int ncpus = epicsThreadGetCPUs(); testDiag("System has %u CPUs", ncpus); From 05e0381b191aeea29cfe7286c0797c6faf99f53c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 2 Jan 2020 16:39:10 -0600 Subject: [PATCH 276/281] Fix VxWorks epicsThreadMustJoin() problems taskWait() actually returns OK on timeout, so drop the timeout warning (the other implementations don't have one). The taskWait() may return ERROR with S_objLib_OBJ_ID_ERROR if the target thread has higher priority; this indicates a successful join, because we already did a rendezvous using joinSem. Delete joinSem *after* calling taskSpareFieldSet(), in case it matters. --- modules/libcom/src/osi/os/vxWorks/osdThread.c | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 0ed31389f..1eaea3a3c 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -211,16 +211,20 @@ void epicsThreadAwaitingJoin(int tid) if (status) perror("epicsThreadAwaitingJoin"); - semDelete(joinSem); taskSpareFieldSet(tid, joinField, 0); + semDelete(joinSem); } #define PREPARE_JOIN(tid, joinable) \ taskSpareFieldSet(tid, joinField, \ joinable ? (int) semBCreate(SEM_Q_FIFO, SEM_EMPTY) : 0) - #define AWAIT_JOIN(tid) epicsThreadAwaitingJoin(tid) + #define AWAIT_JOIN(tid) \ + epicsThreadAwaitingJoin(tid) + #else + #define PREPARE_JOIN(tid, joinable) #define AWAIT_JOIN(tid) + #endif static void createFunction(EPICSTHREADFUNC func, void *parm) @@ -297,48 +301,34 @@ void epicsThreadMustJoin(epicsThreadId id) joinSem = (SEM_ID) taskSpareFieldGet(tid, joinField); if ((int) joinSem == ERROR) { - errlogPrintf("%s: Thread '%s' no longer exists.\n", - fn, taskName(tid)); + errlogPrintf("%s: Thread %#x no longer exists.\n", fn, tid); return; } if (tid == taskIdSelf()) { if (joinSem) { - semDelete(joinSem); taskSpareFieldSet(tid, joinField, 0); + semDelete(joinSem); } else { - errlogPrintf("%s: Self-join of unjoinable thread '%s'\n", - fn, taskName(tid)); + errlogPrintf("%s: Thread '%s' (%#x) can't self-join.\n", + fn, epicsThreadGetNameSelf(), tid); } return; } if (!joinSem) { - cantProceed("%s: Thread '%s' is not joinable.\n", - fn, taskName(tid)); + cantProceed("%s: Thread '%s' (%#x) is not joinable.\n", + fn, taskName(tid), tid); return; } semGive(joinSem); /* Rendezvous with thread */ - status = taskWait(tid, JOIN_WARNING_TIMEOUT); - if (status && errno == S_objLib_OBJ_TIMEOUT) { - errlogPrintf("Warning: %s still waiting for thread '%s'\n", - fn, taskName(tid)); - status = taskWait(tid, WAIT_FOREVER); - } - if (status) { - if (errno == S_taskLib_ILLEGAL_OPERATION) { - errlogPrintf("%s: This shouldn't happen!\n", fn); - } - else if (errno == S_objLib_OBJ_ID_ERROR) { - errlogPrintf("%s: %x is not a known thread\n", fn, tid); - } - else { - perror(fn); - } - cantProceed(fn); + status = taskWait(tid, WAIT_FOREVER); + if (status && errno != S_objLib_OBJ_ID_ERROR) { + perror(fn); + cantProceed("%s: ", fn); } #endif } From 8f358f4dd87fe6fb8fb40c426af652d383840b04 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 2 Jan 2020 16:41:55 -0600 Subject: [PATCH 277/281] VxWorks::osdThread: Rename createFunction => epicsThreadEntry and make it visible (non-static) so it appears in back-traces. --- modules/libcom/src/osi/os/vxWorks/osdThread.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/libcom/src/osi/os/vxWorks/osdThread.c b/modules/libcom/src/osi/os/vxWorks/osdThread.c index 1eaea3a3c..babdf11cf 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdThread.c +++ b/modules/libcom/src/osi/os/vxWorks/osdThread.c @@ -190,8 +190,8 @@ void epicsThreadOnce(epicsThreadOnceId *id, void (*func)(void *), void *arg) #ifdef EPICS_THREAD_CAN_JOIN -/* This routine is not static so it appears in the back-trace - * of a thread that is waiting to be joined. +/* The next 2 routines are not static so they appear in the back-trace + * of the epicsThreads that have called them. */ void epicsThreadAwaitingJoin(int tid) { @@ -227,7 +227,7 @@ void epicsThreadAwaitingJoin(int tid) #endif -static void createFunction(EPICSTHREADFUNC func, void *parm) +void epicsThreadEntry(EPICSTHREADFUNC func, void *parm) { int tid = taskIdSelf(); @@ -274,7 +274,7 @@ epicsThreadId epicsThreadCreateOpt(const char * name, tid = taskCreate((char *)name,getOssPriorityValue(opts->priority), TASK_FLAGS, stackSize, - (FUNCPTR)createFunction, (int)funptr, (int)parm, + (FUNCPTR)epicsThreadEntry, (int)funptr, (int)parm, 0,0,0,0,0,0,0,0); if (tid == ERROR) { errlogPrintf("epicsThreadCreate %s failure %s\n", From 468f965dc2753e7a381dcc09dd9b5656e3149ac2 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 5 Jan 2020 16:52:40 -0800 Subject: [PATCH 278/281] dbLoadTemplate.h missing extern "C" --- modules/database/src/ioc/dbtemplate/dbLoadTemplate.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h index a6ca60617..d08357b6e 100644 --- a/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h +++ b/modules/database/src/ioc/dbtemplate/dbLoadTemplate.h @@ -12,7 +12,16 @@ #define INCdbLoadTemplateh #include "shareLib.h" + +#ifdef __cplusplus +extern "C" { +#endif + epicsShareFunc int dbLoadTemplate( const char *sub_file, const char *cmd_collect); +#ifdef __cplusplus +} +#endif + #endif /*INCdbLoadTemplateh*/ From 8dc131dc4cc04eef3df513a978576442af9405b1 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 12 Jan 2020 10:32:15 -0800 Subject: [PATCH 279/281] osiSockTest test epicsSocketEnableAddressUseForDatagramFanout() --- modules/libcom/test/osiSockTest.c | 63 ++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/modules/libcom/test/osiSockTest.c b/modules/libcom/test/osiSockTest.c index 6672cdbd3..39777fc10 100644 --- a/modules/libcom/test/osiSockTest.c +++ b/modules/libcom/test/osiSockTest.c @@ -77,15 +77,76 @@ void udpSockTest(void) } +static +int doBind(int expect, SOCKET S, unsigned* port) +{ + osiSockAddr addr; + int ret; + + memset(&addr, 0, sizeof(addr)); + addr.ia.sin_family = AF_INET; + addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + addr.ia.sin_port = htons(*port); + + ret = bind(S, &addr.sa, sizeof(addr.ia)); + if(ret) { + testOk(expect==1, "bind() to %u error %d, %d", *port, ret, SOCKERRNO); + return 1; + } else { + osiSocklen_t slen = sizeof(addr); + ret = getsockname(S, &addr.sa, &slen); + if(ret) { + testFail("Unable to find sock name after binding"); + return 1; + } else { + *port = ntohs(addr.ia.sin_port); + testOk(expect==0, "bind() to port %u", *port); + return 0; + } + } +} + +void udpSockFanoutTest(void) +{ + SOCKET A, B, C; + unsigned port=0; /* choose random port */ + + A = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + B = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + C = epicsSocketCreate(AF_INET, SOCK_DGRAM, 0); + + if(A==INVALID_SOCKET || B==INVALID_SOCKET || C==INVALID_SOCKET) + testAbort("Insufficient sockets"); + + /* not A */ + epicsSocketEnableAddressUseForDatagramFanout(B); + epicsSocketEnableAddressUseForDatagramFanout(C); + + testDiag("First test if epicsSocketEnableAddressUseForDatagramFanout() is necessary"); + + doBind(0, A, &port); + doBind(1, B, &port); /* expect failure */ + + epicsSocketDestroy(A); + + testDiag("Now the real test"); + doBind(0, B, &port); + doBind(0, C, &port); + + epicsSocketDestroy(B); + epicsSocketDestroy(C); +} + MAIN(osiSockTest) { int status; - testPlan(14); + testPlan(18); status = osiSockAttach(); testOk(status, "osiSockAttach"); udpSockTest(); + udpSockFanoutTest(); osiSockRelease(); return testDone(); From 65ef6e9d5946bff8dee1d140245b12f9073a9252 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 12 Jan 2020 11:00:13 -0800 Subject: [PATCH 280/281] posix epicsSocketEnableAddressUseForDatagramFanout() prefer SO_REUSEPORT prefer SO_REUSEPORT on targets which define it. Linux defines both, and seems to treat SO_REUSEPORT and SO_REUSEADDR as equivalent. BSD derivatives need SO_REUSEPORT. --- .../src/osi/os/posix/osdSockAddrReuse.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp b/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp index 3a3f78ebd..bac6a587e 100644 --- a/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp +++ b/modules/libcom/src/osi/os/posix/osdSockAddrReuse.cpp @@ -12,6 +12,9 @@ /* * Author: Jeff Hill */ +#if defined(__rtems__) +# define __BSD_VISIBLE 1 +#endif #define epicsExportSharedSymbols #include "osiSock.h" @@ -31,19 +34,23 @@ epicsShareFunc void epicsShareAPI } } -/* - * SO_REUSEPORT is not in POSIX - */ +#ifdef SO_REUSEPORT +# define X_REUSEUDP SO_REUSEPORT +#else +# define X_REUSEUDP SO_REUSEADDR +#endif + epicsShareFunc void epicsShareAPI epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ) { int yes = true; int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEADDR, + status = setsockopt ( s, SOL_SOCKET, X_REUSEUDP, (char *) & yes, sizeof ( yes ) ); if ( status < 0 ) { errlogPrintf ( "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEADDR?\n"); + "unable to set %s?\n", + (X_REUSEUDP==SO_REUSEADDR)?"SO_REUSEADDR":"SO_REUSEPORT"); } } From d0c4cc0cec8d31b88ee480d2d7f007f17cf0cdbf Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 12 Jan 2020 11:07:01 -0800 Subject: [PATCH 281/281] Darwin/iOS use posix osdSockAddrReuse.cpp Redundant now that the posix version prefers SO_REUSEPORT if defined. --- .../src/osi/os/Darwin/osdSockAddrReuse.cpp | 48 ------------------- .../src/osi/os/iOS/osdSockAddrReuse.cpp | 47 ------------------ 2 files changed, 95 deletions(-) delete mode 100644 modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp delete mode 100644 modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp diff --git a/modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp b/modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp deleted file mode 100644 index 869514160..000000000 --- a/modules/libcom/src/osi/os/Darwin/osdSockAddrReuse.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2002 The University of Chicago, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE Versions 3.13.7 -* and higher are distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author: Jeff Hill - */ - -#define epicsExportSharedSymbols -#include "osiSock.h" -#include "errlog.h" - -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressReuseDuringTimeWaitState ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEADDR, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEADDR?\n"); - } -} - -/* - * SO_REUSEPORT is not in POSIX - */ -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEPORT, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEPORT?\n"); - } -} diff --git a/modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp b/modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp deleted file mode 100644 index 9f64e331a..000000000 --- a/modules/libcom/src/osi/os/iOS/osdSockAddrReuse.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/*************************************************************************\ -* Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne -* National Laboratory. -* Copyright (c) 2002 The Regents of the University of California, as -* Operator of Los Alamos National Laboratory. -* EPICS BASE is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author: Jeff Hill - */ - -#define epicsExportSharedSymbols -#include "osiSock.h" -#include "errlog.h" - -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressReuseDuringTimeWaitState ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEADDR, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEADDR?\n"); - } -} - -/* - * SO_REUSEPORT is not in POSIX - */ -epicsShareFunc void epicsShareAPI - epicsSocketEnableAddressUseForDatagramFanout ( SOCKET s ) -{ - int yes = true; - int status; - status = setsockopt ( s, SOL_SOCKET, SO_REUSEPORT, - (char *) & yes, sizeof ( yes ) ); - if ( status < 0 ) { - errlogPrintf ( - "epicsSocketEnablePortUseForDatagramFanout: " - "unable to set SO_REUSEPORT?\n"); - } -}