From dc579b78db205414588bce2be64863448622fc8e Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sat, 19 Sep 2020 00:07:06 +0100 Subject: [PATCH 01/22] * Fix and enable usage of QueryPerformanceCounter() * Use GetTickCount64() as fallback on Windows Vista and above --- .../libcom/src/osi/os/WIN32/osdMonotonic.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index cb846433e..e9fce3834 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -14,17 +14,18 @@ #include "generalTimeSup.h" static unsigned char osdUsePrefCounter; -static epicsUInt64 osdMonotonicResolution; +static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */ +static double perfCounterScale; /* convert performance counter tics to nanoseconds */ void osdMonotonicInit(void) { LARGE_INTEGER freq, val; - if(!QueryPerformanceFrequency(&freq) || - !QueryPerformanceCounter(&val)) + if(QueryPerformanceFrequency(&freq) && + QueryPerformanceCounter(&val)) { - double period = 1.0/freq.QuadPart; - osdMonotonicResolution = period*1e9; + perfCounterScale = 1e9 / freq.QuadPart; + osdMonotonicResolution = 1 + (int)perfCounterScale; osdUsePrefCounter = 1; } else { osdMonotonicResolution = 1e6; /* 1 ms TODO place holder */ @@ -44,9 +45,14 @@ epicsUInt64 epicsMonotonicGet(void) errMessage(errlogMinor, "Warning: failed to fetch performance counter\n"); return 0; } else - return val.QuadPart; + return val.QuadPart * perfCounterScale; } else { - epicsUInt64 ret = GetTickCount(); + epicsUInt64 ret = +#if _WIN32_WINNT >= 0x0600 /* Windows Vista / Server 2008 and later */ + GetTickCount64(); +#else + GetTickCount(); /* this wraps every 49.7 days */ +#endif /* _WIN32_WINNT >= 0x0600 */ ret *= 1000000; return ret; } From f8a6735691637aac688821dcdcc4ec6f13a30960 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sat, 19 Sep 2020 00:53:05 +0100 Subject: [PATCH 02/22] Print warning if using GetTickCount() --- modules/libcom/src/osi/os/WIN32/osdMonotonic.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index e9fce3834..8b72d24fb 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -29,6 +29,9 @@ void osdMonotonicInit(void) osdUsePrefCounter = 1; } else { osdMonotonicResolution = 1e6; /* 1 ms TODO place holder */ +#if _WIN32_WINNT < 0x0600 /* Older than Windows Vista / Server 2008 */ + errMessage(errlogMinor, "Warning: using GetTickCount() so monotonic time will wrap every 49.7 days\n"); +#endif } } From fe35e6e7033d56d28ce2a364c8c967e9b8b1d7ae Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Fri, 25 Sep 2020 20:59:20 +0100 Subject: [PATCH 03/22] Remove use of GetTickCount() - only use performance counter --- .../libcom/src/osi/os/WIN32/osdMonotonic.c | 32 ++++++------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index 8b72d24fb..03caf55bd 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -13,25 +13,23 @@ #include "epicsTime.h" #include "generalTimeSup.h" -static unsigned char osdUsePrefCounter; static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */ static double perfCounterScale; /* convert performance counter tics to nanoseconds */ void osdMonotonicInit(void) { LARGE_INTEGER freq, val; - + /* QueryPerformanceCounter() is available on Windows 2000 and later, and guaranteed + to always succeed on Windows XP or later. On Windows 2000 it may + return 0 for freq.QuadPart if unavailable */ if(QueryPerformanceFrequency(&freq) && - QueryPerformanceCounter(&val)) + QueryPerformanceCounter(&val) && + freq.QuadPart != 0) { perfCounterScale = 1e9 / freq.QuadPart; osdMonotonicResolution = 1 + (int)perfCounterScale; - osdUsePrefCounter = 1; } else { - osdMonotonicResolution = 1e6; /* 1 ms TODO place holder */ -#if _WIN32_WINNT < 0x0600 /* Older than Windows Vista / Server 2008 */ - errMessage(errlogMinor, "Warning: using GetTickCount() so monotonic time will wrap every 49.7 days\n"); -#endif + errMessage(errlogMajor, "Windows Performance Counter is not available\n"); } } @@ -43,20 +41,10 @@ epicsUInt64 epicsMonotonicResolution(void) epicsUInt64 epicsMonotonicGet(void) { LARGE_INTEGER val; - if(osdUsePrefCounter) { - if(!QueryPerformanceCounter(&val)) { - errMessage(errlogMinor, "Warning: failed to fetch performance counter\n"); - return 0; - } else - return val.QuadPart * perfCounterScale; + if(!QueryPerformanceCounter(&val)) { + errMessage(errlogMinor, "Warning: failed to fetch performance counter\n"); + return 0; } else { - epicsUInt64 ret = -#if _WIN32_WINNT >= 0x0600 /* Windows Vista / Server 2008 and later */ - GetTickCount64(); -#else - GetTickCount(); /* this wraps every 49.7 days */ -#endif /* _WIN32_WINNT >= 0x0600 */ - ret *= 1000000; - return ret; + return val.QuadPart * perfCounterScale; /* return value in nanoseconds */ } } From bbdd9392fe542b3e4470b7f4088d9b8ff3656549 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sun, 27 Sep 2020 00:42:20 +0100 Subject: [PATCH 04/22] Call cantProceed() if performance counter is unavailable --- modules/libcom/src/osi/os/WIN32/osdMonotonic.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index 03caf55bd..208c1aaa0 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -10,6 +10,7 @@ #define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE #include "dbDefs.h" #include "errlog.h" +#include "cantProceed.h" #include "epicsTime.h" #include "generalTimeSup.h" @@ -29,7 +30,7 @@ void osdMonotonicInit(void) perfCounterScale = 1e9 / freq.QuadPart; osdMonotonicResolution = 1 + (int)perfCounterScale; } else { - errMessage(errlogMajor, "Windows Performance Counter is not available\n"); + cantProceed("osdMonotonicInit: Windows Performance Counter is not available\n"); } } @@ -42,9 +43,9 @@ epicsUInt64 epicsMonotonicGet(void) { LARGE_INTEGER val; if(!QueryPerformanceCounter(&val)) { - errMessage(errlogMinor, "Warning: failed to fetch performance counter\n"); + cantProceed("epicsMonotonicGet: Failed to read Windows Performance Counter\n"); return 0; } else { - return val.QuadPart * perfCounterScale; /* return value in nanoseconds */ + return (epicsUInt64)(val.QuadPart * perfCounterScale + 0.5); /* return value in nanoseconds */ } } From 8a90688880bae68bc8b6bf537e09a4fc6306421c Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sun, 4 Oct 2020 00:20:11 +0100 Subject: [PATCH 05/22] Make returned value relative to IOC boot time to improve accuracy --- modules/libcom/src/osi/os/WIN32/osdMonotonic.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index 208c1aaa0..e9db3b1da 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -14,8 +14,10 @@ #include "epicsTime.h" #include "generalTimeSup.h" -static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */ -static double perfCounterScale; /* convert performance counter tics to nanoseconds */ +static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */ +static epicsUInt64 perfCounterFrequency; /* performance counter tics per second */ +static epicsUInt64 perfCounterOffset; /* performance counter value at initialisation */ +static const epicsUInt64 sec2nsec = 1000000000; /* number of nanoseconds in a second */ void osdMonotonicInit(void) { @@ -27,8 +29,9 @@ void osdMonotonicInit(void) QueryPerformanceCounter(&val) && freq.QuadPart != 0) { - perfCounterScale = 1e9 / freq.QuadPart; - osdMonotonicResolution = 1 + (int)perfCounterScale; + perfCounterFrequency = freq.QuadPart; + perfCounterOffset = val.QuadPart; + osdMonotonicResolution = sec2nsec / perfCounterFrequency + (sec2nsec % perfCounterFrequency != 0 ? 1 : 0); } else { cantProceed("osdMonotonicInit: Windows Performance Counter is not available\n"); } @@ -45,7 +48,7 @@ epicsUInt64 epicsMonotonicGet(void) if(!QueryPerformanceCounter(&val)) { cantProceed("epicsMonotonicGet: Failed to read Windows Performance Counter\n"); return 0; - } else { - return (epicsUInt64)(val.QuadPart * perfCounterScale + 0.5); /* return value in nanoseconds */ + } else { /* return value in nanoseconds */ + return (epicsUInt64)((double)(val.QuadPart - perfCounterOffset) * sec2nsec / perfCounterFrequency + 0.5); } } From cdc627a15cd0bda32c136d3b00a0549a5c93569b Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sun, 4 Oct 2020 01:20:44 +0100 Subject: [PATCH 06/22] Use native Windows type for perfCounterOffset --- modules/libcom/src/osi/os/WIN32/osdMonotonic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index e9db3b1da..a10e05eba 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -16,7 +16,7 @@ static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */ static epicsUInt64 perfCounterFrequency; /* performance counter tics per second */ -static epicsUInt64 perfCounterOffset; /* performance counter value at initialisation */ +static LONGLONG perfCounterOffset; /* performance counter value at initialisation */ static const epicsUInt64 sec2nsec = 1000000000; /* number of nanoseconds in a second */ void osdMonotonicInit(void) From 34a0b387b0273094cd241b839dc931f97c338b6c Mon Sep 17 00:00:00 2001 From: Jeong Han Lee Date: Tue, 2 Feb 2021 17:26:12 -0800 Subject: [PATCH 07/22] add dawrin-aarch64 (arm64) Host Arch --- configure/os/CONFIG.Common.darwin-aarch64 | 14 ++++++++++++++ configure/os/CONFIG.darwin-aarch64.Common | 8 ++++++++ configure/os/CONFIG_SITE.Common.darwin-aarch64 | 9 +++++++++ src/tools/EpicsHostArch.pl | 5 +++-- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 configure/os/CONFIG.Common.darwin-aarch64 create mode 100644 configure/os/CONFIG.darwin-aarch64.Common create mode 100644 configure/os/CONFIG_SITE.Common.darwin-aarch64 diff --git a/configure/os/CONFIG.Common.darwin-aarch64 b/configure/os/CONFIG.Common.darwin-aarch64 new file mode 100644 index 000000000..639d79b68 --- /dev/null +++ b/configure/os/CONFIG.Common.darwin-aarch64 @@ -0,0 +1,14 @@ +# CONFIG.Common.darwin-aarch64 +# +# This file is maintained by the build community. +# +# Definitions for darwin-ppc target builds +# Sites may override these definitions in CONFIG_SITE.Common.darwin-ppc +#------------------------------------------------------- + +# +# To build universal binaries, configure ARCH_CLASS +# in the file CONFIG_SITE.Common.darwin-aarch64 + +# Include definitions common to all Darwin targets +include $(CONFIG)/os/CONFIG.darwinCommon.darwinCommon diff --git a/configure/os/CONFIG.darwin-aarch64.Common b/configure/os/CONFIG.darwin-aarch64.Common new file mode 100644 index 000000000..0be8d68fe --- /dev/null +++ b/configure/os/CONFIG.darwin-aarch64.Common @@ -0,0 +1,8 @@ +# CONFIG.darwin-aarch64.Common +# +# Definitions for darwin-aarch64 host builds +# Sites may override these definitions in CONFIG_SITE.darwin-aarch64.Common +#------------------------------------------------------- + +#Include definitions common to unix hosts +include $(CONFIG)/os/CONFIG.UnixCommon.Common diff --git a/configure/os/CONFIG_SITE.Common.darwin-aarch64 b/configure/os/CONFIG_SITE.Common.darwin-aarch64 new file mode 100644 index 000000000..8d79eb16e --- /dev/null +++ b/configure/os/CONFIG_SITE.Common.darwin-aarch64 @@ -0,0 +1,9 @@ +# CONFIG_SITE.Common.darwin-aarch64 +# +# Site override definitions for darwin-aarch64 target builds +#------------------------------------------------------- + +# +# arm64 devices: Apple Silicon M1 + +ARCH_CLASS = arm64 diff --git a/src/tools/EpicsHostArch.pl b/src/tools/EpicsHostArch.pl index d1508bf0e..52c427253 100644 --- a/src/tools/EpicsHostArch.pl +++ b/src/tools/EpicsHostArch.pl @@ -46,8 +46,9 @@ sub HostArch { my ($kernel, $hostname, $release, $version, $cpu) = uname; if (m/^darwin/) { for ($cpu) { - return 'darwin-x86' if m/^(i386|x86_64)/; - return 'darwin-ppc' if m/Power Macintosh/; + return 'darwin-x86' if m/^(i386|x86_64)/; + return 'darwin-ppc' if m/Power Macintosh/; + return 'darwin-aarch64' if m/arm64/; } die "$0: macOS CPU type '$cpu' not recognized\n"; } From d3e96c4c2b02606d952739db17e7e3d0811efc80 Mon Sep 17 00:00:00 2001 From: Jeong Han Lee Date: Fri, 5 Feb 2021 17:02:54 -0800 Subject: [PATCH 08/22] fixed a typo in CONFIG.Common.darwin-aarch64 --- configure/os/CONFIG.Common.darwin-aarch64 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure/os/CONFIG.Common.darwin-aarch64 b/configure/os/CONFIG.Common.darwin-aarch64 index 639d79b68..eaba1efb2 100644 --- a/configure/os/CONFIG.Common.darwin-aarch64 +++ b/configure/os/CONFIG.Common.darwin-aarch64 @@ -2,8 +2,8 @@ # # This file is maintained by the build community. # -# Definitions for darwin-ppc target builds -# Sites may override these definitions in CONFIG_SITE.Common.darwin-ppc +# Definitions for darwin-aarch64 target builds +# Sites may override these definitions in CONFIG_SITE.Common.darwin-aarch64 #------------------------------------------------------- # From 410921b5efafcd9014a3da7dbfd5f47d220d5288 Mon Sep 17 00:00:00 2001 From: Michael Ritzert Date: Thu, 7 Jan 2021 12:11:12 +0100 Subject: [PATCH 09/22] Use getifaddrs instead of SIOCGIFCONF. The old code is preserved in osdNetIfConf.c, which is used by the default platform directory. Platforms that support getifaddrs use the new code from osdNetIfAddrs.c. --- modules/libcom/src/osi/os/Darwin/osdNetIntf.c | 1 + modules/libcom/src/osi/os/Linux/osdNetIntf.c | 1 + .../libcom/src/osi/os/cygwin32/osdNetIntf.c | 1 + .../libcom/src/osi/os/default/osdNetIntf.c | 352 +----------------- .../libcom/src/osi/os/freebsd/osdNetIntf.c | 1 + modules/libcom/src/osi/os/iOS/osdNetIntf.c | 1 + modules/libcom/src/osi/osdNetIfAddrs.c | 222 +++++++++++ modules/libcom/src/osi/osdNetIfConf.c | 352 ++++++++++++++++++ 8 files changed, 580 insertions(+), 351 deletions(-) create mode 100644 modules/libcom/src/osi/os/Darwin/osdNetIntf.c create mode 100644 modules/libcom/src/osi/os/Linux/osdNetIntf.c create mode 100644 modules/libcom/src/osi/os/cygwin32/osdNetIntf.c create mode 100644 modules/libcom/src/osi/os/freebsd/osdNetIntf.c create mode 100644 modules/libcom/src/osi/os/iOS/osdNetIntf.c create mode 100644 modules/libcom/src/osi/osdNetIfAddrs.c create mode 100644 modules/libcom/src/osi/osdNetIfConf.c diff --git a/modules/libcom/src/osi/os/Darwin/osdNetIntf.c b/modules/libcom/src/osi/os/Darwin/osdNetIntf.c new file mode 100644 index 000000000..aa7639e22 --- /dev/null +++ b/modules/libcom/src/osi/os/Darwin/osdNetIntf.c @@ -0,0 +1 @@ +#include "../osi/osdNetIfAddrs.c" diff --git a/modules/libcom/src/osi/os/Linux/osdNetIntf.c b/modules/libcom/src/osi/os/Linux/osdNetIntf.c new file mode 100644 index 000000000..aa7639e22 --- /dev/null +++ b/modules/libcom/src/osi/os/Linux/osdNetIntf.c @@ -0,0 +1 @@ +#include "../osi/osdNetIfAddrs.c" diff --git a/modules/libcom/src/osi/os/cygwin32/osdNetIntf.c b/modules/libcom/src/osi/os/cygwin32/osdNetIntf.c new file mode 100644 index 000000000..aa7639e22 --- /dev/null +++ b/modules/libcom/src/osi/os/cygwin32/osdNetIntf.c @@ -0,0 +1 @@ +#include "../osi/osdNetIfAddrs.c" diff --git a/modules/libcom/src/osi/os/default/osdNetIntf.c b/modules/libcom/src/osi/os/default/osdNetIntf.c index 33bfd355c..04ca4f756 100644 --- a/modules/libcom/src/osi/os/default/osdNetIntf.c +++ b/modules/libcom/src/osi/os/default/osdNetIntf.c @@ -1,351 +1 @@ -/*************************************************************************\ -* 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. -* SPDX-License-Identifier: EPICS -* EPICS Base is distributed subject to a Software License Agreement found -* in file LICENSE that is included with this distribution. -\*************************************************************************/ - -/* - * Author: Jeff Hill - * Date: 04-05-94 - */ - -#include -#include -#include -#include - -#include "osiSock.h" -#include "epicsAssert.h" -#include "errlog.h" -#include "epicsThread.h" - -#ifdef DEBUG -# define ifDepenDebugPrintf(argsInParen) printf argsInParen -#else -# define ifDepenDebugPrintf(argsInParen) -#endif - -static osiSockAddr osiLocalAddrResult; -static epicsThreadOnceId osiLocalAddrId = EPICS_THREAD_ONCE_INIT; - -/* - * Determine the size of an ifreq structure - * Made difficult by the fact that addresses larger than the structure - * size may be returned from the kernel. - */ -static size_t ifreqSize ( struct ifreq *pifreq ) -{ - size_t size; - - size = ifreq_size ( pifreq ); - if ( size < sizeof ( *pifreq ) ) { - size = sizeof ( *pifreq ); - } - return size; -} - -/* - * Move to the next ifreq structure - */ -static struct ifreq * ifreqNext ( struct ifreq *pifreq ) -{ - struct ifreq *ifr; - - ifr = ( struct ifreq * )( ifreqSize (pifreq) + ( char * ) pifreq ); - ifDepenDebugPrintf( ("ifreqNext() pifreq %p, size 0x%x, ifr 0x%p\n", pifreq, (unsigned)ifreqSize (pifreq), ifr) ); - return ifr; -} - - -/* - * osiSockDiscoverBroadcastAddresses () - */ -LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses - (ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr) -{ - static const unsigned nelem = 100; - int status; - struct ifconf ifconf; - struct ifreq *pIfreqList; - struct ifreq *pIfreqListEnd; - struct ifreq *pifreq; - struct ifreq *pnextifreq; - osiSockAddrNode *pNewNode; - - if ( pMatchAddr->sa.sa_family == AF_INET ) { - if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) { - pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); - if ( pNewNode == NULL ) { - errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); - return; - } - pNewNode->addr.ia.sin_family = AF_INET; - pNewNode->addr.ia.sin_port = htons ( 0 ); - pNewNode->addr.ia.sin_addr.s_addr = htonl (INADDR_LOOPBACK); - ellAdd ( pList, &pNewNode->node ); - return; - } - } - - /* - * use pool so that we avoid using too much stack space - * - * nelem is set to the maximum interfaces - * on one machine here - */ - pIfreqList = (struct ifreq *) calloc ( nelem, sizeof(*pifreq) ); - if (!pIfreqList) { - errlogPrintf ("osiSockDiscoverBroadcastAddresses(): no memory to complete request\n"); - return; - } - - ifconf.ifc_len = nelem * sizeof(*pifreq); - ifconf.ifc_req = pIfreqList; - status = socket_ioctl (socket, SIOCGIFCONF, &ifconf); - if (status < 0 || ifconf.ifc_len == 0) { - errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration (%d)\n", status); - free (pIfreqList); - return; - } - - pIfreqListEnd = (struct ifreq *) (ifconf.ifc_len + (char *) pIfreqList); - pIfreqListEnd--; - - for ( pifreq = pIfreqList; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) { - uint32_t current_ifreqsize; - - /* - * find the next ifreq - */ - pnextifreq = ifreqNext (pifreq); - - /* determine ifreq size */ - current_ifreqsize = ifreqSize ( pifreq ); - /* copy current ifreq to aligned bufferspace (to start of pIfreqList buffer) */ - memmove(pIfreqList, pifreq, current_ifreqsize); - - ifDepenDebugPrintf (("osiSockDiscoverBroadcastAddresses(): found IFACE: %s len: 0x%x current_ifreqsize: 0x%x \n", - pIfreqList->ifr_name, - (unsigned)ifreq_size(pifreq), - (unsigned)current_ifreqsize)); - - /* - * If its not an internet interface then dont use it - */ - if ( pIfreqList->ifr_addr.sa_family != AF_INET ) { - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): interface \"%s\" was not AF_INET\n", pIfreqList->ifr_name) ); - continue; - } - - /* - * if it isnt a wildcarded interface then look for - * an exact match - */ - if ( pMatchAddr->sa.sa_family != AF_UNSPEC ) { - if ( pMatchAddr->sa.sa_family != AF_INET ) { - continue; - } - if ( pMatchAddr->ia.sin_addr.s_addr != htonl (INADDR_ANY) ) { - struct sockaddr_in *pInetAddr = (struct sockaddr_in *) &pIfreqList->ifr_addr; - if ( pInetAddr->sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) { - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" didnt match\n", pIfreqList->ifr_name) ); - continue; - } - } - } - - status = socket_ioctl ( socket, SIOCGIFFLAGS, pIfreqList ); - if ( status ) { - errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf flags fetch for \"%s\" failed\n", pIfreqList->ifr_name); - continue; - } - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" flags: %x\n", pIfreqList->ifr_name, pIfreqList->ifr_flags) ); - - /* - * dont bother with interfaces that have been disabled - */ - if ( ! ( pIfreqList->ifr_flags & IFF_UP ) ) { - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" was down\n", pIfreqList->ifr_name) ); - continue; - } - - /* - * dont use the loop back interface - */ - if ( pIfreqList->ifr_flags & IFF_LOOPBACK ) { - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): ignoring loopback interface: \"%s\"\n", pIfreqList->ifr_name) ); - continue; - } - - pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); - if ( pNewNode == NULL ) { - errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); - free ( pIfreqList ); - return; - } - - /* - * If this is an interface that supports - * broadcast fetch the broadcast address. - * - * Otherwise if this is a point to point - * interface then use the destination address. - * - * Otherwise CA will not query through the - * interface. - */ - if ( pIfreqList->ifr_flags & IFF_BROADCAST ) { - osiSockAddr baddr; - status = socket_ioctl (socket, SIOCGIFBRDADDR, pIfreqList); - if ( status ) { - errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": bcast addr fetch fail\n", pIfreqList->ifr_name); - free ( pNewNode ); - continue; - } - baddr.sa = pIfreqList->ifr_broadaddr; - if (baddr.ia.sin_family==AF_INET && baddr.ia.sin_addr.s_addr != INADDR_ANY) { - pNewNode->addr.sa = pIfreqList->ifr_broadaddr; - ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); - } else { - ifDepenDebugPrintf ( ( "Ignoring broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); - free ( pNewNode ); - continue; - } - } -#if defined (IFF_POINTOPOINT) - else if ( pIfreqList->ifr_flags & IFF_POINTOPOINT ) { - status = socket_ioctl ( socket, SIOCGIFDSTADDR, pIfreqList); - if ( status ) { - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": pt to pt addr fetch fail\n", pIfreqList->ifr_name) ); - free ( pNewNode ); - continue; - } - pNewNode->addr.sa = pIfreqList->ifr_dstaddr; - } -#endif - else { - ifDepenDebugPrintf ( ( "osiSockDiscoverBroadcastAddresses(): net intf \"%s\": not point to point or bcast?\n", pIfreqList->ifr_name ) ); - free ( pNewNode ); - continue; - } - - ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" found\n", pIfreqList->ifr_name) ); - - /* - * LOCK applied externally - */ - ellAdd ( pList, &pNewNode->node ); - } - - free ( pIfreqList ); -} - -/* - * osiLocalAddr () - */ -static void osiLocalAddrOnce (void *raw) -{ - SOCKET *psocket = raw; - const unsigned nelem = 100; - osiSockAddr addr; - int status; - struct ifconf ifconf; - struct ifreq *pIfreqList; - struct ifreq *pifreq; - struct ifreq *pIfreqListEnd; - struct ifreq *pnextifreq; - - memset ( (void *) &addr, '\0', sizeof ( addr ) ); - addr.sa.sa_family = AF_UNSPEC; - - pIfreqList = (struct ifreq *) calloc ( nelem, sizeof(*pIfreqList) ); - if ( ! pIfreqList ) { - errlogPrintf ( "osiLocalAddr(): no memory to complete request\n" ); - goto fail; - } - - ifconf.ifc_len = nelem * sizeof ( *pIfreqList ); - ifconf.ifc_req = pIfreqList; - status = socket_ioctl ( *psocket, SIOCGIFCONF, &ifconf ); - if ( status < 0 || ifconf.ifc_len == 0 ) { - char sockErrBuf[64]; - epicsSocketConvertErrnoToString ( - sockErrBuf, sizeof ( sockErrBuf ) ); - errlogPrintf ( - "osiLocalAddr(): SIOCGIFCONF ioctl failed because \"%s\"\n", - sockErrBuf ); - goto fail; - } - - pIfreqListEnd = (struct ifreq *) ( ifconf.ifc_len + (char *) ifconf.ifc_req ); - pIfreqListEnd--; - - for ( pifreq = ifconf.ifc_req; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) { - osiSockAddr addrCpy; - uint32_t current_ifreqsize; - - /* - * find the next if req - */ - pnextifreq = ifreqNext ( pifreq ); - - /* determine ifreq size */ - current_ifreqsize = ifreqSize ( pifreq ); - /* copy current ifreq to aligned bufferspace (to start of pIfreqList buffer) */ - memmove(pIfreqList, pifreq, current_ifreqsize); - - if ( pIfreqList->ifr_addr.sa_family != AF_INET ) { - ifDepenDebugPrintf ( ("osiLocalAddr(): interface %s was not AF_INET\n", pIfreqList->ifr_name) ); - continue; - } - - addrCpy.sa = pIfreqList->ifr_addr; - - status = socket_ioctl ( *psocket, SIOCGIFFLAGS, pIfreqList ); - if ( status < 0 ) { - errlogPrintf ( "osiLocalAddr(): net intf flags fetch for %s failed\n", pIfreqList->ifr_name ); - continue; - } - - if ( ! ( pIfreqList->ifr_flags & IFF_UP ) ) { - ifDepenDebugPrintf ( ("osiLocalAddr(): net intf %s was down\n", pIfreqList->ifr_name) ); - continue; - } - - /* - * dont use the loop back interface - */ - if ( pIfreqList->ifr_flags & IFF_LOOPBACK ) { - ifDepenDebugPrintf ( ("osiLocalAddr(): ignoring loopback interface: %s\n", pIfreqList->ifr_name) ); - continue; - } - - ifDepenDebugPrintf ( ("osiLocalAddr(): net intf %s found\n", pIfreqList->ifr_name) ); - - osiLocalAddrResult = addrCpy; - free ( pIfreqList ); - return; - } - - errlogPrintf ( - "osiLocalAddr(): only loopback found\n"); -fail: - /* fallback to loopback */ - memset ( (void *) &addr, '\0', sizeof ( addr ) ); - addr.ia.sin_family = AF_INET; - addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - osiLocalAddrResult = addr; - - free ( pIfreqList ); -} - - -LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr (SOCKET socket) -{ - epicsThreadOnce(&osiLocalAddrId, osiLocalAddrOnce, &socket); - return osiLocalAddrResult; -} +#include "../osi/osdNetIfConf.c" diff --git a/modules/libcom/src/osi/os/freebsd/osdNetIntf.c b/modules/libcom/src/osi/os/freebsd/osdNetIntf.c new file mode 100644 index 000000000..aa7639e22 --- /dev/null +++ b/modules/libcom/src/osi/os/freebsd/osdNetIntf.c @@ -0,0 +1 @@ +#include "../osi/osdNetIfAddrs.c" diff --git a/modules/libcom/src/osi/os/iOS/osdNetIntf.c b/modules/libcom/src/osi/os/iOS/osdNetIntf.c new file mode 100644 index 000000000..aa7639e22 --- /dev/null +++ b/modules/libcom/src/osi/os/iOS/osdNetIntf.c @@ -0,0 +1 @@ +#include "../osi/osdNetIfAddrs.c" diff --git a/modules/libcom/src/osi/osdNetIfAddrs.c b/modules/libcom/src/osi/osdNetIfAddrs.c new file mode 100644 index 000000000..6e780cbbb --- /dev/null +++ b/modules/libcom/src/osi/osdNetIfAddrs.c @@ -0,0 +1,222 @@ +/*************************************************************************\ +* 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. +* SPDX-License-Identifier: EPICS +* EPICS Base is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* This file included from various os/.../osdNetIntf.c */ + +#include +#include +#include +#include +#include +#include + +#include "osiSock.h" +#include "epicsAssert.h" +#include "errlog.h" +#include "epicsThread.h" + +#ifdef DEBUG +# define ifDepenDebugPrintf(argsInParen) printf argsInParen +#else +# define ifDepenDebugPrintf(argsInParen) +#endif + +static osiSockAddr osiLocalAddrResult; +static epicsThreadOnceId osiLocalAddrId = EPICS_THREAD_ONCE_INIT; + +/* + * osiSockDiscoverBroadcastAddresses () + */ +LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses + (ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr) +{ + osiSockAddrNode *pNewNode; + + if ( pMatchAddr->sa.sa_family == AF_INET ) { + if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) { + pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); + if ( pNewNode == NULL ) { + errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); + return; + } + pNewNode->addr.ia.sin_family = AF_INET; + pNewNode->addr.ia.sin_port = htons ( 0 ); + pNewNode->addr.ia.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + ellAdd ( pList, &pNewNode->node ); + return; + } + } + + struct ifaddrs *ifaddr; + int result = getifaddrs (&ifaddr); + if ( result != 0 ) { + errlogPrintf("osiSockDiscoverBroadcastAddresses(): getifaddrs failed.\n"); + return; + } + + for ( struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next ) { + if ( ifa->ifa_addr == NULL ) { + continue; + } + + ifDepenDebugPrintf (("osiSockDiscoverBroadcastAddresses(): found IFACE: %s\n", + ifa->ifa_name)); + + /* + * If its not an internet interface then dont use it + */ + if ( ifa->ifa_addr->sa_family != AF_INET ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): interface \"%s\" was not AF_INET\n", ifa->ifa_name) ); + continue; + } + + /* + * if it isnt a wildcarded interface then look for + * an exact match + */ + if ( pMatchAddr->sa.sa_family != AF_UNSPEC ) { + if ( pMatchAddr->sa.sa_family != AF_INET ) { + continue; + } + if ( pMatchAddr->ia.sin_addr.s_addr != htonl (INADDR_ANY) ) { + struct sockaddr_in *pInetAddr = (struct sockaddr_in *) ifa->ifa_addr; + if ( pInetAddr->sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" didnt match\n", ifa->ifa_name) ); + continue; + } + } + } + + /* + * dont bother with interfaces that have been disabled + */ + if ( ! ( ifa->ifa_flags & IFF_UP ) ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" was down\n", ifa->ifa_name) ); + continue; + } + + /* + * dont use the loop back interface + */ + if ( ifa->ifa_flags & IFF_LOOPBACK ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): ignoring loopback interface: \"%s\"\n", ifa->ifa_name) ); + continue; + } + + pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); + if ( pNewNode == NULL ) { + errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); + freeifaddrs ( ifaddr ); + return; + } + + /* + * If this is an interface that supports + * broadcast use the broadcast address. + * + * Otherwise if this is a point to point + * interface then use the destination address. + * + * Otherwise CA will not query through the + * interface. + */ + if ( ifa->ifa_flags & IFF_BROADCAST ) { + osiSockAddr baddr; + baddr.sa = *ifa->ifa_broadaddr; + if (baddr.ia.sin_family==AF_INET && baddr.ia.sin_addr.s_addr != INADDR_ANY) { + pNewNode->addr.sa = *ifa->ifa_broadaddr; + ifDepenDebugPrintf ( ( "found broadcast addr = %08x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); + } else { + ifDepenDebugPrintf ( ( "Ignoring broadcast addr = %08x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); + free ( pNewNode ); + continue; + } + } +#if defined (IFF_POINTOPOINT) + else if ( ifa->ifa_flags & IFF_POINTOPOINT ) { + pNewNode->addr.sa = *ifa->ifa_dstaddr; + } +#endif + else { + ifDepenDebugPrintf ( ( "osiSockDiscoverBroadcastAddresses(): net intf \"%s\": not point to point or bcast?\n", ifa->ifa_name ) ); + free ( pNewNode ); + continue; + } + + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" found\n", ifa->ifa_name) ); + + /* + * LOCK applied externally + */ + ellAdd ( pList, &pNewNode->node ); + } + + freeifaddrs ( ifaddr ); +} + +/* + * osiLocalAddrOnce () + */ +static void osiLocalAddrOnce (void *raw) +{ + struct ifaddrs *ifaddr; + int result = getifaddrs (&ifaddr); + if ( result != 0 ) { + errlogPrintf("osiLocalAddrOnce(): getifaddrs failed.\n"); + return; + } + + for ( struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next ) { + if ( ifa->ifa_addr == NULL ) { + continue; + } + + if ( ! ( ifa->ifa_flags & IFF_UP ) ) { + ifDepenDebugPrintf ( ("osiLocalAddrOnce(): net intf %s was down\n", ifa->ifa_name) ); + continue; + } + + if ( ifa->ifa_addr->sa_family != AF_INET ) { + ifDepenDebugPrintf ( ("osiLocalAddrOnce(): interface %s was not AF_INET\n", ifa->ifa_name) ); + continue; + } + + /* + * dont use the loop back interface + */ + if ( ifa->ifa_flags & IFF_LOOPBACK ) { + ifDepenDebugPrintf ( ("osiLocalAddrOnce(): ignoring loopback interface: %s\n", ifa->ifa_name) ); + continue; + } + + ifDepenDebugPrintf ( ("osiLocalAddr(): net intf %s found\n", ifa->ifa_name) ); + + osiLocalAddrResult.sa = *ifa->ifa_addr; + freeifaddrs ( ifaddr ); + return; + } + + errlogPrintf ( + "osiLocalAddr(): only loopback found\n"); + /* fallback to loopback */ + osiSockAddr addr; + memset ( (void *) &addr, '\0', sizeof ( addr ) ); + addr.ia.sin_family = AF_INET; + addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + osiLocalAddrResult = addr; + + freeifaddrs ( ifaddr ); +} + + +LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr (SOCKET socket) +{ + epicsThreadOnce(&osiLocalAddrId, osiLocalAddrOnce, &socket); + return osiLocalAddrResult; +} diff --git a/modules/libcom/src/osi/osdNetIfConf.c b/modules/libcom/src/osi/osdNetIfConf.c new file mode 100644 index 000000000..47339020f --- /dev/null +++ b/modules/libcom/src/osi/osdNetIfConf.c @@ -0,0 +1,352 @@ +/*************************************************************************\ +* 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. +* SPDX-License-Identifier: EPICS +* EPICS Base is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ +/* This file included from various os/.../osdNetIntf.c */ + +/* + * Author: Jeff Hill + * Date: 04-05-94 + */ + +#include +#include +#include +#include + +#include "osiSock.h" +#include "epicsAssert.h" +#include "errlog.h" +#include "epicsThread.h" + +#ifdef DEBUG +# define ifDepenDebugPrintf(argsInParen) printf argsInParen +#else +# define ifDepenDebugPrintf(argsInParen) +#endif + +static osiSockAddr osiLocalAddrResult; +static epicsThreadOnceId osiLocalAddrId = EPICS_THREAD_ONCE_INIT; + +/* + * Determine the size of an ifreq structure + * Made difficult by the fact that addresses larger than the structure + * size may be returned from the kernel. + */ +static size_t ifreqSize ( struct ifreq *pifreq ) +{ + size_t size; + + size = ifreq_size ( pifreq ); + if ( size < sizeof ( *pifreq ) ) { + size = sizeof ( *pifreq ); + } + return size; +} + +/* + * Move to the next ifreq structure + */ +static struct ifreq * ifreqNext ( struct ifreq *pifreq ) +{ + struct ifreq *ifr; + + ifr = ( struct ifreq * )( ifreqSize (pifreq) + ( char * ) pifreq ); + ifDepenDebugPrintf( ("ifreqNext() pifreq %p, size 0x%x, ifr 0x%p\n", pifreq, (unsigned)ifreqSize (pifreq), ifr) ); + return ifr; +} + + +/* + * osiSockDiscoverBroadcastAddresses () + */ +LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses + (ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr) +{ + static const unsigned nelem = 100; + int status; + struct ifconf ifconf; + struct ifreq *pIfreqList; + struct ifreq *pIfreqListEnd; + struct ifreq *pifreq; + struct ifreq *pnextifreq; + osiSockAddrNode *pNewNode; + + if ( pMatchAddr->sa.sa_family == AF_INET ) { + if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) { + pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); + if ( pNewNode == NULL ) { + errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); + return; + } + pNewNode->addr.ia.sin_family = AF_INET; + pNewNode->addr.ia.sin_port = htons ( 0 ); + pNewNode->addr.ia.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + ellAdd ( pList, &pNewNode->node ); + return; + } + } + + /* + * use pool so that we avoid using too much stack space + * + * nelem is set to the maximum interfaces + * on one machine here + */ + pIfreqList = (struct ifreq *) calloc ( nelem, sizeof(*pifreq) ); + if (!pIfreqList) { + errlogPrintf ("osiSockDiscoverBroadcastAddresses(): no memory to complete request\n"); + return; + } + + ifconf.ifc_len = nelem * sizeof(*pifreq); + ifconf.ifc_req = pIfreqList; + status = socket_ioctl (socket, SIOCGIFCONF, &ifconf); + if (status < 0 || ifconf.ifc_len == 0) { + errlogPrintf ("osiSockDiscoverBroadcastAddresses(): unable to fetch network interface configuration (%d)\n", status); + free (pIfreqList); + return; + } + + pIfreqListEnd = (struct ifreq *) (ifconf.ifc_len + (char *) pIfreqList); + pIfreqListEnd--; + + for ( pifreq = pIfreqList; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) { + uint32_t current_ifreqsize; + + /* + * find the next ifreq + */ + pnextifreq = ifreqNext (pifreq); + + /* determine ifreq size */ + current_ifreqsize = ifreqSize ( pifreq ); + /* copy current ifreq to aligned bufferspace (to start of pIfreqList buffer) */ + memmove(pIfreqList, pifreq, current_ifreqsize); + + ifDepenDebugPrintf (("osiSockDiscoverBroadcastAddresses(): found IFACE: %s len: 0x%x current_ifreqsize: 0x%x \n", + pIfreqList->ifr_name, + (unsigned)ifreq_size(pifreq), + (unsigned)current_ifreqsize)); + + /* + * If its not an internet interface then dont use it + */ + if ( pIfreqList->ifr_addr.sa_family != AF_INET ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): interface \"%s\" was not AF_INET\n", pIfreqList->ifr_name) ); + continue; + } + + /* + * if it isnt a wildcarded interface then look for + * an exact match + */ + if ( pMatchAddr->sa.sa_family != AF_UNSPEC ) { + if ( pMatchAddr->sa.sa_family != AF_INET ) { + continue; + } + if ( pMatchAddr->ia.sin_addr.s_addr != htonl (INADDR_ANY) ) { + struct sockaddr_in *pInetAddr = (struct sockaddr_in *) &pIfreqList->ifr_addr; + if ( pInetAddr->sin_addr.s_addr != pMatchAddr->ia.sin_addr.s_addr ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" didnt match\n", pIfreqList->ifr_name) ); + continue; + } + } + } + + status = socket_ioctl ( socket, SIOCGIFFLAGS, pIfreqList ); + if ( status ) { + errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf flags fetch for \"%s\" failed\n", pIfreqList->ifr_name); + continue; + } + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" flags: %x\n", pIfreqList->ifr_name, pIfreqList->ifr_flags) ); + + /* + * dont bother with interfaces that have been disabled + */ + if ( ! ( pIfreqList->ifr_flags & IFF_UP ) ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" was down\n", pIfreqList->ifr_name) ); + continue; + } + + /* + * dont use the loop back interface + */ + if ( pIfreqList->ifr_flags & IFF_LOOPBACK ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): ignoring loopback interface: \"%s\"\n", pIfreqList->ifr_name) ); + continue; + } + + pNewNode = (osiSockAddrNode *) calloc (1, sizeof (*pNewNode) ); + if ( pNewNode == NULL ) { + errlogPrintf ( "osiSockDiscoverBroadcastAddresses(): no memory available for configuration\n" ); + free ( pIfreqList ); + return; + } + + /* + * If this is an interface that supports + * broadcast fetch the broadcast address. + * + * Otherwise if this is a point to point + * interface then use the destination address. + * + * Otherwise CA will not query through the + * interface. + */ + if ( pIfreqList->ifr_flags & IFF_BROADCAST ) { + osiSockAddr baddr; + status = socket_ioctl (socket, SIOCGIFBRDADDR, pIfreqList); + if ( status ) { + errlogPrintf ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": bcast addr fetch fail\n", pIfreqList->ifr_name); + free ( pNewNode ); + continue; + } + baddr.sa = pIfreqList->ifr_broadaddr; + if (baddr.ia.sin_family==AF_INET && baddr.ia.sin_addr.s_addr != INADDR_ANY) { + pNewNode->addr.sa = pIfreqList->ifr_broadaddr; + ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); + } else { + ifDepenDebugPrintf ( ( "Ignoring broadcast addr = %x\n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); + free ( pNewNode ); + continue; + } + } +#if defined (IFF_POINTOPOINT) + else if ( pIfreqList->ifr_flags & IFF_POINTOPOINT ) { + status = socket_ioctl ( socket, SIOCGIFDSTADDR, pIfreqList); + if ( status ) { + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\": pt to pt addr fetch fail\n", pIfreqList->ifr_name) ); + free ( pNewNode ); + continue; + } + pNewNode->addr.sa = pIfreqList->ifr_dstaddr; + } +#endif + else { + ifDepenDebugPrintf ( ( "osiSockDiscoverBroadcastAddresses(): net intf \"%s\": not point to point or bcast?\n", pIfreqList->ifr_name ) ); + free ( pNewNode ); + continue; + } + + ifDepenDebugPrintf ( ("osiSockDiscoverBroadcastAddresses(): net intf \"%s\" found\n", pIfreqList->ifr_name) ); + + /* + * LOCK applied externally + */ + ellAdd ( pList, &pNewNode->node ); + } + + free ( pIfreqList ); +} + +/* + * osiLocalAddr () + */ +static void osiLocalAddrOnce (void *raw) +{ + SOCKET *psocket = raw; + const unsigned nelem = 100; + osiSockAddr addr; + int status; + struct ifconf ifconf; + struct ifreq *pIfreqList; + struct ifreq *pifreq; + struct ifreq *pIfreqListEnd; + struct ifreq *pnextifreq; + + memset ( (void *) &addr, '\0', sizeof ( addr ) ); + addr.sa.sa_family = AF_UNSPEC; + + pIfreqList = (struct ifreq *) calloc ( nelem, sizeof(*pIfreqList) ); + if ( ! pIfreqList ) { + errlogPrintf ( "osiLocalAddr(): no memory to complete request\n" ); + goto fail; + } + + ifconf.ifc_len = nelem * sizeof ( *pIfreqList ); + ifconf.ifc_req = pIfreqList; + status = socket_ioctl ( *psocket, SIOCGIFCONF, &ifconf ); + if ( status < 0 || ifconf.ifc_len == 0 ) { + char sockErrBuf[64]; + epicsSocketConvertErrnoToString ( + sockErrBuf, sizeof ( sockErrBuf ) ); + errlogPrintf ( + "osiLocalAddr(): SIOCGIFCONF ioctl failed because \"%s\"\n", + sockErrBuf ); + goto fail; + } + + pIfreqListEnd = (struct ifreq *) ( ifconf.ifc_len + (char *) ifconf.ifc_req ); + pIfreqListEnd--; + + for ( pifreq = ifconf.ifc_req; pifreq <= pIfreqListEnd; pifreq = pnextifreq ) { + osiSockAddr addrCpy; + uint32_t current_ifreqsize; + + /* + * find the next if req + */ + pnextifreq = ifreqNext ( pifreq ); + + /* determine ifreq size */ + current_ifreqsize = ifreqSize ( pifreq ); + /* copy current ifreq to aligned bufferspace (to start of pIfreqList buffer) */ + memmove(pIfreqList, pifreq, current_ifreqsize); + + if ( pIfreqList->ifr_addr.sa_family != AF_INET ) { + ifDepenDebugPrintf ( ("osiLocalAddr(): interface %s was not AF_INET\n", pIfreqList->ifr_name) ); + continue; + } + + addrCpy.sa = pIfreqList->ifr_addr; + + status = socket_ioctl ( *psocket, SIOCGIFFLAGS, pIfreqList ); + if ( status < 0 ) { + errlogPrintf ( "osiLocalAddr(): net intf flags fetch for %s failed\n", pIfreqList->ifr_name ); + continue; + } + + if ( ! ( pIfreqList->ifr_flags & IFF_UP ) ) { + ifDepenDebugPrintf ( ("osiLocalAddr(): net intf %s was down\n", pIfreqList->ifr_name) ); + continue; + } + + /* + * dont use the loop back interface + */ + if ( pIfreqList->ifr_flags & IFF_LOOPBACK ) { + ifDepenDebugPrintf ( ("osiLocalAddr(): ignoring loopback interface: %s\n", pIfreqList->ifr_name) ); + continue; + } + + ifDepenDebugPrintf ( ("osiLocalAddr(): net intf %s found\n", pIfreqList->ifr_name) ); + + osiLocalAddrResult = addrCpy; + free ( pIfreqList ); + return; + } + + errlogPrintf ( + "osiLocalAddr(): only loopback found\n"); +fail: + /* fallback to loopback */ + memset ( (void *) &addr, '\0', sizeof ( addr ) ); + addr.ia.sin_family = AF_INET; + addr.ia.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + osiLocalAddrResult = addr; + + free ( pIfreqList ); +} + + +LIBCOM_API osiSockAddr epicsStdCall osiLocalAddr (SOCKET socket) +{ + epicsThreadOnce(&osiLocalAddrId, osiLocalAddrOnce, &socket); + return osiLocalAddrResult; +} From 8723d4d9cb90dfd4894ddb16a5695d8166093aaa Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 5 Feb 2021 13:30:33 -0800 Subject: [PATCH 10/22] include database S_* in error string table --- modules/database/src/ioc/db/dbAccessDefs.h | 3 +-- modules/libcom/src/error/Makefile | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h index 5715df35d..f2cf091a3 100644 --- a/modules/database/src/ioc/db/dbAccessDefs.h +++ b/modules/database/src/ioc/db/dbAccessDefs.h @@ -173,9 +173,8 @@ struct dbr_alDouble {DBRalDouble}; #define dbr_alLong_size sizeof(struct dbr_alLong) #define dbr_alDouble_size sizeof(struct dbr_alDouble) -#ifndef INCerrMdefh #include "errMdef.h" -#endif + #define S_db_notFound (M_dbAccess| 1) /*Process Variable Not Found*/ #define S_db_badDbrtype (M_dbAccess| 3) /*Illegal Database Request Type*/ #define S_db_noMod (M_dbAccess| 5) /*Attempt to modify noMod field*/ diff --git a/modules/libcom/src/error/Makefile b/modules/libcom/src/error/Makefile index c79752cc3..570974b95 100644 --- a/modules/libcom/src/error/Makefile +++ b/modules/libcom/src/error/Makefile @@ -26,5 +26,7 @@ ERR_S_FILES += $(LIBCOM)/as/asLib.h ERR_S_FILES += $(LIBCOM)/misc/epicsStdlib.h ERR_S_FILES += $(LIBCOM)/pool/epicsThreadPool.h ERR_S_FILES += $(LIBCOM)/error/errMdef.h +ERR_S_FILES += $(TOP)/modules/database/src/ioc/db/dbAccessDefs.h +ERR_S_FILES += $(TOP)/modules/database/src/ioc/dbStatic/dbStaticLib.h CLEANS += errSymTbl.c From 27918cb7a1a5c3c9335897f73d1f6ed7c99f6d6d Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 4 Feb 2021 08:49:54 -0800 Subject: [PATCH 11/22] improve error message from dbPutString() for DBF_MENU/DEVICE --- modules/database/src/ioc/dbStatic/dbLexRoutines.c | 4 ++-- modules/database/src/ioc/dbStatic/dbStaticLib.c | 3 --- modules/database/src/ioc/dbStatic/dbStaticPvt.h | 2 ++ modules/database/src/ioc/dbStatic/dbStaticRun.c | 12 +++++++++++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index ade66e347..612dd6587 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1185,8 +1185,8 @@ static void dbRecordField(char *name,char *value) char msg[128]; errSymLookup(status, msg, sizeof(msg)); - epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s\n", - dbGetRecordName(pdbentry), name, value, msg); + epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s : %s\n", + dbGetRecordName(pdbentry), name, value, pdbentry->message ? pdbentry->message : "", msg); yyerror(NULL); return; } diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index fd2980571..4ed96272b 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -81,8 +81,6 @@ maplinkType pamaplinkType[LINK_NTYPES] = { }; /*forward references for private routines*/ -static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) - EPICS_PRINTF_STYLE(2,3); static long dbAddOnePath (DBBASE *pdbbase, const char *path, unsigned length); /* internal routines*/ @@ -199,7 +197,6 @@ void dbMsgNCpy(DBENTRY *pdbentry, const char *msg, size_t len) pdbentry->message[len] = '\0'; } -static void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) { va_list args; diff --git a/modules/database/src/ioc/dbStatic/dbStaticPvt.h b/modules/database/src/ioc/dbStatic/dbStaticPvt.h index 5c68d2696..0197054ee 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticPvt.h +++ b/modules/database/src/ioc/dbStatic/dbStaticPvt.h @@ -36,6 +36,8 @@ char *dbRecordName(DBENTRY *pdbentry); char *dbGetStringNum(DBENTRY *pdbentry); long dbPutStringNum(DBENTRY *pdbentry,const char *pstring); +void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) EPICS_PRINTF_STYLE(2,3); + struct jlink; typedef struct dbLinkInfo { diff --git a/modules/database/src/ioc/dbStatic/dbStaticRun.c b/modules/database/src/ioc/dbStatic/dbStaticRun.c index ca36e1803..6d3fd5f60 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticRun.c +++ b/modules/database/src/ioc/dbStatic/dbStaticRun.c @@ -28,6 +28,7 @@ #include "dbCommonPvt.h" #include "dbStaticLib.h" #include "dbStaticPvt.h" +#include "dbAccess.h" #include "devSup.h" #include "special.h" @@ -479,8 +480,17 @@ long dbPutStringNum(DBENTRY *pdbentry, const char *pstring) epicsEnum16 value; long status = epicsParseUInt16(pstring, &value, 0, NULL); - if (status) + if (status) { + status = S_db_badChoice; + if(pflddes->field_type==DBF_MENU) { + dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; + dbMsgPrint(pdbentry, "using menu %s", pdbMenu->name); + + } else if(pflddes->field_type==DBF_DEVICE) { + dbMsgPrint(pdbentry, "no such device support for '%s' record type", pdbentry->precordType->name); + } return status; + } index = dbGetNMenuChoices(pdbentry); if (value > index && index > 0 && value < USHRT_MAX) From 745c3f552e7cbd13e07cacdd7577468cc3349a6f Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 5 Feb 2021 07:05:22 -0800 Subject: [PATCH 12/22] Com: add epicsStrSimilarity() --- modules/libcom/src/misc/epicsString.c | 70 +++++++++++++++++++++++++++ modules/libcom/src/misc/epicsString.h | 10 ++++ modules/libcom/test/epicsStringTest.c | 34 ++++++++++++- 3 files changed, 113 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/misc/epicsString.c b/modules/libcom/src/misc/epicsString.c index 766af20b6..e18d9214a 100644 --- a/modules/libcom/src/misc/epicsString.c +++ b/modules/libcom/src/misc/epicsString.c @@ -23,9 +23,11 @@ #include #include +#include "epicsAssert.h" #include "epicsStdio.h" #include "cantProceed.h" #include "epicsString.h" +#include "epicsMath.h" /* Deprecated, use epicsStrnRawFromEscaped() instead */ int dbTranslateEscape(char *dst, const char *src) @@ -358,3 +360,71 @@ unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed) } return hash; } + +/* Compute normalized Levenshtein distance + * + * https://en.wikipedia.org/wiki/Levenshtein_distance + * + * We modify this to give half weight to case insensitive substitution. + * All normal integer weights are multiplied by two, with case + * insensitive added in as one. + */ +double epicsStrSimilarity(const char *A, const char *B) +{ + double ret = 0; + size_t lA, lB, a, b; + size_t norm; + size_t *dist0, *dist1, *stemp; + + lA = strlen(A); + lB = strlen(B); + + /* max number of edits to change A into B is max(lA, lB) */ + norm = lA > lB ? lA : lB; + /* take into account our weighting */ + norm *= 2u; + + dist0 = calloc(1+lB, sizeof(*dist0)); + dist1 = calloc(1+lB, sizeof(*dist1)); + if(!dist0 || !dist1) { + ret = -1.0; + goto done; + } + + for(b=0; b<1+lB; b++) + dist0[b] = 2*b; + + for(a=0; a inscost) + mincost = inscost; + if(mincost > subcost) + mincost = subcost; + + dist1[b+1] = mincost; + } + + stemp = dist0; + dist0 = dist1; + dist1 = stemp; + } + + ret = norm ? (norm - dist0[lB]) / (double)norm : 1.0; +done: + free(dist0); + free(dist1); + return ret; +} diff --git a/modules/libcom/src/misc/epicsString.h b/modules/libcom/src/misc/epicsString.h index 2ef675bc9..3c08e5277 100644 --- a/modules/libcom/src/misc/epicsString.h +++ b/modules/libcom/src/misc/epicsString.h @@ -41,6 +41,16 @@ LIBCOM_API char * epicsStrtok_r(char *s, const char *delim, char **lasts); LIBCOM_API unsigned int epicsStrHash(const char *str, unsigned int seed); LIBCOM_API unsigned int epicsMemHash(const char *str, size_t length, unsigned int seed); +/** Compare two strings and return a number in the range [0.0, 1.0] or -1.0 on error. + * + * Computes a normalized edit distance representing the similarity between two strings. + * + * @returns 1.0 when A and B are identical, down to 0.0 when A and B are unrelated, + * or < 0.0 on error. + * + * @since UNRELEASED + */ +LIBCOM_API double epicsStrSimilarity(const char *A, const char *B); /* dbTranslateEscape is deprecated, use epicsStrnRawFromEscaped instead */ LIBCOM_API int dbTranslateEscape(char *s, const char *ct); diff --git a/modules/libcom/test/epicsStringTest.c b/modules/libcom/test/epicsStringTest.c index 054f0c043..e4e95c998 100644 --- a/modules/libcom/test/epicsStringTest.c +++ b/modules/libcom/test/epicsStringTest.c @@ -17,6 +17,7 @@ #include "epicsUnitTest.h" #include "epicsString.h" +#include "epicsMath.h" #include "testMain.h" static @@ -74,6 +75,35 @@ void testGlob(void) { testOk1(epicsStrGlobMatch("hello","*")); } +static +void testDistance(void) { + double dist; + testDiag("testDistance()"); + +#define TEST(EXPECT, A, B) dist = epicsStrSimilarity(A, B); testOk(fabs(dist-(EXPECT))<0.01, "distance \"%s\", \"%s\" %f ~= %f", A, B, dist, EXPECT) + + TEST(1.00, "", ""); + TEST(1.00, "A", "A"); + TEST(0.00, "A", "B"); + TEST(1.00, "exact", "exact"); + TEST(0.90, "10 second", "10 seconds"); + TEST(0.71, "Passive", "Pensive"); + TEST(0.11, "10 second", "Pensive"); + TEST(0.97, "Set output to IVOV", "Set output To IVOV"); + + /* we modify Levenshtein to give half weight to case insensitive matches */ + + /* totally unrelated except for 'i' ~= 'I' */ + TEST(0.06, "Passive", "I/O Intr"); + TEST(0.06, "I/O Intr", "Pensive"); + /* 2x subst and 1x case subst, max distance 2xlen("YES") */ + TEST(0.50, "YES", "yes"); + TEST(0.00, "YES", "NO"); + TEST(0.67, "YES", "Yes"); + TEST(0.67, "Tes", "yes"); +#undef TEST +} + MAIN(epicsStringTest) { const char * const empty = ""; @@ -88,7 +118,7 @@ MAIN(epicsStringTest) char *s; int status; - testPlan(387); + testPlan(401); testChars(); @@ -284,5 +314,7 @@ MAIN(epicsStringTest) testOk(result[1] == 'g', " Terminator char got '%c'", result[1]); testOk(result[status] == 0, " 0-terminated"); + testDistance(); + return testDone(); } From 2c1c35268eccfc317f0e818112b1e5b67815c898 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 5 Feb 2021 07:05:22 -0800 Subject: [PATCH 13/22] db: Suggest DBF_MENU values on parser error --- .../database/src/ioc/dbStatic/dbLexRoutines.c | 1 + .../database/src/ioc/dbStatic/dbStaticLib.c | 46 +++++++++++++++++++ .../database/src/ioc/dbStatic/dbStaticPvt.h | 2 + 3 files changed, 49 insertions(+) diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 612dd6587..787ce29d8 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1187,6 +1187,7 @@ static void dbRecordField(char *name,char *value) errSymLookup(status, msg, sizeof(msg)); epicsPrintf("Can't set \"%s.%s\" to \"%s\" %s : %s\n", dbGetRecordName(pdbentry), name, value, pdbentry->message ? pdbentry->message : "", msg); + dbPutStringSuggest(pdbentry, value); yyerror(NULL); return; } diff --git a/modules/database/src/ioc/dbStatic/dbStaticLib.c b/modules/database/src/ioc/dbStatic/dbStaticLib.c index 4ed96272b..63a76d321 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticLib.c +++ b/modules/database/src/ioc/dbStatic/dbStaticLib.c @@ -2632,6 +2632,52 @@ long dbPutString(DBENTRY *pdbentry,const char *pstring) return(status); } +void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring) +{ + dbFldDes *pflddes = pdbentry->pflddes; + + switch (pflddes->field_type) { + case DBF_MENU: + case DBF_DEVICE: { + int i, nchoices = 0; + char** choices = NULL; + const char *best = NULL; + double maxdist = 0.0; /* don't offer suggestions which have no similarity */ + + if(pflddes->field_type==DBF_MENU) { + dbMenu *pdbMenu = (dbMenu *)pflddes->ftPvt; + if(!pdbMenu) + return; + + choices = pdbMenu->papChoiceValue; + nchoices = pdbMenu->nChoice; + + } else { + dbDeviceMenu *pdbDeviceMenu = dbGetDeviceMenu(pdbentry); + if(!pdbDeviceMenu) + return; + + choices = pdbDeviceMenu->papChoice; + nchoices = pdbDeviceMenu->nChoice; + } + + for(i=0; imaxdist) { + best = choices[i]; + maxdist = dist; + } + } + if(best) { + epicsPrintf(" Did you mean \"%s\"?\n", best); + } + } + break; + default: + break; + } +} + char * dbVerify(DBENTRY *pdbentry, const char *pstring) { dbFldDes *pflddes = pdbentry->pflddes; diff --git a/modules/database/src/ioc/dbStatic/dbStaticPvt.h b/modules/database/src/ioc/dbStatic/dbStaticPvt.h index 0197054ee..0ff9bdbce 100644 --- a/modules/database/src/ioc/dbStatic/dbStaticPvt.h +++ b/modules/database/src/ioc/dbStatic/dbStaticPvt.h @@ -38,6 +38,8 @@ long dbPutStringNum(DBENTRY *pdbentry,const char *pstring); void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) EPICS_PRINTF_STYLE(2,3); +void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring); + struct jlink; typedef struct dbLinkInfo { From 3f209efa3c4d25c7bf91af23288e021cfe2e44ea Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Feb 2021 09:23:27 -0800 Subject: [PATCH 14/22] release notes --- documentation/RELEASE_NOTES.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 1679526fb..ca30e7c8f 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -19,6 +19,11 @@ should also be read to understand what has changed since earlier releases. +### Add epicsStrSimilarity() + +Add epicsStrSimilarity() to epicsString.h which uses edit distance as an approximate comparison. +Enables a new "Did you mean ..." suggestion when a .db file provides an invalid value for a DBF_MENU or DBF_DEVICE field. + ### Build System: New `VALID_BUILDS` type "Command" Target architectures that support command-line programs that run the `main()` From 30e1431fb458659baef752bcd4fa84484ed057f0 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 8 Feb 2021 09:43:51 -0800 Subject: [PATCH 15/22] c89 compat --- modules/libcom/src/osi/osdNetIfAddrs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/libcom/src/osi/osdNetIfAddrs.c b/modules/libcom/src/osi/osdNetIfAddrs.c index 6e780cbbb..1ca4e8eca 100644 --- a/modules/libcom/src/osi/osdNetIfAddrs.c +++ b/modules/libcom/src/osi/osdNetIfAddrs.c @@ -37,6 +37,7 @@ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses (ELLLIST *pList, SOCKET socket, const osiSockAddr *pMatchAddr) { osiSockAddrNode *pNewNode; + struct ifaddrs *ifa; if ( pMatchAddr->sa.sa_family == AF_INET ) { if ( pMatchAddr->ia.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) { @@ -60,7 +61,7 @@ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses return; } - for ( struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next ) { + for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next ) { if ( ifa->ifa_addr == NULL ) { continue; } From 36d0fbd7be85a2ab44b64733d69435ec8663effc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 8 Feb 2021 13:34:01 -0600 Subject: [PATCH 16/22] Another c89 compat fix --- modules/libcom/src/osi/osdNetIfAddrs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/libcom/src/osi/osdNetIfAddrs.c b/modules/libcom/src/osi/osdNetIfAddrs.c index 1ca4e8eca..97be89b36 100644 --- a/modules/libcom/src/osi/osdNetIfAddrs.c +++ b/modules/libcom/src/osi/osdNetIfAddrs.c @@ -166,14 +166,14 @@ LIBCOM_API void epicsStdCall osiSockDiscoverBroadcastAddresses */ static void osiLocalAddrOnce (void *raw) { - struct ifaddrs *ifaddr; + struct ifaddrs *ifaddr, *ifa; int result = getifaddrs (&ifaddr); if ( result != 0 ) { errlogPrintf("osiLocalAddrOnce(): getifaddrs failed.\n"); return; } - for ( struct ifaddrs *ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next ) { + for ( ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next ) { if ( ifa->ifa_addr == NULL ) { continue; } From 552b2d17668add44f59f721ee6c1dc328c6067da Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Fri, 19 Feb 2021 15:40:39 -0800 Subject: [PATCH 17/22] dbConstAddLink bounds check dbrType cf. 6c914d19c3cfa2d183e44b7fe2c6211ab8c24a58 --- modules/database/src/ioc/db/dbConstLink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/database/src/ioc/db/dbConstLink.c b/modules/database/src/ioc/db/dbConstLink.c index 153b39c93..5ba79f2b0 100644 --- a/modules/database/src/ioc/db/dbConstLink.c +++ b/modules/database/src/ioc/db/dbConstLink.c @@ -169,6 +169,9 @@ static long dbConstLoadScalar(struct link *plink, short dbrType, void *pbuffer) return dbPutConvertJSON(pstr, dbrType, pbuffer, &nReq); } + if(dbrType>=NELEMENTS(convert)) + return S_db_badDbrtype; + return convert[dbrType](pstr, pbuffer, NULL); } From 9c23247c04f17266f68a5e0b577c5d445eff0123 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sat, 20 Feb 2021 17:02:09 -0600 Subject: [PATCH 18/22] Windows: Move cxx warning flag to the right CONFIG file --- configure/os/CONFIG.win32-x86.Common | 3 --- configure/os/CONFIG.win32-x86.win32-x86 | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure/os/CONFIG.win32-x86.Common b/configure/os/CONFIG.win32-x86.Common index c76af8ea3..8ea906688 100644 --- a/configure/os/CONFIG.win32-x86.Common +++ b/configure/os/CONFIG.win32-x86.Common @@ -26,6 +26,3 @@ endif # Needed to find dlls for base installed build tools (antelope,eflex,...) PATH := $(EPICS_BASE_BIN):$(PATH) - -# Silence the tr1 namespace deprecation warnings -USR_CXXFLAGS_WIN32 += -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index 22ce15967..a8115a714 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -107,6 +107,9 @@ CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE WARN_CXXFLAGS_YES = -W3 -w44355 -w44344 -w44251 WARN_CXXFLAGS_NO = -W1 +# Silence tr1 namespace deprecation warnings +WARN_CXXFLAGS += -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING + # # -Ox maximum optimizations # -GL whole program optimization From 9d0597fc1509363ee34876f4c2cd37667bc2251c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Sun, 21 Feb 2021 12:04:07 -0600 Subject: [PATCH 19/22] Fix MS compiler issue that I introduced into Freddie's code Plus a little more code simplification. --- modules/libcom/src/osi/os/WIN32/osdMonotonic.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c index e2d4f92ff..cff18d0e6 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMonotonic.c +++ b/modules/libcom/src/osi/os/WIN32/osdMonotonic.c @@ -46,13 +46,11 @@ epicsUInt64 epicsMonotonicResolution(void) epicsUInt64 epicsMonotonicGet(void) { LARGE_INTEGER val; + double dval; if (!QueryPerformanceCounter(&val)) { cantProceed("epicsMonotonicGet: Failed to read Windows Performance Counter\n"); return 0; } - else { /* return value in nanoseconds */ - val.QuadPart -= perfCounterOffset; - double nsec = (double)(val.QuadPart) * sec2nsec / perfCounterFrequency; - return (epicsUInt64)(nsec + 0.5); - } + dval = val.QuadPart - perfCounterOffset; + return (epicsUInt64)(dval * sec2nsec / perfCounterFrequency + 0.5); } From c4348dc6e0185d6b1e9c1ba2ffb991d292c451c3 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 21 Feb 2021 11:16:20 -0800 Subject: [PATCH 20/22] ci: fix gcc 4.8 builds --- .ci | 2 +- .github/workflows/ci-scripts-build.yml | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.ci b/.ci index ad8dd4a13..3db08b597 160000 --- a/.ci +++ b/.ci @@ -1 +1 @@ -Subproject commit ad8dd4a136348c7dc889fdc03a645e0f0358a2dc +Subproject commit 3db08b5977efd7a3ac8eecfa068b5bfdfdf84dd0 diff --git a/.github/workflows/ci-scripts-build.yml b/.github/workflows/ci-scripts-build.yml index 02daab742..83bdd9dde 100644 --- a/.github/workflows/ci-scripts-build.yml +++ b/.github/workflows/ci-scripts-build.yml @@ -82,19 +82,19 @@ jobs: - os: ubuntu-16.04 cmp: gcc-4.8 - utoolchain: true + utoolchain: "4.8" configuration: default name: "Ub-16 gcc-4.8" - os: ubuntu-16.04 cmp: gcc-4.9 - utoolchain: true + utoolchain: "4.9" configuration: default name: "Ub-16 gcc-4.9" - os: ubuntu-20.04 cmp: gcc-8 - utoolchain: true + utoolchain: "8" configuration: default name: "Ub-20 gcc-8" @@ -131,10 +131,11 @@ jobs: if: runner.os == 'Linux' - name: "apt-get install ${{ matrix.cmp }}" run: | + sudo apt-get update sudo apt-get -y install software-properties-common sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test sudo apt-get update - sudo apt-get -y install ${{ matrix.cmp }} + sudo apt-get -y install g++-${{ matrix.utoolchain }} if: matrix.utoolchain - name: Prepare and compile dependencies run: python .ci/cue.py prepare From 5a8b6e4111b869e8913b7bfaff4c56b546fb8879 Mon Sep 17 00:00:00 2001 From: Dirk Zimoch Date: Mon, 23 Nov 2020 14:59:28 +0100 Subject: [PATCH 21/22] posix: PI for epicsMutex, epicsEvent etc. Enable priority-inheritance for primitives based on pthread_mutex_t. Based on work by Till Straumann --- documentation/RELEASE_NOTES.md | 7 + modules/libcom/src/osi/Makefile | 1 + modules/libcom/src/osi/os/posix/osdEvent.c | 5 +- modules/libcom/src/osi/os/posix/osdMutex.c | 290 +++++------------- .../src/osi/os/posix/osdPosixMutexPriv.h | 28 ++ modules/libcom/src/osi/os/posix/osdSpin.c | 6 +- modules/libcom/src/osi/os/posix/osdThread.c | 9 +- 7 files changed, 121 insertions(+), 225 deletions(-) create mode 100644 modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index ca30e7c8f..617049dfa 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -19,6 +19,13 @@ should also be read to understand what has changed since earlier releases. +### Priority inversion safe posix mutexes + +On Posix systems, epicsMutex now support priority inheritance if available. +The IOC needs to run with SCHED_FIFO engaged. +Support for Posix implementations before POSIX.1-2001 (_XOPEN_SOURCE < 500, +glibc version < 2.3.3) has been dropped. + ### Add epicsStrSimilarity() Add epicsStrSimilarity() to epicsString.h which uses edit distance as an approximate comparison. diff --git a/modules/libcom/src/osi/Makefile b/modules/libcom/src/osi/Makefile index f0108e662..ce9dcc692 100644 --- a/modules/libcom/src/osi/Makefile +++ b/modules/libcom/src/osi/Makefile @@ -112,6 +112,7 @@ Com_SRCS += osdStdio.c THREAD_CPPFLAGS_NO += -DDONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING osdThread_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING)) osdSpin_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING)) +osdMutex_CPPFLAGS += $(THREAD_CPPFLAGS_$(USE_POSIX_THREAD_PRIORITY_SCHEDULING)) Com_SRCS += osdThread.c Com_SRCS += osdThreadExtra.c diff --git a/modules/libcom/src/osi/os/posix/osdEvent.c b/modules/libcom/src/osi/os/posix/osdEvent.c index 251f35d0b..db61c240b 100644 --- a/modules/libcom/src/osi/os/posix/osdEvent.c +++ b/modules/libcom/src/osi/os/posix/osdEvent.c @@ -23,6 +23,7 @@ #include "epicsEvent.h" #include "epicsTime.h" #include "errlog.h" +#include "osdPosixMutexPriv.h" struct epicsEventOSD { pthread_mutex_t mutex; @@ -50,11 +51,11 @@ LIBCOM_API epicsEventId epicsEventCreate(epicsEventInitialState init) epicsEventId pevent = malloc(sizeof(*pevent)); if (pevent) { - int status = pthread_mutex_init(&pevent->mutex, 0); + int status = osdPosixMutexInit(&pevent->mutex, 0); pevent->isFull = (init == epicsEventFull); if (status) { - printStatus(status, "pthread_mutex_init", "epicsEventCreate"); + printStatus(status, "osdPosixMutexInit", "epicsEventCreate"); } else { status = pthread_cond_init(&pevent->cond, 0); if (!status) diff --git a/modules/libcom/src/osi/os/posix/osdMutex.c b/modules/libcom/src/osi/os/posix/osdMutex.c index 707ae6304..6279c57f3 100644 --- a/modules/libcom/src/osi/os/posix/osdMutex.c +++ b/modules/libcom/src/osi/os/posix/osdMutex.c @@ -11,6 +11,10 @@ /* Author: Marty Kraimer Date: 13AUG1999 */ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + #include #include #include @@ -21,6 +25,7 @@ #include #include "epicsMutex.h" +#include "osdPosixMutexPriv.h" #include "cantProceed.h" #include "epicsTime.h" #include "errlog.h" @@ -38,6 +43,69 @@ cantProceed((method)); \ } +#if defined(DONT_USE_POSIX_THREAD_PRIORITY_SCHEDULING) +#undef _POSIX_THREAD_PRIO_INHERIT +#endif + +/* Global var - pthread_once does not support passing args but it is more efficient + * than epicsThreadOnce which always acquires a mutex. + */ +static pthread_mutexattr_t globalAttrDefault; +static pthread_mutexattr_t globalAttrRecursive; +static pthread_once_t globalAttrInitOnce = PTHREAD_ONCE_INIT; + +static void globalAttrInit() +{ + int status; + + status = pthread_mutexattr_init(&globalAttrDefault); + checkStatusQuit(status,"pthread_mutexattr_init(&globalAttrDefault)","globalAttrInit"); + status = pthread_mutexattr_init(&globalAttrRecursive); + checkStatusQuit(status,"pthread_mutexattr_init(&globalAttrRecursive)","globalAttrInit"); + status = pthread_mutexattr_settype(&globalAttrRecursive, PTHREAD_MUTEX_RECURSIVE); + checkStatusQuit(status, "pthread_mutexattr_settype(&globalAttrRecursive, PTHREAD_MUTEX_RECURSIVE)", "globalAttrInit"); +#if defined _POSIX_THREAD_PRIO_INHERIT + status = pthread_mutexattr_setprotocol(&globalAttrDefault, PTHREAD_PRIO_INHERIT); + if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocol(&globalAttrDefault, PTHREAD_PRIO_INHERIT)"); + status = pthread_mutexattr_setprotocol(&globalAttrRecursive, PTHREAD_PRIO_INHERIT); + if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocol(&globalAttrRecursive, PTHREAD_PRIO_INHERIT)"); + if (status == 0) { + /* Can we really use PTHREAD_PRIO_INHERIT? */ + pthread_mutex_t temp; + status = pthread_mutex_init(&temp, &globalAttrRecursive); + if (errVerbose) checkStatus(status, "pthread_mutex_init(&temp, &globalAttrRecursive)"); + if (status != 0) { + /* No, PTHREAD_PRIO_INHERIT does not work, fall back to PTHREAD_PRIO_NONE */; + pthread_mutexattr_setprotocol(&globalAttrDefault, PTHREAD_PRIO_NONE); + pthread_mutexattr_setprotocol(&globalAttrRecursive, PTHREAD_PRIO_NONE); + } else { + pthread_mutex_destroy(&temp); + } + } +#endif +} + +int osdPosixMutexInit (pthread_mutex_t *m, int mutextype) +{ + pthread_mutexattr_t *atts; + int status; + + status = pthread_once( &globalAttrInitOnce, globalAttrInit ); + checkStatusQuit(status,"pthread_once","epicsPosixMutexAttrGet"); + + switch (mutextype) { + case PTHREAD_MUTEX_DEFAULT: + atts = &globalAttrDefault; + break; + case PTHREAD_MUTEX_RECURSIVE: + atts = &globalAttrRecursive; + break; + default: + return ENOTSUP; + } + return pthread_mutex_init(m, atts); +} + static int mutexLock(pthread_mutex_t *id) { int status; @@ -48,23 +116,8 @@ static int mutexLock(pthread_mutex_t *id) return status; } -/* Until these can be demonstrated to work leave them undefined*/ -/* On solaris 8 _POSIX_THREAD_PRIO_INHERIT fails*/ -#undef _POSIX_THREAD_PROCESS_SHARED -#undef _POSIX_THREAD_PRIO_INHERIT - -/* Two completely different implementations are provided below - * If support is available for PTHREAD_MUTEX_RECURSIVE then - * only pthread_mutex is used. - * If support is not available for PTHREAD_MUTEX_RECURSIVE then - * a much more complicated solution is required - */ - - -#if defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 typedef struct epicsMutexOSD { pthread_mutex_t lock; - pthread_mutexattr_t mutexAttr; } epicsMutexOSD; epicsMutexOSD * epicsMutexOsdCreate(void) { @@ -73,32 +126,12 @@ epicsMutexOSD * epicsMutexOsdCreate(void) { pmutex = calloc(1, sizeof(*pmutex)); if(!pmutex) - goto fail; + return NULL; - status = pthread_mutexattr_init(&pmutex->mutexAttr); - if (status) - goto fail; + status = osdPosixMutexInit(&pmutex->lock, PTHREAD_MUTEX_RECURSIVE); + if (!status) + return pmutex; -#if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT > 0 - status = pthread_mutexattr_setprotocol(&pmutex->mutexAttr, - PTHREAD_PRIO_INHERIT); - if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal"); -#endif /*_POSIX_THREAD_PRIO_INHERIT*/ - - status = pthread_mutexattr_settype(&pmutex->mutexAttr, - PTHREAD_MUTEX_RECURSIVE); - checkStatus(status, "pthread_mutexattr_settype"); - if (status) - goto fail; - - status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr); - if (status) - goto dattr; - return pmutex; - -dattr: - pthread_mutexattr_destroy(&pmutex->mutexAttr); -fail: free(pmutex); return NULL; } @@ -109,11 +142,9 @@ void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex) status = pthread_mutex_destroy(&pmutex->lock); checkStatus(status, "pthread_mutex_destroy"); - status = pthread_mutexattr_destroy(&pmutex->mutexAttr); - checkStatus(status, "pthread_mutexattr_destroy"); free(pmutex); } - + void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex) { int status; @@ -157,178 +188,3 @@ void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level) */ printf(" pthread_mutex_t* uaddr=%p\n", &pmutex->lock); } - -#else /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */ - -typedef struct epicsMutexOSD { - pthread_mutex_t lock; - pthread_mutexattr_t mutexAttr; - pthread_cond_t waitToBeOwner; -#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0 - pthread_condattr_t condAttr; -#endif /*_POSIX_THREAD_PROCESS_SHARED*/ - int count; - int owned; /* TRUE | FALSE */ - pthread_t ownerTid; -} epicsMutexOSD; - -epicsMutexOSD * epicsMutexOsdCreate(void) { - epicsMutexOSD *pmutex; - int status; - - pmutex = calloc(1, sizeof(*pmutex)); - if(!pmutex) - return NULL; - - status = pthread_mutexattr_init(&pmutex->mutexAttr); - if(status) - goto fail; - -#if defined(_POSIX_THREAD_PRIO_INHERIT) && _POSIX_THREAD_PRIO_INHERIT > 0 - status = pthread_mutexattr_setprotocol( - &pmutex->mutexAttr,PTHREAD_PRIO_INHERIT); - if (errVerbose) checkStatus(status, "pthread_mutexattr_setprotocal"); -#endif /*_POSIX_THREAD_PRIO_INHERIT*/ - - status = pthread_mutex_init(&pmutex->lock, &pmutex->mutexAttr); - if(status) - goto dattr; - -#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0 - status = pthread_condattr_init(&pmutex->condAttr); - checkStatus(status, "pthread_condattr_init"); - status = pthread_condattr_setpshared(&pmutex->condAttr, - PTHREAD_PROCESS_PRIVATE); - checkStatus(status, "pthread_condattr_setpshared"); - status = pthread_cond_init(&pmutex->waitToBeOwner, &pmutex->condAttr); -#else - status = pthread_cond_init(&pmutex->waitToBeOwner, 0); -#endif /*_POSIX_THREAD_PROCESS_SHARED*/ - if(status) - goto dmutex; - - return pmutex; - -dmutex: - pthread_mutex_destroy(&pmutex->lock); -dattr: - pthread_mutexattr_destroy(&pmutex->mutexAttr); -fail: - free(pmutex); - return NULL; -} - -void epicsMutexOsdDestroy(struct epicsMutexOSD * pmutex) -{ - int status; - - status = pthread_cond_destroy(&pmutex->waitToBeOwner); - checkStatus(status, "pthread_cond_destroy"); -#if defined(_POSIX_THREAD_PROCESS_SHARED) && _POSIX_THREAD_PROCESS_SHARED > 0 - status = pthread_condattr_destroy(&pmutex->condAttr); -#endif /*_POSIX_THREAD_PROCESS_SHARED*/ - status = pthread_mutex_destroy(&pmutex->lock); - checkStatus(status, "pthread_mutex_destroy"); - status = pthread_mutexattr_destroy(&pmutex->mutexAttr); - checkStatus(status, "pthread_mutexattr_destroy"); - free(pmutex); -} - -void epicsMutexOsdUnlock(struct epicsMutexOSD * pmutex) -{ - int status; - - status = mutexLock(&pmutex->lock); - checkStatus(status, "pthread_mutex_lock epicsMutexOsdUnlock"); - if(status) - return; - - if ((pmutex->count <= 0) || (pmutex->ownerTid != pthread_self())) { - pthread_mutex_unlock(&pmutex->lock); - checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock"); - errlogPrintf("epicsMutexOsdUnlock but caller is not owner\n"); - cantProceed("epicsMutexOsdUnlock but caller is not owner"); - return; - } - - pmutex->count--; - if (pmutex->count == 0) { - pmutex->owned = 0; - pmutex->ownerTid = 0; - status = pthread_cond_signal(&pmutex->waitToBeOwner); - checkStatusQuit(status, "pthread_cond_signal epicsMutexOsdUnlock", "epicsMutexOsdUnlock"); - } - - status = pthread_mutex_unlock(&pmutex->lock); - checkStatus(status, "pthread_mutex_unlock epicsMutexOsdUnlock"); -} - -static int condWait(pthread_cond_t *condId, pthread_mutex_t *mutexId) -{ - int status; - - while ((status = pthread_cond_wait(condId, mutexId)) == EINTR) { - errlogPrintf("pthread_cond_wait returned EINTR. Violates SUSv3\n"); - } - return status; -} - -epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD * pmutex) -{ - pthread_t tid = pthread_self(); - int status; - - if (!pmutex || !tid) return epicsMutexLockError; - status = mutexLock(&pmutex->lock); - if (status == EINVAL) return epicsMutexLockError; - checkStatus(status, "pthread_mutex_lock epicsMutexOsdLock"); - if(status) - return epicsMutexLockError; - - while (pmutex->owned && !pthread_equal(pmutex->ownerTid, tid)) - condWait(&pmutex->waitToBeOwner, &pmutex->lock); - pmutex->ownerTid = tid; - pmutex->owned = 1; - pmutex->count++; - - status = pthread_mutex_unlock(&pmutex->lock); - checkStatus(status, "pthread_mutex_unlock epicsMutexOsdLock"); - if(status) - return epicsMutexLockError; - return epicsMutexLockOK; -} - -epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD * pmutex) -{ - pthread_t tid = pthread_self(); - epicsMutexLockStatus result; - int status; - - status = mutexLock(&pmutex->lock); - if (status == EINVAL) return epicsMutexLockError; - checkStatus(status, "pthread_mutex_lock epicsMutexOsdTryLock"); - if(status) - return epicsMutexLockError; - - if (!pmutex->owned || pthread_equal(pmutex->ownerTid, tid)) { - pmutex->ownerTid = tid; - pmutex->owned = 1; - pmutex->count++; - result = epicsMutexLockOK; - } else { - result = epicsMutexLockTimeout; - } - - status = pthread_mutex_unlock(&pmutex->lock); - checkStatus(status, "pthread_mutex_unlock epicsMutexOsdTryLock"); - if(status) - return epicsMutexLockError; - return result; -} - -void epicsMutexOsdShow(struct epicsMutexOSD *pmutex,unsigned int level) -{ - printf("ownerTid %p count %d owned %d\n", - (void *)pmutex->ownerTid, pmutex->count, pmutex->owned); -} -#endif /*defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE)>=500 */ diff --git a/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h b/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h new file mode 100644 index 000000000..2b6846c91 --- /dev/null +++ b/modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h @@ -0,0 +1,28 @@ +/*************************************************************************\ +* 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. +* SPDX-License-Identifier: EPICS +* EPICS Base is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#ifndef osdPosixMutexPrivh +#define osdPosixMutexPrivh + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Returns ENOTSUP if requested mutextype is not supported */ +/* At the moment, only 0 (default non recursive mutex) and PTHREAD_MUTEX_RECURSIVE are supported */ +int osdPosixMutexInit(pthread_mutex_t *,int mutextype); + +#ifdef __cplusplus +} +#endif + +#endif /* osdPosixMutexPrivh */ diff --git a/modules/libcom/src/osi/os/posix/osdSpin.c b/modules/libcom/src/osi/os/posix/osdSpin.c index 1f8434b8c..f039e7c34 100644 --- a/modules/libcom/src/osi/os/posix/osdSpin.c +++ b/modules/libcom/src/osi/os/posix/osdSpin.c @@ -109,6 +109,8 @@ void epicsSpinUnlock(epicsSpinId spin) { * POSIX MUTEX IMPLEMENTATION */ +#include + typedef struct epicsSpin { pthread_mutex_t lock; } epicsSpin; @@ -121,8 +123,8 @@ epicsSpinId epicsSpinCreate(void) { if (!spin) goto fail; - status = pthread_mutex_init(&spin->lock, NULL); - checkStatus(status, "pthread_mutex_init"); + status = osdPosixMutexInit(&spin->lock, 0); + checkStatus(status, "osdPosixMutexInit"); if (status) goto fail; diff --git a/modules/libcom/src/osi/os/posix/osdThread.c b/modules/libcom/src/osi/os/posix/osdThread.c index fe375fd16..45255881f 100644 --- a/modules/libcom/src/osi/os/posix/osdThread.c +++ b/modules/libcom/src/osi/os/posix/osdThread.c @@ -32,6 +32,7 @@ #include "ellLib.h" #include "epicsEvent.h" #include "epicsMutex.h" +#include "osdPosixMutexPriv.h" #include "epicsString.h" #include "epicsThread.h" #include "cantProceed.h" @@ -327,10 +328,10 @@ static void once(void) int status; pthread_key_create(&getpthreadInfo,0); - status = pthread_mutex_init(&onceLock,0); - checkStatusOnceQuit(status,"pthread_mutex_init","epicsThreadInit"); - status = pthread_mutex_init(&listLock,0); - checkStatusOnceQuit(status,"pthread_mutex_init","epicsThreadInit"); + status = osdPosixMutexInit(&onceLock,0); + checkStatusOnceQuit(status,"osdPosixMutexInit","epicsThreadInit"); + status = osdPosixMutexInit(&listLock,0); + checkStatusOnceQuit(status,"osdPosixMutexInit","epicsThreadInit"); pcommonAttr = calloc(1,sizeof(commonAttr)); if(!pcommonAttr) checkStatusOnceQuit(errno,"calloc","epicsThreadInit"); status = pthread_attr_init(&pcommonAttr->attr); From 5593103c11157aada4e40c5f00c6b033387fb57e Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Sun, 21 Feb 2021 10:36:21 -0800 Subject: [PATCH 22/22] posix: epicsMutexShowAll() print if PI mutex are used Confirms that pthread_mutex_t are actually being created with PTHREAD_PRIO_INHERIT, ie. if both libc and kernel support is present. --- documentation/RELEASE_NOTES.md | 3 +++ modules/libcom/src/osi/epicsMutex.cpp | 2 ++ modules/libcom/src/osi/epicsMutex.h | 3 +++ modules/libcom/src/osi/os/RTEMS/osdMutex.c | 4 ++++ modules/libcom/src/osi/os/WIN32/osdMutex.c | 4 ++++ modules/libcom/src/osi/os/posix/osdMutex.c | 14 ++++++++++++++ modules/libcom/src/osi/os/vxWorks/osdMutex.c | 3 +++ 7 files changed, 33 insertions(+) diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 617049dfa..eb9ba33fa 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -26,6 +26,9 @@ The IOC needs to run with SCHED_FIFO engaged. Support for Posix implementations before POSIX.1-2001 (_XOPEN_SOURCE < 500, glibc version < 2.3.3) has been dropped. +The epicsMutexShowAll() function (available through IOC shell) +will print "PI is enabled" if both libc and kernel support is present. + ### Add epicsStrSimilarity() Add epicsStrSimilarity() to epicsString.h which uses edit distance as an approximate comparison. diff --git a/modules/libcom/src/osi/epicsMutex.cpp b/modules/libcom/src/osi/epicsMutex.cpp index 1c15583a6..0a63a6f33 100644 --- a/modules/libcom/src/osi/epicsMutex.cpp +++ b/modules/libcom/src/osi/epicsMutex.cpp @@ -17,6 +17,7 @@ * currently safe to convert a thread id to a thread name because * the thread may have exited making the thread id invalid. */ +#define EPICS_PRIVATE_API #include @@ -223,6 +224,7 @@ void epicsStdCall epicsMutexShowAll(int onlyLocked,unsigned int level) printf("ellCount(&mutexList) %d ellCount(&freeList) %d\n", ellCount(&mutexList),ellCount(&freeList)); + epicsMutexOsdShowAll(); epicsMutexLockStatus lockStat = epicsMutexOsdLock(epicsMutexGlobalLock); assert ( lockStat == epicsMutexLockOK ); diff --git a/modules/libcom/src/osi/epicsMutex.h b/modules/libcom/src/osi/epicsMutex.h index fec4de9f8..fc47eda0c 100644 --- a/modules/libcom/src/osi/epicsMutex.h +++ b/modules/libcom/src/osi/epicsMutex.h @@ -258,6 +258,9 @@ void epicsMutexOsdUnlock(struct epicsMutexOSD *); epicsMutexLockStatus epicsMutexOsdLock(struct epicsMutexOSD *); epicsMutexLockStatus epicsMutexOsdTryLock(struct epicsMutexOSD *); void epicsMutexOsdShow(struct epicsMutexOSD *,unsigned int level); +#ifdef EPICS_PRIVATE_API +void epicsMutexOsdShowAll(void); +#endif #ifdef __cplusplus } diff --git a/modules/libcom/src/osi/os/RTEMS/osdMutex.c b/modules/libcom/src/osi/os/RTEMS/osdMutex.c index 80e7872ff..44adf2f6e 100644 --- a/modules/libcom/src/osi/os/RTEMS/osdMutex.c +++ b/modules/libcom/src/osi/os/RTEMS/osdMutex.c @@ -22,6 +22,8 @@ #include #include +#define EPICS_PRIVATE_API + #include "epicsStdio.h" #include "epicsMutex.h" #include "epicsEvent.h" @@ -193,3 +195,5 @@ LIBCOM_API void epicsMutexOsdShow(struct epicsMutexOSD * id,unsigned int level) #endif epicsEventShow ((epicsEventId)id,level); } + +void epicsMutexOsdShowAll(void) {} diff --git a/modules/libcom/src/osi/os/WIN32/osdMutex.c b/modules/libcom/src/osi/os/WIN32/osdMutex.c index 596d5af65..405a9c741 100644 --- a/modules/libcom/src/osi/os/WIN32/osdMutex.c +++ b/modules/libcom/src/osi/os/WIN32/osdMutex.c @@ -42,6 +42,8 @@ #endif #include +#define EPICS_PRIVATE_API + #include "libComAPI.h" #include "epicsMutex.h" #include "epicsAssert.h" @@ -176,3 +178,5 @@ void epicsMutexOsdShow ( epicsMutexOSD * pSem, unsigned level ) } } +void epicsMutexOsdShowAll(void) {} + diff --git a/modules/libcom/src/osi/os/posix/osdMutex.c b/modules/libcom/src/osi/os/posix/osdMutex.c index 6279c57f3..83833f85c 100644 --- a/modules/libcom/src/osi/os/posix/osdMutex.c +++ b/modules/libcom/src/osi/os/posix/osdMutex.c @@ -24,11 +24,14 @@ #include #include +#define EPICS_PRIVATE_API + #include "epicsMutex.h" #include "osdPosixMutexPriv.h" #include "cantProceed.h" #include "epicsTime.h" #include "errlog.h" +#include "epicsStdio.h" #include "epicsAssert.h" #define checkStatus(status,message) \ @@ -188,3 +191,14 @@ void epicsMutexOsdShow(struct epicsMutexOSD * pmutex, unsigned int level) */ printf(" pthread_mutex_t* uaddr=%p\n", &pmutex->lock); } + +void epicsMutexOsdShowAll(void) +{ + int proto = -1; + int ret = pthread_mutexattr_getprotocol(&globalAttrRecursive, &proto); + if(ret) { + printf("PI maybe not enabled: %d\n", ret); + } else { + printf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not"); + } +} diff --git a/modules/libcom/src/osi/os/vxWorks/osdMutex.c b/modules/libcom/src/osi/os/vxWorks/osdMutex.c index 4b439a1f1..d772bf2dd 100644 --- a/modules/libcom/src/osi/os/vxWorks/osdMutex.c +++ b/modules/libcom/src/osi/os/vxWorks/osdMutex.c @@ -20,6 +20,7 @@ /* The following not defined in an vxWorks header */ int sysClkRateGet(void); +#define EPICS_PRIVATE_API #include "epicsMutex.h" @@ -47,3 +48,5 @@ void epicsMutexOsdShow(struct epicsMutexOSD * id,unsigned int level) { semShow((SEM_ID)id,level); } + +void epicsMutexOsdShowAll(void) {}