This commit is contained in:
Brendan Chandler
2021-02-25 14:06:41 -06:00
38 changed files with 984 additions and 610 deletions

View File

@@ -93,19 +93,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"
@@ -142,10 +142,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

View File

@@ -0,0 +1,14 @@
# CONFIG.Common.darwin-aarch64
#
# This file is maintained by the build community.
#
# Definitions for darwin-aarch64 target builds
# Sites may override these definitions in CONFIG_SITE.Common.darwin-aarch64
#-------------------------------------------------------
#
# 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -19,6 +19,21 @@ 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.
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.
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()`

View File

@@ -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*/

View File

@@ -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);
}

View File

@@ -1185,8 +1185,9 @@ 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);
dbPutStringSuggest(pdbentry, value);
yyerror(NULL);
return;
}

View File

@@ -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;
@@ -2635,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; i<nchoices; i++) {
double dist = epicsStrSimilarity(pstring, choices[i]);
if(dist>maxdist) {
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;

View File

@@ -36,6 +36,10 @@ 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);
void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring);
struct jlink;
typedef struct dbLinkInfo {

View File

@@ -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)

View File

@@ -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

View File

@@ -23,9 +23,11 @@
#include <errno.h>
#include <ctype.h>
#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<lA; a++) {
dist1[0] = 2*(a+1);
for(b=0; b<lB; b++) {
size_t delcost = dist0[b+1] + 2,
inscost = dist1[b] + 2,
subcost = dist0[b],
mincost = delcost;
char ca = A[a], cb = B[b];
if(ca!=cb)
subcost++;
if(toupper((int)ca)!=toupper((int)cb))
subcost++;
if(mincost > 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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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 <new>
@@ -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 );

View File

@@ -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
}

View File

@@ -0,0 +1 @@
#include "../osi/osdNetIfAddrs.c"

View File

@@ -0,0 +1 @@
#include "../osi/osdNetIfAddrs.c"

View File

@@ -22,6 +22,8 @@
#include <rtems.h>
#include <rtems/error.h>
#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) {}

View File

@@ -10,24 +10,31 @@
#define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE
#include "dbDefs.h"
#include "errlog.h"
#include "cantProceed.h"
#include "epicsTime.h"
#include "generalTimeSup.h"
static unsigned char osdUsePrefCounter;
static epicsUInt64 osdMonotonicResolution;
static epicsUInt64 osdMonotonicResolution; /* timer resolution in nanoseconds */
static epicsUInt64 perfCounterFrequency; /* performance counter tics per second */
static LONGLONG perfCounterOffset; /* performance counter value at initialisation */
static const epicsUInt64 sec2nsec = 1000000000; /* number of nanoseconds in a second */
void osdMonotonicInit(void)
{
LARGE_INTEGER freq, val;
if(!QueryPerformanceFrequency(&freq) ||
!QueryPerformanceCounter(&val))
{
double period = 1.0/freq.QuadPart;
osdMonotonicResolution = period*1e9;
osdUsePrefCounter = 1;
} else {
osdMonotonicResolution = 1e6; /* 1 ms TODO place holder */
/* QueryPerformanceCounter() is available on Windows 2000 and later, and is
* guaranteed to succeed on Windows XP or later. On Windows 2000 it may
* return 0 for freq.QuadPart if unavailable */
if (QueryPerformanceFrequency(&freq) &&
QueryPerformanceCounter(&val) &&
freq.QuadPart != 0) {
perfCounterFrequency = freq.QuadPart;
perfCounterOffset = val.QuadPart;
osdMonotonicResolution = sec2nsec / perfCounterFrequency +
!!(sec2nsec % perfCounterFrequency);
}
else {
cantProceed("osdMonotonicInit: Windows Performance Counter is not available\n");
}
}
@@ -39,15 +46,11 @@ 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;
} else {
epicsUInt64 ret = GetTickCount();
ret *= 1000000;
return ret;
double dval;
if (!QueryPerformanceCounter(&val)) {
cantProceed("epicsMonotonicGet: Failed to read Windows Performance Counter\n");
return 0;
}
dval = val.QuadPart - perfCounterOffset;
return (epicsUInt64)(dval * sec2nsec / perfCounterFrequency + 0.5);
}

View File

@@ -42,6 +42,8 @@
#endif
#include <windows.h>
#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) {}

View File

@@ -0,0 +1 @@
#include "../osi/osdNetIfAddrs.c"

View File

@@ -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 <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#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"

View File

@@ -0,0 +1 @@
#include "../osi/osdNetIfAddrs.c"

View File

@@ -0,0 +1 @@
#include "../osi/osdNetIfAddrs.c"

View File

@@ -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)

View File

@@ -11,6 +11,10 @@
/* Author: Marty Kraimer Date: 13AUG1999 */
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
@@ -20,10 +24,14 @@
#include <unistd.h>
#include <pthread.h>
#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) \
@@ -38,6 +46,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 +119,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 +129,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 +145,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 +191,14 @@ 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)
void epicsMutexOsdShowAll(void)
{
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;
int proto = -1;
int ret = pthread_mutexattr_getprotocol(&globalAttrRecursive, &proto);
if(ret) {
printf("PI maybe not enabled: %d\n", ret);
} else {
result = epicsMutexLockTimeout;
printf("PI is%s enabled\n", proto==PTHREAD_PRIO_INHERIT ? "" : " not");
}
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 */

View File

@@ -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 <pthread.h>
#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 */

View File

@@ -109,6 +109,8 @@ void epicsSpinUnlock(epicsSpinId spin) {
* POSIX MUTEX IMPLEMENTATION
*/
#include <osdPosixMutexPriv.h>
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;

View File

@@ -33,6 +33,7 @@
#include "ellLib.h"
#include "epicsEvent.h"
#include "epicsMutex.h"
#include "osdPosixMutexPriv.h"
#include "epicsString.h"
#include "epicsThread.h"
#include "cantProceed.h"
@@ -328,10 +329,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);

View File

@@ -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) {}

View File

@@ -0,0 +1,223 @@
/*************************************************************************\
* 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 <ctype.h>
#include <ifaddrs.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#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;
struct ifaddrs *ifa;
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 ( 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, *ifa;
int result = getifaddrs (&ifaddr);
if ( result != 0 ) {
errlogPrintf("osiLocalAddrOnce(): getifaddrs failed.\n");
return;
}
for ( 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;
}

View File

@@ -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 <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#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;
}

View File

@@ -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();
}

View File

@@ -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";
}