Merge branch '7.0' of https://github.com/epics-base/epics-base into rtems5
This commit is contained in:
9
.github/workflows/ci-scripts-build.yml
vendored
9
.github/workflows/ci-scripts-build.yml
vendored
@@ -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
|
||||
|
||||
14
configure/os/CONFIG.Common.darwin-aarch64
Normal file
14
configure/os/CONFIG.Common.darwin-aarch64
Normal 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
|
||||
8
configure/os/CONFIG.darwin-aarch64.Common
Normal file
8
configure/os/CONFIG.darwin-aarch64.Common
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
9
configure/os/CONFIG_SITE.Common.darwin-aarch64
Normal file
9
configure/os/CONFIG_SITE.Common.darwin-aarch64
Normal 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
|
||||
@@ -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()`
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
1
modules/libcom/src/osi/os/Darwin/osdNetIntf.c
Normal file
1
modules/libcom/src/osi/os/Darwin/osdNetIntf.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../osi/osdNetIfAddrs.c"
|
||||
1
modules/libcom/src/osi/os/Linux/osdNetIntf.c
Normal file
1
modules/libcom/src/osi/os/Linux/osdNetIntf.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../osi/osdNetIfAddrs.c"
|
||||
@@ -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) {}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
1
modules/libcom/src/osi/os/cygwin32/osdNetIntf.c
Normal file
1
modules/libcom/src/osi/os/cygwin32/osdNetIntf.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../osi/osdNetIfAddrs.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 <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"
|
||||
|
||||
1
modules/libcom/src/osi/os/freebsd/osdNetIntf.c
Normal file
1
modules/libcom/src/osi/os/freebsd/osdNetIntf.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../osi/osdNetIfAddrs.c"
|
||||
1
modules/libcom/src/osi/os/iOS/osdNetIntf.c
Normal file
1
modules/libcom/src/osi/os/iOS/osdNetIntf.c
Normal file
@@ -0,0 +1 @@
|
||||
#include "../osi/osdNetIfAddrs.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)
|
||||
|
||||
@@ -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 */
|
||||
|
||||
28
modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h
Normal file
28
modules/libcom/src/osi/os/posix/osdPosixMutexPriv.h
Normal 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 */
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
223
modules/libcom/src/osi/osdNetIfAddrs.c
Normal file
223
modules/libcom/src/osi/osdNetIfAddrs.c
Normal 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;
|
||||
}
|
||||
352
modules/libcom/src/osi/osdNetIfConf.c
Normal file
352
modules/libcom/src/osi/osdNetIfConf.c
Normal 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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user