diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 5655c5d91..8c9cef1aa 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -14,6 +14,16 @@

Changes between 3.15.3 and 3.15.4

+

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 +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 +called by the IOC at iocInit (unless disabled by setting the global variable +dbThreadRealtimeLock to zero).

+

Added dbQuietMacroWarnings control

When loading database files, macros get expanded even on comment lines. If a diff --git a/src/ioc/misc/dbCore.dbd b/src/ioc/misc/dbCore.dbd index 1fec39eca..42e84c251 100644 --- a/src/ioc/misc/dbCore.dbd +++ b/src/ioc/misc/dbCore.dbd @@ -20,3 +20,6 @@ variable(dbQuietMacroWarnings,int) variable(dbTemplateMaxVars,int) # Default number of parallel callback threads variable(callbackParallelThreadsDefault,int) + +# Real-time operation +variable(dbThreadRealtimeLock,int) diff --git a/src/ioc/misc/iocInit.c b/src/ioc/misc/iocInit.c index 1e30eeb77..791516983 100644 --- a/src/ioc/misc/iocInit.c +++ b/src/ioc/misc/iocInit.c @@ -36,7 +36,7 @@ #include "caeventmask.h" -#define epicsExportSharedSymbols +#include "epicsExport.h" /* defines epicsExportSharedSymbols */ #include "alarm.h" #include "asDbLib.h" #include "callback.h" @@ -86,7 +86,9 @@ static void initDatabase(void); static void initialProcess(void); static void exitDatabase(void *dummy); - +int dbThreadRealtimeLock = 1; +epicsExportAddress(int, dbThreadRealtimeLock); + /* * Initialize EPICS on the IOC. */ @@ -186,6 +188,10 @@ int iocBuild(void) rsrv_init(); status = iocBuild_3(); + + if (dbThreadRealtimeLock) + epicsThreadRealtimeLock(); + if (!status) iocBuildMode = buildRSRV; return status; } diff --git a/src/libCom/osi/epicsThread.h b/src/libCom/osi/epicsThread.h index fa28215d3..141044661 100644 --- a/src/libCom/osi/epicsThread.h +++ b/src/libCom/osi/epicsThread.h @@ -57,6 +57,12 @@ typedef epicsThreadId epicsThreadOnceId; epicsShareFunc void epicsShareAPI epicsThreadOnce( epicsThreadOnceId *id, EPICSTHREADFUNC, void *arg); +/* When real-time scheduling is active, attempt any post-init operations + * that preserve real-time performance. For POSIX targets this locks the + * process into RAM, preventing swap-related VM faults. + */ +epicsShareFunc void epicsThreadRealtimeLock(void); + epicsShareFunc void epicsShareAPI epicsThreadExitMain(void); epicsShareFunc epicsThreadId epicsShareAPI epicsThreadCreate ( diff --git a/src/libCom/osi/os/RTEMS/osdThread.c b/src/libCom/osi/os/RTEMS/osdThread.c index 0102157d6..1fa032820 100644 --- a/src/libCom/osi/os/RTEMS/osdThread.c +++ b/src/libCom/osi/os/RTEMS/osdThread.c @@ -248,6 +248,9 @@ epicsThreadInit (void) } } +void epicsThreadRealtimeLock(void) +{} + /* * Create and start a new thread */ diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index 48cd8cb4e..9d45e28e0 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -303,6 +303,10 @@ static unsigned osdPriorityMagFromPriorityOSI ( unsigned osiPriority, unsigned p return magnitude; } +epicsShareFunc +void epicsThreadRealtimeLock(void) +{} + /* * epicsThreadGetOsdPriorityValue () */ diff --git a/src/libCom/osi/os/posix/osdThread.c b/src/libCom/osi/os/posix/osdThread.c index 57d663faa..755390eed 100644 --- a/src/libCom/osi/os/posix/osdThread.c +++ b/src/libCom/osi/os/posix/osdThread.c @@ -357,21 +357,10 @@ static void once(void) pcommonAttr->maxPriority); } -#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0 - if(errVerbose) { - fprintf(stderr, "LRT: min priority: %d max priority %d\n", + if (errVerbose) { + fprintf(stderr, "LRT: min priority: %d max priority %d\n", pcommonAttr->minPriority, pcommonAttr->maxPriority); } - if (pcommonAttr->maxPriority > pcommonAttr->minPriority) { - status = mlockall(MCL_CURRENT | MCL_FUTURE); - if(status) { - fprintf(stderr, "Unable to lock the virtual address space using mlockall\n"); - } else { - fprintf(stderr,"Successfully locked memory using mlockAll\n"); - } - } -#endif - #else if(errVerbose) fprintf(stderr,"task priorities are not implemented\n"); @@ -425,7 +414,22 @@ static void epicsThreadInit(void) checkStatusQuit(status,"pthread_once","epicsThreadInit"); } - +epicsShareFunc +void epicsThreadRealtimeLock(void) +{ +#if defined(_POSIX_MEMLOCK) && _POSIX_MEMLOCK > 0 + if (pcommonAttr->maxPriority > pcommonAttr->minPriority) { + int status = mlockall(MCL_CURRENT | MCL_FUTURE); + + if (status) { + fprintf(stderr, "epicsThreadRealtimeLock " + "Warning: Unable to lock the virtual address space.\n" + "VM page faults may harm real-time performance.\n"); + } + } +#endif +} + epicsShareFunc unsigned int epicsShareAPI epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) { #if defined (OSITHREAD_USE_DEFAULT_STACK) diff --git a/src/libCom/osi/os/vxWorks/osdThread.c b/src/libCom/osi/os/vxWorks/osdThread.c index 9a6e8cb3b..ce01ea609 100644 --- a/src/libCom/osi/os/vxWorks/osdThread.c +++ b/src/libCom/osi/os/vxWorks/osdThread.c @@ -114,6 +114,9 @@ static void epicsThreadInit(void) lock = 0; } +void epicsThreadRealtimeLock(void) +{} + unsigned int epicsThreadGetStackSize (epicsThreadStackSizeClass stackSizeClass) {