Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
57c930fbee | ||
|
|
785b777baf | ||
|
|
d0d15ee911 | ||
|
|
5af9c7e50d | ||
|
|
5fe563bed8 | ||
|
|
11fba63d18 | ||
|
|
1db37bcd91 | ||
|
|
beec00b403 | ||
|
|
4966baf423 | ||
|
|
e5b4829074 | ||
|
|
d8b5616772 | ||
|
|
92615a77fe | ||
|
|
b3f92d81db | ||
|
|
839f764bcb | ||
|
|
4bb50fe664 | ||
|
|
c77f32b19c | ||
|
|
66ce1c2076 | ||
|
|
1a9dc993c1 | ||
|
|
cb1571783b | ||
|
|
5dfc6caf3c | ||
|
|
cb49bd0133 | ||
|
|
4720b61c1f | ||
| 4383cf291e | |||
|
|
a6977ae731 | ||
|
|
07cbf00187 | ||
|
|
c75b9ad0be | ||
|
|
87acb98d1e | ||
|
|
403e203325 | ||
|
|
a7a56912eb | ||
|
|
fe4a32e425 | ||
|
|
823386573f | ||
|
|
ea8247586f | ||
|
|
e88a186fc3 | ||
|
|
20f32068c3 | ||
|
|
8998341588 |
2
.ci
2
.ci
Submodule .ci updated: 130e88b709...20f8e05393
2
.github/workflows/check-editorconfig.yml
vendored
2
.github/workflows/check-editorconfig.yml
vendored
@@ -8,6 +8,6 @@ jobs:
|
||||
editorconfig:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: EditorConfig-Action
|
||||
uses: greut/eclint-action@v0
|
||||
|
||||
5
.github/workflows/ci-scripts-build.yml
vendored
5
.github/workflows/ci-scripts-build.yml
vendored
@@ -29,6 +29,7 @@ on:
|
||||
- '.gitattributes'
|
||||
- '**/*.html'
|
||||
- '**/*.md'
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
SETUP_PATH: .ci-local:.ci
|
||||
@@ -283,6 +284,10 @@ jobs:
|
||||
submodules: true
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@master
|
||||
if: matrix.image!='centos:7'
|
||||
- name: Automatic core dumper analysis
|
||||
uses: mdavidsaver/ci-core-dumper@node16
|
||||
if: matrix.image=='centos:7'
|
||||
- name: Prepare and compile dependencies
|
||||
run: python .ci/cue.py prepare
|
||||
- name: Build main module
|
||||
|
||||
@@ -52,7 +52,7 @@ EPICS_MODIFICATION = 8
|
||||
|
||||
# EPICS_PATCH_LEVEL must be a number (win32 resource file requirement)
|
||||
# Not included in the official EPICS version number if zero
|
||||
EPICS_PATCH_LEVEL = 0
|
||||
EPICS_PATCH_LEVEL = 1
|
||||
|
||||
# Immediately after an official release the EPICS_PATCH_LEVEL is incremented
|
||||
# and the -DEV suffix is added (similar to the Maven -SNAPSHOT versions)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
EPICS_CA_MAJOR_VERSION = 4
|
||||
EPICS_CA_MINOR_VERSION = 14
|
||||
EPICS_CA_MAINTENANCE_VERSION = 3
|
||||
EPICS_CA_MAINTENANCE_VERSION = 4
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
EPICS_DATABASE_MAJOR_VERSION = 3
|
||||
EPICS_DATABASE_MINOR_VERSION = 23
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 0
|
||||
EPICS_DATABASE_MAINTENANCE_VERSION = 1
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
EPICS_LIBCOM_MAJOR_VERSION = 3
|
||||
EPICS_LIBCOM_MINOR_VERSION = 23
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 0
|
||||
EPICS_LIBCOM_MAINTENANCE_VERSION = 1
|
||||
|
||||
# Development flag, set to zero for release versions
|
||||
|
||||
|
||||
@@ -34,5 +34,9 @@ CFG += TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
ifeq ($(GNU),YES)
|
||||
# Pass compiler flags to preprocessor to enable _FORTIFY_SOURCE
|
||||
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): CPPFLAGS += $(CFLAGS)
|
||||
endif
|
||||
TOOLCHAIN.$(EPICS_HOST_ARCH).$(T_A): toolchain.c
|
||||
$(PREPROCESS.cpp)
|
||||
|
||||
@@ -532,11 +532,11 @@ endif # LOADABLE_SHRLIB_SUFFIX
|
||||
ifneq ($(INSTALL_CONFIGS),)
|
||||
$(INSTALL_CONFIG)/%: %
|
||||
$(ECHO) "Installing config file $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D))
|
||||
|
||||
$(INSTALL_CONFIG)/%: ../%
|
||||
$(ECHO) "Installing config file $@"
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $< $(@D)
|
||||
@$(INSTALL) -d -m $(INSTALL_PERMISSIONS) $(abspath $< $(@D))
|
||||
endif
|
||||
|
||||
$(INSTALL_INCLUDE)/%: $(COMMON_DIR)/%
|
||||
|
||||
@@ -47,3 +47,8 @@ COMMANDLINE_LIBRARY ?= EPICS
|
||||
#else
|
||||
COMMANDLINE_LIBRARY ?= $(strip $(if $(wildcard $(if $(GNU_DIR),$(GNU_DIR)/include/readline/readline.h)), READLINE, EPICS))
|
||||
#endif
|
||||
|
||||
#if defined(_FORTIFY_SOURCE) && _FORTIFY_SOURCE>2
|
||||
OP_SYS_CPPFLAGS += -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2
|
||||
#endif
|
||||
|
||||
|
||||
@@ -18,6 +18,55 @@ should also be read to understand what has changed since earlier releases:
|
||||
- [pva2pva](https://epics-base.github.io/pva2pva/release_notes.html)
|
||||
- [pvaClient](https://github.com/epics-base/pvaClientCPP/blob/master/documentation/RELEASE_NOTES.md)
|
||||
|
||||
## EPICS Release 7.0.8.1
|
||||
|
||||
### Limit to `_FORTIFY_SOURCE=2`
|
||||
|
||||
GCC versions 12 and beyond and glibc have added some aggressive runtime
|
||||
checks for buffer overflows in libc functions at runtime, and the
|
||||
[Ubuntu 2024.04](https://wiki.ubuntu.com/ToolChain/CompilerFlags) release
|
||||
increased their default gcc fortification level from 2 to 3.
|
||||
This has started causing EPICS Base builds to fail on that version, and
|
||||
other OS releases may make that configuration change with similar results.
|
||||
This release detects a compiler configured with `_FORTIFY_SOURCE=3` and
|
||||
overrides it to 2.
|
||||
Later releases of Base will adjust the code, providing information to the
|
||||
compiler to avoid triggering these incorrect protections.
|
||||
|
||||
### Fix issue with compress record
|
||||
|
||||
In Base 7.0.8, an update to the compress record was added to allow for certain
|
||||
algorithms to use partially filled buffers in their computations. Unfortunately,
|
||||
this broke the behaviour of the records in certain cases. This has been fixed.
|
||||
|
||||
### Various minor changes
|
||||
|
||||
These included fixing minor memory leaks and documentation corrections. The
|
||||
`SIZV` field of lsi, lso and printf record VAL fields now can't exceed 32767
|
||||
characters, to match an internal limit.
|
||||
|
||||
### `epicsSocketAccept()` now returns `SOCKET`, not `int`
|
||||
|
||||
This might have some effect on downstream modules still using `int`, but the
|
||||
OS-specific osdSock.h headers which osiSock.h includes have all declared
|
||||
`SOCKET` (in most casese as a typedef for `int`) for many releases.
|
||||
This change removes a compiler warning on WIN32.
|
||||
Further details and the discussion about this change can be found
|
||||
[here](https://github.com/epics-base/epics-base/pull/458).
|
||||
|
||||
### `dbLoadRecords` allows macros with default values
|
||||
|
||||
Previously the parser assumed that files containing macro substitutions were
|
||||
bad if no macro definitions were provided; that assumption was made incorrect
|
||||
once macro substitutions were allowed to provide a default value.
|
||||
|
||||
### Hostname length limit in CA removed
|
||||
|
||||
Before this release, the CA client library only handled hostnames in address
|
||||
list environment variables up to 255 characters long.
|
||||
This limit has been removed.
|
||||
|
||||
-----
|
||||
|
||||
## EPICS Release 7.0.8
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
|
||||
<li>Tag the module:
|
||||
<blockquote><tt>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.8' <module-version>
|
||||
git tag -m 'ANJ: Tag for EPICS 7.0.8.1' <module-version>
|
||||
</tt></blockquote>
|
||||
</li>
|
||||
|
||||
@@ -269,7 +269,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td>Tag the epics-base module in Git:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.8
|
||||
git tag -m 'ANJ: Tagged for release' R7.0.8.1
|
||||
</tt></blockquote>
|
||||
<p>Don't push to GitHub yet.</p>
|
||||
</td>
|
||||
@@ -303,12 +303,12 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
files and directories that are only used for continuous integration:
|
||||
<blockquote><tt>
|
||||
cd base-7.0<br />
|
||||
./.tools/make-tar.sh R7.0.8 ../base-7.0.8.tar.gz base-7.0.8/
|
||||
./.tools/make-tar.sh R7.0.8.1 ../base-7.0.8.1.tar.gz base-7.0.8.1/
|
||||
</tt></blockquote>
|
||||
Create a GPG signature file of the tarfile as follows:
|
||||
<blockquote><tt>
|
||||
cd ..<br />
|
||||
gpg --armor --sign --detach-sig base-7.0.8.tar.gz
|
||||
gpg --armor --sign --detach-sig base-7.0.8.1.tar.gz
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -374,7 +374,7 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td>Upload the tar file and its <tt>.asc</tt> signature file to the
|
||||
epics-controls web-server.
|
||||
<blockquote><tt>
|
||||
scp base-7.0.8.tar.gz base-7.0.8.tar.gz.asc epics-controls:download/base<br />
|
||||
scp base-7.0.8.1.tar.gz base-7.0.8.1.tar.gz.asc epics-controls:download/base<br />
|
||||
</tt></blockquote>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -397,8 +397,8 @@ everything that has to be done since it's so easy to miss steps.</p>
|
||||
<td><input type="checkbox"></td>
|
||||
<td>Release Manager</td>
|
||||
<td>Go to the GitHub
|
||||
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8">
|
||||
Create release from tag R7.0.8</a> page.
|
||||
<a href="https://github.com/epics-base/epics-base/releases/new?tag=R7.0.8.1">
|
||||
Create release from tag R7.0.8.1</a> page.
|
||||
Upload the tar file and its <tt>.asc</tt> signature file to the new
|
||||
GitHub release page.</td>
|
||||
</tr>
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
|
||||
#define epicsAssertAuthor "Jeff Hill johill@lanl.gov"
|
||||
|
||||
#include <vector>
|
||||
#include <exception>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@@ -28,6 +31,7 @@
|
||||
|
||||
#include "envDefs.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsStdioRedirect.h"
|
||||
#include "errlog.h"
|
||||
#include "osiWireFormat.h"
|
||||
@@ -35,39 +39,6 @@
|
||||
#include "addrList.h"
|
||||
#include "iocinf.h"
|
||||
|
||||
/*
|
||||
* getToken()
|
||||
*/
|
||||
static char *getToken ( const char **ppString, char *pBuf, unsigned bufSIze )
|
||||
{
|
||||
bool tokenFound = false;
|
||||
const char *pToken;
|
||||
unsigned i;
|
||||
|
||||
pToken = *ppString;
|
||||
while ( isspace (*pToken) && *pToken ){
|
||||
pToken++;
|
||||
}
|
||||
|
||||
for ( i=0u; i<bufSIze; i++ ) {
|
||||
if ( isspace (pToken[i]) || pToken[i]=='\0' ) {
|
||||
pBuf[i] = '\0';
|
||||
*ppString = &pToken[i];
|
||||
if ( i != 0 ) {
|
||||
tokenFound = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
pBuf[i] = pToken[i];
|
||||
}
|
||||
|
||||
if ( tokenFound ) {
|
||||
pBuf[bufSIze-1] = '\0';
|
||||
return pBuf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* addAddrToChannelAccessAddressList ()
|
||||
*/
|
||||
@@ -77,9 +48,7 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
|
||||
{
|
||||
osiSockAddrNode *pNewNode;
|
||||
const char *pStr;
|
||||
const char *pToken;
|
||||
struct sockaddr_in addr;
|
||||
char buf[256u]; /* large enough to hold an IP address or hostname */
|
||||
int status, ret = -1;
|
||||
|
||||
pStr = envGetConfigParamPtr (pEnv);
|
||||
@@ -87,31 +56,45 @@ extern "C" int epicsStdCall addAddrToChannelAccessAddressList
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ( ( pToken = getToken (&pStr, buf, sizeof (buf) ) ) ) {
|
||||
status = aToIPAddr ( pToken, port, &addr );
|
||||
if (status<0) {
|
||||
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
|
||||
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
|
||||
continue;
|
||||
try {
|
||||
std::vector<char> scratch(pStr, pStr+strlen(pStr)+1); // copy chars and trailing nil
|
||||
|
||||
char *save = NULL;
|
||||
for(const char *pToken = epicsStrtok_r(&scratch[0], " \t\n\r", &save);
|
||||
pToken;
|
||||
pToken = epicsStrtok_r(NULL, " \t\n\r", &save))
|
||||
{
|
||||
if(!pToken[0]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
status = aToIPAddr ( pToken, port, &addr );
|
||||
if (status<0) {
|
||||
fprintf ( stderr, "%s: Parsing '%s'\n", __FILE__, pEnv->name);
|
||||
fprintf ( stderr, "\tBad internet address or host name: '%s'\n", pToken);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
}
|
||||
|
||||
if ( ignoreNonDefaultPort && ntohs ( addr.sin_port ) != port ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pNewNode = (osiSockAddrNode *) calloc (1, sizeof(*pNewNode));
|
||||
if (pNewNode==NULL) {
|
||||
fprintf ( stderr, "addAddrToChannelAccessAddressList(): no memory available for configuration\n");
|
||||
break;
|
||||
}
|
||||
|
||||
pNewNode->addr.ia = addr;
|
||||
|
||||
/*
|
||||
* LOCK applied externally
|
||||
*/
|
||||
ellAdd (pList, &pNewNode->node);
|
||||
ret = 0; /* success if anything is added to the list */
|
||||
} catch(std::exception&) { // only bad_alloc currently possible
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -225,6 +225,11 @@ static void asCaTask(void)
|
||||
if(asCaDebug) printf("asCaTask has cleared all channels\n");
|
||||
epicsEventSignal(asCaTaskWait);
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
cantProceed("Unreachable. Perpetual thread.");
|
||||
|
||||
taskwdRemove(0);
|
||||
}
|
||||
|
||||
void asCaStart(void)
|
||||
|
||||
@@ -118,6 +118,10 @@ typedef struct dbRecordNode {
|
||||
char *recordname;
|
||||
ELLLIST infoList; /*LIST head of info nodes*/
|
||||
int flags;
|
||||
/** Parse order of this record()
|
||||
* @since 7.0.8.1
|
||||
*/
|
||||
unsigned order;
|
||||
struct dbRecordNode *aliasedRecnode; /* NULL unless flags|DBRN_FLAGS_ISALIAS */
|
||||
}dbRecordNode;
|
||||
|
||||
@@ -184,5 +188,9 @@ typedef struct dbBase {
|
||||
struct gphPvt *pgpHash;
|
||||
short ignoreMissingMenus;
|
||||
short loadCdefs;
|
||||
/** Total number of records.
|
||||
* @since 7.0.8.1
|
||||
*/
|
||||
unsigned no_records;
|
||||
}dbBase;
|
||||
#endif
|
||||
|
||||
@@ -247,23 +247,23 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
}
|
||||
my_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
freeListInitPvt(&freeListPvt,sizeof(tempListNode),100);
|
||||
if(substitutions) {
|
||||
if(macCreateHandle(&macHandle,NULL)) {
|
||||
epicsPrintf("macCreateHandle error\n");
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
macParseDefns(macHandle,(char *)substitutions,&macPairs);
|
||||
if(macPairs ==NULL) {
|
||||
macDeleteHandle(macHandle);
|
||||
macHandle = NULL;
|
||||
} else {
|
||||
macInstallMacros(macHandle,macPairs);
|
||||
free((void *)macPairs);
|
||||
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
}
|
||||
macSuppressWarning(macHandle,dbQuietMacroWarnings);
|
||||
if (substitutions == NULL)
|
||||
substitutions = "";
|
||||
if(macCreateHandle(&macHandle,NULL)) {
|
||||
epicsPrintf("macCreateHandle error\n");
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
}
|
||||
macParseDefns(macHandle,substitutions,&macPairs);
|
||||
if(macPairs == NULL) {
|
||||
macDeleteHandle(macHandle);
|
||||
macHandle = NULL;
|
||||
} else {
|
||||
macInstallMacros(macHandle,macPairs);
|
||||
free(macPairs);
|
||||
mac_input_buffer = dbCalloc(MY_BUFFER_SIZE,sizeof(char));
|
||||
}
|
||||
macSuppressWarning(macHandle,dbQuietMacroWarnings);
|
||||
pinputFile = dbCalloc(1,sizeof(inputFile));
|
||||
if (filename) {
|
||||
pinputFile->filename = macEnvExpand(filename);
|
||||
|
||||
@@ -1445,6 +1445,7 @@ long dbCreateRecord(DBENTRY *pdbentry,const char *precordName)
|
||||
pdbentry->precnode = pNewRecNode;
|
||||
ppvd = dbPvdAdd(pdbentry->pdbbase,precordType,pNewRecNode);
|
||||
if(!ppvd) {errMessage(-1,"Logic Err: Could not add to PVD");return(-1);}
|
||||
pNewRecNode->order = pdbentry->pdbbase->no_records++;
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1686,6 +1687,7 @@ long dbCreateAlias(DBENTRY *pdbentry, const char *alias)
|
||||
}
|
||||
|
||||
ellAdd(&precordType->recList, &pnewnode->node);
|
||||
pnewnode->order = pdbentry->pdbbase->no_records++;
|
||||
precordType->no_aliases++;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -193,7 +193,7 @@ struct lset;
|
||||
struct link {
|
||||
struct dbCommon *precord; /* Pointer to record owning link */
|
||||
short type;
|
||||
short flags;
|
||||
unsigned short flags;
|
||||
struct lset *lset;
|
||||
char *text; /* Raw link text */
|
||||
union value value;
|
||||
|
||||
@@ -120,6 +120,11 @@ static void req_server (void *pParm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
cantProceed("Unreachable. Perpetual thread.");
|
||||
|
||||
taskwdRemove(0);
|
||||
}
|
||||
|
||||
static
|
||||
@@ -748,6 +753,7 @@ void rsrv_init (void)
|
||||
if(!havesometcp)
|
||||
cantProceed("CAS: No TCP server started\n");
|
||||
}
|
||||
free(socks);
|
||||
|
||||
/* servers list is considered read-only from this point */
|
||||
|
||||
|
||||
@@ -129,7 +129,11 @@ void rsrv_online_notify_task(void *pParm)
|
||||
}
|
||||
}
|
||||
|
||||
/* ATM never reached, just a placeholder */
|
||||
cantProceed("Unreachable. Perpetual thread.");
|
||||
|
||||
free(lastError);
|
||||
taskwdRemove(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1160,7 +1160,7 @@ See next section.
|
||||
|
||||
=head2 C<special>
|
||||
|
||||
This is called id CALC or OCAL is changed. C<special> calls postfix.
|
||||
This is called if CALC or OCAL is changed. C<special> calls postfix.
|
||||
|
||||
=head2 C<get_units>
|
||||
|
||||
|
||||
@@ -149,13 +149,16 @@ static int compare(const void *arg1, const void *arg2)
|
||||
else return 1;
|
||||
}
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
static int compress_array(compressRecord *prec,
|
||||
double *psource, int no_elements)
|
||||
{
|
||||
epicsInt32 i,j;
|
||||
epicsInt32 j;
|
||||
epicsInt32 n, nnew;
|
||||
epicsInt32 nsam = prec->nsam;
|
||||
double value;
|
||||
epicsUInt32 samples_written = 0;
|
||||
double value = 0.0;
|
||||
|
||||
/* skip out of limit data */
|
||||
if (prec->ilil < prec->ihil) {
|
||||
@@ -167,61 +170,54 @@ static int compress_array(compressRecord *prec,
|
||||
}
|
||||
if (prec->n <= 0)
|
||||
prec->n = 1;
|
||||
if (no_elements < prec->n && prec->pbuf != menuYesNoYES)
|
||||
return 1; /*dont do anything*/
|
||||
n = no_elements;
|
||||
n = prec->n;
|
||||
|
||||
/* determine number of samples to take */
|
||||
if (no_elements < nsam * n)
|
||||
nnew = (no_elements / n);
|
||||
else nnew = nsam;
|
||||
nnew = min(no_elements, nsam * n);
|
||||
|
||||
/* compress according to specified algorithm */
|
||||
switch (prec->alg){
|
||||
case compressALG_N_to_1_Low_Value:
|
||||
/* compress N to 1 keeping the lowest value */
|
||||
for (i = 0; i < nnew; i++) {
|
||||
while (nnew > 0)
|
||||
{
|
||||
if (nnew < n && prec->pbuf != menuYesNoYES)
|
||||
break;
|
||||
|
||||
n = min(n, nnew);
|
||||
switch (prec->alg)
|
||||
{
|
||||
case compressALG_N_to_1_Low_Value:
|
||||
value = *psource++;
|
||||
for (j = 1; j < n; j++, psource++) {
|
||||
for (j = 1; j < n; j++, psource++)
|
||||
{
|
||||
if (value > *psource)
|
||||
value = *psource;
|
||||
}
|
||||
put_value(prec, &value, 1);
|
||||
}
|
||||
break;
|
||||
case compressALG_N_to_1_High_Value:
|
||||
/* compress N to 1 keeping the highest value */
|
||||
for (i = 0; i < nnew; i++){
|
||||
break;
|
||||
case compressALG_N_to_1_High_Value:
|
||||
value = *psource++;
|
||||
for (j = 1; j < n; j++, psource++) {
|
||||
for (j = 1; j < n; j++, psource++)
|
||||
{
|
||||
if (value < *psource)
|
||||
value = *psource;
|
||||
}
|
||||
put_value(prec, &value, 1);
|
||||
}
|
||||
break;
|
||||
case compressALG_N_to_1_Average:
|
||||
/* compress N to 1 keeping the average value */
|
||||
for (i = 0; i < nnew; i++) {
|
||||
value = 0;
|
||||
for (j = 0; j < n; j++, psource++)
|
||||
break;
|
||||
case compressALG_N_to_1_Average:
|
||||
value = *psource++;
|
||||
for (j = 1; j < n; j++, psource++)
|
||||
{
|
||||
value += *psource;
|
||||
value /= n;
|
||||
put_value(prec, &value, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case compressALG_N_to_1_Median:
|
||||
/* compress N to 1 keeping the median value */
|
||||
/* note: sorts source array (OK; it's a work pointer) */
|
||||
for (i = 0; i < nnew; i++, psource += nnew) {
|
||||
}
|
||||
value = value / n;
|
||||
break;
|
||||
case compressALG_N_to_1_Median:
|
||||
/* note: sorts source array (OK; it's a work pointer) */
|
||||
qsort(psource, n, sizeof(double), compare);
|
||||
value = psource[n / 2];
|
||||
put_value(prec, &value, 1);
|
||||
psource += n;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
nnew -= n;
|
||||
put_value(prec, &value, 1);
|
||||
samples_written++;
|
||||
}
|
||||
return 0;
|
||||
return (samples_written == 0);
|
||||
}
|
||||
|
||||
static int array_average(compressRecord *prec,
|
||||
|
||||
@@ -91,10 +91,10 @@ The BPTR field contains a pointer to the unsigned long array of frequency
|
||||
values. The VAL field references this array as well. However, the BPTR field is
|
||||
not accessible at run-time.
|
||||
|
||||
The MCNT field keeps counts the number of signal counts since the last monitor
|
||||
The MCNT field keeps the number of signal counts since the last monitor
|
||||
was invoked.
|
||||
|
||||
The collections controls field (CMD) is a menu field with five choices:
|
||||
The collections controls field (CMD) is a menu field with four choices:
|
||||
|
||||
=menu histogramCMD
|
||||
|
||||
@@ -110,8 +110,6 @@ array. Unlike C<Read>, it doesn't clear the array first.
|
||||
|
||||
The C<Stop> command disables the reading of signal values into the array.
|
||||
|
||||
The C<Setup> command waits until the C<start> or C<read> command has been issued
|
||||
to start counting.
|
||||
|
||||
The CSTA or collections status field implements the CMD field choices by
|
||||
enabling or disabling the reading of values into the histogram array. While
|
||||
|
||||
@@ -49,6 +49,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (sizv < 16) {
|
||||
sizv = 16; /* Enforce a minimum size for the VAL field */
|
||||
prec->sizv = sizv;
|
||||
} else if (sizv > 0x7fff) {
|
||||
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
|
||||
prec->sizv = sizv;
|
||||
}
|
||||
|
||||
prec->val = callocMustSucceed(1, sizv, "lsi::init_record");
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
=title Long String Input Record (lsi)
|
||||
|
||||
The long string input record is used to retrieve an arbitrary ASCII string with
|
||||
a maximum length of 65535 characters.
|
||||
a maximum length of 32767 characters.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
@@ -36,7 +36,7 @@ from. It can be a database or channel access link, or a constant. If constant,
|
||||
the VAL field is initialized with the constant and can be changed via dbPuts.
|
||||
Otherwise, the string is read from the specified location each time the record
|
||||
is processed and placed in the VAL field. The maximum number of characters in
|
||||
VAL is given by SIZV, and cannot be larger than 65535. In addition, the
|
||||
VAL is given by SIZV, and cannot be larger than 32767. In addition, the
|
||||
appropriate device support module must be entered into the DTYP field.
|
||||
|
||||
=fields VAL, OVAL, SIZV, INP, DTYP
|
||||
|
||||
@@ -53,6 +53,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (sizv < 16) {
|
||||
sizv = 16; /* Enforce a minimum size for the VAL field */
|
||||
prec->sizv = sizv;
|
||||
} else if (sizv > 0x7fff) {
|
||||
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
|
||||
prec->sizv = sizv;
|
||||
}
|
||||
|
||||
prec->val = callocMustSucceed(1, sizv, "lso::init_record");
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
=title Long String Output Record (lso)
|
||||
|
||||
The long string output record is used to write an arbitrary ASCII string with a
|
||||
maximum length of 65535 characters.
|
||||
maximum length of 32767 characters.
|
||||
|
||||
This record type was included in base.dbd beginning with epics-base 3.15.0.2 .
|
||||
|
||||
@@ -41,7 +41,7 @@ C<supervisory> is specified, DOL is ignored, the current value of VAL is
|
||||
written, and VAL can be changed externally via dbPuts at run-time.
|
||||
|
||||
The maximum number of characters in VAL is given by SIZV, and cannot be larger
|
||||
than 65535.
|
||||
than 32767.
|
||||
|
||||
DOL can also be a constant instead of a link, in which case VAL is initialized
|
||||
to the constant value. Most simple string constants are likely to be interpreted
|
||||
|
||||
@@ -337,6 +337,9 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
if (sizv < 16) {
|
||||
sizv = 16; /* Enforce a minimum size for the VAL field */
|
||||
prec->sizv = sizv;
|
||||
} else if (sizv > 0x7fff) {
|
||||
sizv = 0x7fff; /* SIZV is unsigned, but dbAddr::field_size is signed */
|
||||
prec->sizv = sizv;
|
||||
}
|
||||
|
||||
prec->val = callocMustSucceed(1, sizv, "printf::init_record");
|
||||
|
||||
@@ -152,7 +152,7 @@ Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Dat
|
||||
for information on specifying links.
|
||||
|
||||
The formatted string is written to the VAL field. The maximum number of
|
||||
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
|
||||
characters in VAL is given by SIZV, and cannot be larger than 32767. The LEN
|
||||
field contains the length of the formatted string in the VAL field.
|
||||
|
||||
=fields FMT, INP0, INP1, INP2, INP3, INP4, INP5, INP6, INP7, INP8, INP9, VAL, SIZV, LEN
|
||||
|
||||
@@ -469,6 +469,38 @@ testNto1Average(void) {
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void testNto2Average(void) {
|
||||
DBADDR wfaddr, caddr;
|
||||
|
||||
testDiag("Test N to 1 Average, NSAM=2, N=2");
|
||||
|
||||
testdbPrepare();
|
||||
|
||||
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
|
||||
|
||||
recTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
|
||||
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=2");
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
fetchRecordOrDie("wf", wfaddr);
|
||||
fetchRecordOrDie("comp", caddr);
|
||||
|
||||
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
|
||||
|
||||
dbScanLock(caddr.precord);
|
||||
dbProcess(caddr.precord);
|
||||
|
||||
checkArrD("comp", 2, 1.5, 3.5, 0, 0);
|
||||
dbScanUnlock(caddr.precord);
|
||||
|
||||
testIocShutdownOk();
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
testNto1AveragePartial(void) {
|
||||
double buf = 0.0;
|
||||
@@ -517,6 +549,36 @@ testNto1AveragePartial(void) {
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
testNtoMPartial(void) {
|
||||
DBADDR wfaddr, caddr;
|
||||
|
||||
testDiag("Test Average, N to M, Partial");
|
||||
|
||||
testdbPrepare();
|
||||
testdbReadDatabase("recTestIoc.dbd", NULL, NULL);
|
||||
recTestIoc_registerRecordDeviceDriver(pdbbase);
|
||||
testdbReadDatabase("compressTest.db", NULL, "INP=wf,ALG=N to 1 Average,BALG=FIFO Buffer,NSAM=2,N=3,PBUF=YES");
|
||||
|
||||
eltc(0);
|
||||
testIocInitOk();
|
||||
eltc(1);
|
||||
|
||||
fetchRecordOrDie("wf", wfaddr);
|
||||
fetchRecordOrDie("comp", caddr);
|
||||
|
||||
writeToWaveform(&wfaddr, 4, 1., 2., 3., 4.);
|
||||
|
||||
dbScanLock(caddr.precord);
|
||||
dbProcess(caddr.precord);
|
||||
|
||||
checkArrD("comp", 2, 2.0, 4.0, 0, 0);
|
||||
dbScanUnlock(caddr.precord);
|
||||
|
||||
testIocShutdownOk();
|
||||
testdbCleanup();
|
||||
}
|
||||
|
||||
void
|
||||
testNto1LowValue(void) {
|
||||
double buf = 0.0;
|
||||
@@ -634,12 +696,14 @@ testAIAveragePartial(void) {
|
||||
|
||||
MAIN(compressTest)
|
||||
{
|
||||
testPlan(132);
|
||||
testPlan(134);
|
||||
testFIFOCirc();
|
||||
testLIFOCirc();
|
||||
testArrayAverage();
|
||||
testNto1Average();
|
||||
testNto2Average();
|
||||
testNto1AveragePartial();
|
||||
testNtoMPartial();
|
||||
testAIAveragePartial();
|
||||
testNto1LowValue();
|
||||
return testDone();
|
||||
|
||||
@@ -366,7 +366,7 @@ long epicsStdCall asAddClient(ASCLIENTPVT *pasClientPvt,ASMEMBERPVT asMemberPvt,
|
||||
{
|
||||
ASGMEMBER *pasgmember = asMemberPvt;
|
||||
ASGCLIENT *pasgclient;
|
||||
int len, i;
|
||||
size_t len, i;
|
||||
|
||||
long status;
|
||||
if(!asActive) return(S_asLib_asNotActive);
|
||||
@@ -394,7 +394,7 @@ long epicsStdCall asChangeClient(
|
||||
{
|
||||
ASGCLIENT *pasgclient = asClientPvt;
|
||||
long status;
|
||||
int len, i;
|
||||
size_t len, i;
|
||||
|
||||
if(!asActive) return(S_asLib_asNotActive);
|
||||
if(!pasgclient) return(S_asLib_badClient);
|
||||
|
||||
@@ -63,7 +63,7 @@ GPHENTRY * epicsStdCall gphFindParse(gphPvt *pgphPvt, const char *name, size_t l
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *gphlist;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
unsigned hash;
|
||||
|
||||
if (pgphPvt == NULL) return NULL;
|
||||
paplist = pgphPvt->paplist;
|
||||
@@ -99,7 +99,7 @@ GPHENTRY * epicsStdCall gphAdd(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
unsigned hash;
|
||||
|
||||
if (pgphPvt == NULL) return NULL;
|
||||
paplist = pgphPvt->paplist;
|
||||
@@ -144,7 +144,7 @@ void epicsStdCall gphDelete(gphPvt *pgphPvt, const char *name, void *pvtid)
|
||||
ELLLIST **paplist;
|
||||
ELLLIST *plist = NULL;
|
||||
GPHENTRY *pgphNode;
|
||||
int hash;
|
||||
unsigned hash;
|
||||
|
||||
if (pgphPvt == NULL) return;
|
||||
paplist = pgphPvt->paplist;
|
||||
|
||||
@@ -43,7 +43,7 @@ static char ioc_log_file_command[256];
|
||||
|
||||
|
||||
struct iocLogClient {
|
||||
int insock;
|
||||
SOCKET insock;
|
||||
struct ioc_log_server *pserver;
|
||||
size_t nChar;
|
||||
char recvbuf[1024];
|
||||
|
||||
@@ -15,40 +15,25 @@
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Up to now epicsShareThings have been declared as imports
|
||||
* (Appropriate for other stuff)
|
||||
* After setting the following they will be declared as exports
|
||||
* (Appropriate for what we implement)
|
||||
*/
|
||||
#include <epicsAssert.h>
|
||||
#include "adjustment.h"
|
||||
|
||||
LIBCOM_API size_t adjustToWorstCaseAlignment(size_t size)
|
||||
size_t adjustToWorstCaseAlignment(size_t size)
|
||||
{
|
||||
int align_size, adjust;
|
||||
struct test_long_word { char c; long lw; };
|
||||
struct test_double { char c; double d; };
|
||||
struct test_ptr { char c; void *p; };
|
||||
int test_long_size = sizeof(struct test_long_word) - sizeof(long);
|
||||
int test_double_size = sizeof(struct test_double) - sizeof(double);
|
||||
int test_ptr_size = sizeof(struct test_ptr) - sizeof(void *);
|
||||
size_t adjusted_size = size;
|
||||
union aline {
|
||||
/* largest primative types (so far...) */
|
||||
double dval;
|
||||
size_t uval;
|
||||
char *ptr;
|
||||
};
|
||||
|
||||
/*
|
||||
* Use Jeff's alignment tests to determine worst case of long,
|
||||
* double or pointer alignment requirements.
|
||||
*/
|
||||
align_size = test_long_size > test_ptr_size ?
|
||||
test_long_size : test_ptr_size;
|
||||
/* assert that alignment size is a power of 2 */
|
||||
STATIC_ASSERT((sizeof(union aline) & (sizeof(union aline)-1))==0);
|
||||
|
||||
align_size = align_size > test_double_size ?
|
||||
align_size : test_double_size;
|
||||
/* round up to aligment size */
|
||||
size--;
|
||||
size |= sizeof(union aline)-1;
|
||||
size++;
|
||||
|
||||
/*
|
||||
* Increase the size to fit worst case alignment if not already
|
||||
* properly aligned.
|
||||
*/
|
||||
adjust = align_size - size%align_size;
|
||||
if (adjust != align_size) adjusted_size += adjust;
|
||||
|
||||
return (adjusted_size);
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <climits>
|
||||
#include <stdexcept>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
//#define EPICS_FREELIST_DEBUG
|
||||
#define EPICS_PRIVATE_API
|
||||
@@ -82,7 +83,6 @@ struct ipAddrToAsciiGlobal : public epicsThreadRunable {
|
||||
|
||||
virtual void run ();
|
||||
|
||||
char nameTmp [1024];
|
||||
tsFreeList
|
||||
< ipAddrToAsciiTransactionPrivate, 0x80 >
|
||||
transactionFreeList;
|
||||
@@ -297,6 +297,8 @@ ipAddrToAsciiTransaction & ipAddrToAsciiEnginePrivate::createTransaction ()
|
||||
|
||||
void ipAddrToAsciiGlobal::run ()
|
||||
{
|
||||
std::vector<char> nameTmp(1024);
|
||||
|
||||
epicsGuard < epicsMutex > guard ( this->mutex );
|
||||
while ( ! this->exitFlag ) {
|
||||
{
|
||||
@@ -313,14 +315,13 @@ void ipAddrToAsciiGlobal::run ()
|
||||
|
||||
if ( this->exitFlag )
|
||||
{
|
||||
sockAddrToDottedIP ( & addr.sa, this->nameTmp,
|
||||
sizeof ( this->nameTmp ) );
|
||||
sockAddrToDottedIP ( & addr.sa, &nameTmp[0], nameTmp.size() );
|
||||
}
|
||||
else {
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// depending on DNS configuration, this could take a very long time
|
||||
// so we release the lock
|
||||
sockAddrToA ( &addr.sa, this->nameTmp, sizeof ( this->nameTmp ) );
|
||||
sockAddrToA ( &addr.sa, &nameTmp[0], nameTmp.size() );
|
||||
}
|
||||
|
||||
// the ipAddrToAsciiTransactionPrivate destructor is allowed to
|
||||
@@ -339,7 +340,7 @@ void ipAddrToAsciiGlobal::run ()
|
||||
{
|
||||
epicsGuardRelease < epicsMutex > unguard ( guard );
|
||||
// don't call callback with lock applied
|
||||
pCur->pCB->transactionComplete ( this->nameTmp );
|
||||
pCur->pCB->transactionComplete ( &nameTmp[0] );
|
||||
}
|
||||
|
||||
this->callbackInProgress = false;
|
||||
|
||||
@@ -119,8 +119,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate (
|
||||
return socket ( domain, type, protocol );
|
||||
}
|
||||
|
||||
LIBCOM_API int epicsStdCall epicsSocketAccept (
|
||||
int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen )
|
||||
LIBCOM_API SOCKET epicsStdCall epicsSocketAccept (
|
||||
SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen )
|
||||
{
|
||||
return accept ( sock, pAddr, addrlen );
|
||||
}
|
||||
|
||||
@@ -500,8 +500,6 @@ static unsigned WINAPI epicsWin32ThreadEntry ( LPVOID lpParameter )
|
||||
BOOL success;
|
||||
|
||||
if ( pGbl ) {
|
||||
setThreadName ( pParm->id, pParm->pName );
|
||||
|
||||
success = FlsSetValue ( pGbl->flsIndexThreadLibraryEPICS, pParm );
|
||||
if ( success ) {
|
||||
osdThreadHooksRun ( ( epicsThreadId ) pParm );
|
||||
@@ -659,6 +657,7 @@ epicsThreadId epicsThreadCreateOpt (
|
||||
pParmWIN32->id = ( DWORD ) threadId ;
|
||||
}
|
||||
|
||||
setThreadName ( pParmWIN32->id, pParmWIN32->pName );
|
||||
osdPriority = epicsThreadGetOsdPriorityValue (opts->priority);
|
||||
bstat = SetThreadPriority ( pParmWIN32->handle, osdPriority );
|
||||
if (!bstat) {
|
||||
|
||||
@@ -215,6 +215,7 @@ void currentTime :: startPLL ()
|
||||
CREATE_SUSPENDED | STACK_SIZE_PARAM_IS_A_RESERVATION,
|
||||
& this->threadId );
|
||||
assert ( this->threadHandle );
|
||||
setThreadName ( this->threadId, "EPICS Time PLL" );
|
||||
BOOL bstat = SetThreadPriority (
|
||||
this->threadHandle, THREAD_PRIORITY_HIGHEST );
|
||||
assert ( bstat );
|
||||
@@ -496,7 +497,6 @@ static unsigned __stdcall _pllThreadEntry ( void * pCurrentTimeIn )
|
||||
{
|
||||
currentTime * pCT =
|
||||
reinterpret_cast < currentTime * > ( pCurrentTimeIn );
|
||||
setThreadName ( pCT->threadId, "EPICS Time PLL" );
|
||||
while ( ! pCT->threadShutdownCmd ) {
|
||||
Sleep ( currentTime :: pllDelay * 1000 /* mS */ );
|
||||
pCT->updatePLL ();
|
||||
|
||||
@@ -40,7 +40,16 @@ struct threadNode {
|
||||
struct eventNode *evp;
|
||||
void *buf;
|
||||
unsigned int size;
|
||||
volatile bool eventSent;
|
||||
bool eventSent;
|
||||
inline
|
||||
threadNode()
|
||||
:evp(NULL)
|
||||
,buf(NULL)
|
||||
,size(0u)
|
||||
,eventSent(false)
|
||||
{
|
||||
memset(&link, 0, sizeof(link));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -366,9 +375,10 @@ myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size,
|
||||
|
||||
freeEventNode(pmsg, threadNode.evp, status);
|
||||
|
||||
bool wasSent = threadNode.eventSent;
|
||||
epicsMutexUnlock(pmsg->mutex);
|
||||
|
||||
if (threadNode.eventSent && (threadNode.size <= size))
|
||||
if (wasSent && (threadNode.size <= size))
|
||||
return threadNode.size;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "osiSock.h"
|
||||
#include "epicsAssert.h"
|
||||
#include "errlog.h"
|
||||
#include "epicsAtomic.h"
|
||||
|
||||
/* Linux and *BSD (at least) specific way to atomically set O_CLOEXEC.
|
||||
* RTEMS 5.1 provides SOCK_CLOEXEC, but doesn't implement accept4()
|
||||
@@ -60,19 +61,18 @@ static void unlockInfo (void)
|
||||
epicsMutexUnlock (infoMutex);
|
||||
}
|
||||
|
||||
/*
|
||||
* NOOP
|
||||
*/
|
||||
|
||||
static size_t nAttached;
|
||||
|
||||
int osiSockAttach()
|
||||
{
|
||||
epicsAtomicIncrSizeT(&nAttached);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOOP
|
||||
*/
|
||||
void osiSockRelease()
|
||||
{
|
||||
epicsAtomicDecrSizeT(&nAttached);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -83,6 +83,11 @@ void osiSockRelease()
|
||||
LIBCOM_API SOCKET epicsStdCall epicsSocketCreate (
|
||||
int domain, int type, int protocol )
|
||||
{
|
||||
static unsigned char warnAttached;
|
||||
if(!epicsAtomicGetSizeT(&nAttached) && !warnAttached) {
|
||||
warnAttached = 1;
|
||||
errlogPrintf(ERL_WARNING ": epicsSocketCreate() without osiSockAttach() is not portable\n");
|
||||
}
|
||||
SOCKET sock = socket ( domain, type | SOCK_CLOEXEC, protocol );
|
||||
if ( sock < 0 ) {
|
||||
sock = INVALID_SOCKET;
|
||||
@@ -119,8 +124,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate (
|
||||
return sock;
|
||||
}
|
||||
|
||||
LIBCOM_API int epicsStdCall epicsSocketAccept (
|
||||
int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen )
|
||||
LIBCOM_API SOCKET epicsStdCall epicsSocketAccept (
|
||||
SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen )
|
||||
{
|
||||
#ifndef HAVE_SOCK_CLOEXEC
|
||||
int newSock = accept ( sock, pAddr, addrlen );
|
||||
|
||||
@@ -44,8 +44,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate (
|
||||
return sock;
|
||||
}
|
||||
|
||||
LIBCOM_API int epicsStdCall epicsSocketAccept (
|
||||
int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen )
|
||||
LIBCOM_API SOCKET epicsStdCall epicsSocketAccept (
|
||||
SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen )
|
||||
{
|
||||
int newSock = accept ( sock, pAddr, addrlen );
|
||||
if ( newSock < 0 ) {
|
||||
|
||||
@@ -63,8 +63,8 @@ LIBCOM_API SOCKET epicsStdCall epicsSocketCreate (
|
||||
* peer address.
|
||||
* \return A new socket used for communicating with the peer just accepted, or -1 on error.
|
||||
*/
|
||||
LIBCOM_API int epicsStdCall epicsSocketAccept (
|
||||
int sock, struct sockaddr * pAddr, osiSocklen_t * addrlen );
|
||||
LIBCOM_API SOCKET epicsStdCall epicsSocketAccept (
|
||||
SOCKET sock, struct sockaddr * pAddr, osiSocklen_t * addrlen );
|
||||
/*!
|
||||
* \brief Close and free resources held by a SOCKET object.
|
||||
*
|
||||
|
||||
@@ -60,11 +60,11 @@ void test_gmtime(time_t T, int sec, int min, int hour,
|
||||
struct tm B;
|
||||
testDiag("test_gmtime(%ld, ...)", (long)T);
|
||||
if(epicsTime_gmtime(&T, &B)!=epicsTimeOK) {
|
||||
testFail("epicsTime_localtime() error");
|
||||
testSkip(9, "epicsTime_localtime() failed");
|
||||
testFail("epicsTime_gmtime() error");
|
||||
testSkip(9, "epicsTime_gmtime() failed");
|
||||
} else {
|
||||
B.tm_year += 1900; /* for readability */
|
||||
testPass("epicsTime_localtime() success");
|
||||
testPass("epicsTime_gmtime() success");
|
||||
#define TEST(FLD) testOk(B.tm_##FLD==FLD, "%s %d==%d", #FLD, B.tm_##FLD, FLD)
|
||||
TEST(sec);
|
||||
TEST(min);
|
||||
|
||||
@@ -57,6 +57,9 @@ foreach my $source (@ARGV) {
|
||||
my $temp = "$install_dir/TEMP.$name.$$";
|
||||
my $target = "$install_dir/$name";
|
||||
|
||||
# Don't try to install the file if it already exists
|
||||
next if $source eq $target;
|
||||
|
||||
if (-f $target) {
|
||||
next if -M $target < -M $source and -C $target < -C $source;
|
||||
# Remove old target, making sure it is deletable first
|
||||
|
||||
Reference in New Issue
Block a user