diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD
index c3638c711..2be4b338a 100644
--- a/configure/RULES_BUILD
+++ b/configure/RULES_BUILD
@@ -105,13 +105,17 @@ endif
PRODTARGETS += $(PRODNAME) $(MUNCHNAME) $(CTDT_SRCS) $(CTDT_OBJS) $(NMS)
#---------------------------------------------------------------
-# Generate a test specification if any tests are defined.
+# Test specifications and test result files
#
ifneq (,$(strip $(TESTS)))
TARGETS += testspec
endif
+# Enable testing if this host can run tests on the current target
+ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
+RUNTESTS_ENABLED = YES
TAPFILES += $(TESTSCRIPTS:.t=.tap)
+endif
#---------------------------------------------------------------
# Libraries
@@ -324,7 +328,7 @@ $(MODNAME): %$(MODEXT): %$(EXE)
# Automated testing
runtests: $(TESTSCRIPTS)
-ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
+ifdef RUNTESTS_ENABLED
-$(PERL) -MTest::Harness -e 'runtests @ARGV if @ARGV;' $^
endif
@@ -340,7 +344,7 @@ tapfiles: $(TESTSCRIPTS) $(TAPFILES)
# A .tap file is the output from running the associated test script
%.tap: %.t
-ifneq (,$(findstring $(T_A),$(EPICS_HOST_ARCH) $(CROSS_COMPILER_RUNTEST_ARCHS)))
+ifdef RUNTESTS_ENABLED
-$(PERL) $< -tap > $@
endif
diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86
index f9bb0b9cb..6c6f21a61 100644
--- a/configure/os/CONFIG.win32-x86.win32-x86
+++ b/configure/os/CONFIG.win32-x86.win32-x86
@@ -10,6 +10,8 @@ VALID_BUILDS = Host Ioc
CMPLR_CLASS = msvc
+OPT_WHOLE_PROGRAM = YES
+
#-------------------------------------------------------
WINLINK = link
@@ -42,11 +44,13 @@ WARN_CFLAGS_NO = -W1
# -Ox maximum optimizations
# -GL whole program optimization
# -Oy- re-enable creation of frame pointers
-OPT_CFLAGS_YES = -Ox -GL -Oy-
+OPT_CFLAGS_YES_YES = -Ox -GL -Oy-
+OPT_CFLAGS_YES_NO = -Ox -Oy-
+OPT_CFLAGS_YES = $(OPT_CFLAGS_YES_$(OPT_WHOLE_PROGRAM))
#
# -Zi generate program database for debugging information
-# -RTCsu catch bugs occuring only inoptimized code
+# -RTCsu enable run-time error checks
OPT_CFLAGS_NO = -Zi -RTCsu
# specify object file name and location
@@ -96,17 +100,19 @@ CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE
# -w44355 set "'this' used in the base initializer list" to be level 4
# -w44344 "behavior change: use of explicit template arguments results in ..."
WARN_CXXFLAGS_YES = -W3 -w44355 -w44344
-WARN_CXXFLAGS_NO = -W1
+WARN_CXXFLAGS_NO = -W1
#
# -Ox maximum optimizations
# -GL whole program optimization
# -Oy- re-enable creation of frame pointers
-OPT_CXXFLAGS_YES = -Ox -GL -Oy-
+OPT_CXXFLAGS_YES_YES = -Ox -GL -Oy-
+OPT_CXXFLAGS_YES_NO = -Ox -Oy-
+OPT_CXXFLAGS_YES = $(OPT_CXXFLAGS_YES_$(OPT_WHOLE_PROGRAM))
#
# -Zi generate program database for debugging information
-# -RTCsu catch bugs occurring only in optimized code
+# -RTCsu enable run-time error checks
OPT_CXXFLAGS_NO = -RTCsu -Zi
# specify object file name and location
@@ -136,11 +142,14 @@ RANLIB=
# -fixed:no generate relocatable code
# -version:
Dynamic array sizing support was added to the IOC server (RSRV) in the
+Base-3.14.12 release, but has not until now been supported in the Portable
+Channel Access Server
(PCAS). Channel Access server applications using the
+PCAS may not need to be modified at all; if they already push monitors with
+different gdd array lengths, those variable sizes will be forwarded to any CA
+clients who have requested variable length updates. The example CAS server
+application has been modified to demonstrate this feature.
In implementing the above, the gdd method gdd::put(const gdd *) now +copies the full-sized array from the source gdd if the destination gdd is of +type array, has no allocated memory and a boundary size of 0.
+ +The EPICS timestamp library (epicsTime) inside libCom's OSI layer has +been extended by routines that convert from struct tm to the EPICS +internal epicsTime type, assuming UTC - i.e. without going through +the timezone mechanism. This solves issues with converting from the structured +type to the EPICS timestamp at driver level from multiple threads at a high +repetition rate, where the timezone mechanism was blocking on file access.
+The build configuration files that allow cross-building of the 32-bit
diff --git a/src/ca/client/cac.cpp b/src/ca/client/cac.cpp
index d66cf9dad..d1afe6785 100644
--- a/src/ca/client/cac.cpp
+++ b/src/ca/client/cac.cpp
@@ -149,9 +149,9 @@ cac::cac (
iiuExistenceCount ( 0u ),
cacShutdownInProgress ( false )
{
- if ( ! osiSockAttach () ) {
- throwWithLocation ( caErrorCode (ECA_INTERNAL) );
- }
+ if ( ! osiSockAttach () ) {
+ throwWithLocation ( udpiiu :: noSocket () );
+ }
try {
long status;
diff --git a/src/ca/client/iocinf.h b/src/ca/client/iocinf.h
index c0c33d6c2..0d3b57db1 100644
--- a/src/ca/client/iocinf.h
+++ b/src/ca/client/iocinf.h
@@ -61,11 +61,6 @@ static const double CA_CONN_VERIFY_PERIOD = 30.0; /* (sec) how often to request
*/
static const unsigned contiguousMsgCountWhichTriggersFlowControl = 10u;
-class caErrorCode {
-public:
- caErrorCode ( int ) {};
-};
-
/*
* CA internal functions
*/
diff --git a/src/ca/client/tcpiiu.cpp b/src/ca/client/tcpiiu.cpp
index 58b1b0c0f..7fd848b20 100644
--- a/src/ca/client/tcpiiu.cpp
+++ b/src/ca/client/tcpiiu.cpp
@@ -44,12 +44,7 @@
using namespace std;
-#if 0
-const unsigned mSecPerSec = 1000u;
-const unsigned uSecPerSec = 1000u * mSecPerSec;
-#endif
-
-tcpSendThread::tcpSendThread (
+tcpSendThread::tcpSendThread (
class tcpiiu & iiuIn, const char * pName,
unsigned stackSize, unsigned priority ) :
thread ( *this, pName, stackSize, priority ), iiu ( iiuIn )
@@ -807,28 +802,6 @@ tcpiiu::tcpiiu (
}
}
-# if 0
- //
- // windows has a really strange implementation of thess options
- // and we can avoid the need for this by using pthread_kill on unix
- //
- {
- struct timeval timeout;
- double pollInterval = connectionTimeout / 8.0;
- timeout.tv_sec = static_cast < long > ( pollInterval );
- timeout.tv_usec = static_cast < long >
- ( ( pollInterval - timeout.tv_sec ) * uSecPerSec );
- // intentionally ignore status as we dont expect that all systems
- // will accept this request
- setsockopt ( this->sock, SOL_SOCKET, SO_SNDTIMEO,
- ( char * ) & timeout, sizeof ( timeout ) );
- // intentionally ignore status as we dont expect that all systems
- // will accept this request
- setsockopt ( this->sock, SOL_SOCKET, SO_RCVTIMEO,
- ( char * ) & timeout, sizeof ( timeout ) );
- }
-# endif
-
if ( isNameService() ) {
pSearchDest->setCircuit ( this );
}
diff --git a/src/ca/legacy/gdd/gdd.cc b/src/ca/legacy/gdd/gdd.cc
index fd2b662c9..acb53da4e 100644
--- a/src/ca/legacy/gdd/gdd.cc
+++ b/src/ca/legacy/gdd/gdd.cc
@@ -1355,8 +1355,9 @@ gddStatus gdd::put ( const gdd * dd )
}
aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow;
- if ( srcAvailSize > this->getBounds()->size() ) {
- srcCopySize = this->getBounds()->size();
+ aitUint32 destSize = this->getBounds()->size();
+ if ( destSize > 0 && srcAvailSize > destSize ) {
+ srcCopySize = destSize;
}
else {
srcCopySize = srcAvailSize;
diff --git a/src/ca/legacy/pcas/generic/caHdrLargeArray.h b/src/ca/legacy/pcas/generic/caHdrLargeArray.h
index 89b0d6d4b..7bda002e9 100644
--- a/src/ca/legacy/pcas/generic/caHdrLargeArray.h
+++ b/src/ca/legacy/pcas/generic/caHdrLargeArray.h
@@ -30,7 +30,7 @@
# include "shareLib.h"
#endif
-static const unsigned char CA_MINOR_PROTOCOL_REVISION = 12;
+static const unsigned char CA_MINOR_PROTOCOL_REVISION = 13;
typedef ca_uint32_t caResId;
diff --git a/src/ca/legacy/pcas/generic/caServerI.h b/src/ca/legacy/pcas/generic/caServerI.h
index 344f6393b..012233693 100644
--- a/src/ca/legacy/pcas/generic/caServerI.h
+++ b/src/ca/legacy/pcas/generic/caServerI.h
@@ -40,8 +40,13 @@ class casIntfOS;
class casMonitor;
class casChannelI;
-caStatus convertContainerMemberToAtomic ( class gdd & dd,
- aitUint32 appType, aitUint32 elemCount );
+caStatus convertContainerMemberToAtomic (class gdd & dd,
+ aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount);
+
+// Keep the old signature for backward compatibility
+inline caStatus convertContainerMemberToAtomic (class gdd & dd,
+ aitUint32 appType, aitUint32 elemCount)
+{ return convertContainerMemberToAtomic(dd, appType, elemCount, elemCount); }
class caServerI :
public caServerIO,
diff --git a/src/ca/legacy/pcas/generic/casCtx.h b/src/ca/legacy/pcas/generic/casCtx.h
index 706376e77..eab644685 100644
--- a/src/ca/legacy/pcas/generic/casCtx.h
+++ b/src/ca/legacy/pcas/generic/casCtx.h
@@ -18,6 +18,8 @@
#include "caHdrLargeArray.h"
+class casStrmClient;
+
class casCtx {
public:
casCtx();
@@ -41,6 +43,7 @@ private:
casChannelI * pChannel;
casPVI * pPV;
unsigned nAsyncIO; // checks for improper use of async io
+ friend class casStrmClient;
};
inline const caHdrLargeArray * casCtx::getMsg() const
diff --git a/src/ca/legacy/pcas/generic/casStrmClient.cc b/src/ca/legacy/pcas/generic/casStrmClient.cc
index 6b1de3629..8db94adb3 100644
--- a/src/ca/legacy/pcas/generic/casStrmClient.cc
+++ b/src/ca/legacy/pcas/generic/casStrmClient.cc
@@ -388,14 +388,12 @@ caStatus casStrmClient::echoAction ( epicsGuard < casClientMutex > & )
//
// casStrmClient::verifyRequest()
//
-caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
+caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn)
{
- const caHdrLargeArray * mp = this->ctx.getMsg();
-
//
// channel exists for this resource id ?
//
- chronIntId tmpId ( mp->m_cid );
+ chronIntId tmpId ( ctx.msg.m_cid );
pChan = this->chanTable.lookup ( tmpId );
if ( ! pChan ) {
return ECA_BADCHID;
@@ -404,14 +402,15 @@ caStatus casStrmClient::verifyRequest ( casChannelI * & pChan )
//
// data type out of range ?
//
- if ( mp->m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
+ if ( ctx.msg.m_dataType > ((unsigned)LAST_BUFFER_TYPE) ) {
return ECA_BADTYPE;
}
//
// element count out of range ?
//
- if ( mp->m_count > pChan->getPVI().nativeCount() || mp->m_count == 0u ) {
+ if ( ctx.msg.m_count > pChan->getPVI().nativeCount() ||
+ ( !allowdyn && ctx.msg.m_count == 0u ) ) {
return ECA_BADCOUNT;
}
@@ -444,7 +443,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard )
casChannelI * pChan;
{
- caStatus status = this->verifyRequest ( pChan );
+ caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pChan ) {
return this->sendErr ( guard, mp, pChan->getCID(),
@@ -531,11 +530,15 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
pChan->getCID(), status, ECA_GETFAIL );
}
+ ca_uint32_t count = (msg.m_count == 0) ?
+ (ca_uint32_t)desc.getDataSizeElements() :
+ msg.m_count;
+
void * pPayload;
{
- unsigned payloadSize = dbr_size_n ( msg.m_dataType, msg.m_count );
+ unsigned payloadSize = dbr_size_n ( msg.m_dataType, count );
caStatus localStatus = this->out.copyInHeader ( msg.m_cmmd, payloadSize,
- msg.m_dataType, msg.m_count, pChan->getCID (),
+ msg.m_dataType, count, pChan->getCID (),
msg.m_available, & pPayload );
if ( localStatus ) {
if ( localStatus==S_cas_hugeRequest ) {
@@ -551,21 +554,21 @@ caStatus casStrmClient::readResponse ( epicsGuard < casClientMutex > & guard,
// (places the data in network format)
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr(
- pPayload, msg.m_count, desc, pChan->enumStringTable() );
+ pPayload, count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump ();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__, "- get with PV=%s type=%u count=%u",
- pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
+ pChan->getPVI().getName(), msg.m_dataType, count );
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_badBounds, ECA_GETFAIL );
}
int cacStatus = caNetConvert (
- msg.m_dataType, pPayload, pPayload, true, msg.m_count );
+ msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
- if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
+ if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -585,7 +588,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard
casChannelI * pChan;
{
- caStatus status = this->verifyRequest ( pChan );
+ caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
return this->readNotifyFailureResponse ( guard, * mp, status );
}
@@ -656,11 +659,15 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
return ecaStatus;
}
+ ca_uint32_t count = (msg.m_count == 0) ?
+ (ca_uint32_t)desc.getDataSizeElements() :
+ msg.m_count;
+
void *pPayload;
{
- unsigned size = dbr_size_n ( msg.m_dataType, msg.m_count );
+ unsigned size = dbr_size_n ( msg.m_dataType, count );
caStatus status = this->out.copyInHeader ( msg.m_cmmd, size,
- msg.m_dataType, msg.m_count, ECA_NORMAL,
+ msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@@ -675,23 +682,23 @@ caStatus casStrmClient::readNotifyResponse ( epicsGuard < casClientMutex > & gua
// convert gdd to db_access type
//
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr ( pPayload,
- msg.m_count, desc, pChan->enumStringTable() );
+ count, desc, pChan->enumStringTable() );
if ( mapDBRStatus < 0 ) {
desc.dump();
errPrintf ( S_cas_badBounds, __FILE__, __LINE__,
"- get notify with PV=%s type=%u count=%u",
- pChan->getPVI().getName(), msg.m_dataType, msg.m_count );
+ pChan->getPVI().getName(), msg.m_dataType, count );
return this->readNotifyFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
- msg.m_dataType, pPayload, pPayload, true, msg.m_count );
+ msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
return this->sendErrWithEpicsStatus (
guard, & msg, pChan->getCID(), S_cas_internal, cacStatus );
}
- if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
+ if ( msg.m_dataType == DBR_STRING && count == 1u ) {
unsigned reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -727,8 +734,8 @@ caStatus casStrmClient::readNotifyFailureResponse (
// to be more efficent if it discovers that the source has less data
// than the destination)
//
-caStatus convertContainerMemberToAtomic ( gdd & dd,
- aitUint32 appType, aitUint32 elemCount )
+caStatus convertContainerMemberToAtomic ( gdd & dd,
+ aitUint32 appType, aitUint32 requestedCount, aitUint32 nativeCount )
{
gdd * pVal;
if ( dd.isContainer() ) {
@@ -755,13 +762,13 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
return S_cas_badType;
}
- if ( elemCount <= 1 ) {
+ if ( nativeCount <= 1 ) {
return S_cas_success;
}
// convert to atomic
gddBounds bds;
- bds.setSize ( elemCount );
+ bds.setSize ( requestedCount );
bds.setFirst ( 0u );
pVal->setDimension ( 1u, & bds );
return S_cas_success;
@@ -770,9 +777,9 @@ caStatus convertContainerMemberToAtomic ( gdd & dd,
//
// createDBRDD ()
//
-static caStatus createDBRDD ( unsigned dbrType,
- unsigned elemCount, gdd * & pDD )
-{
+static caStatus createDBRDD ( unsigned dbrType,
+ unsigned requestedCount, unsigned nativeCount, gdd * & pDD )
+{
/*
* DBR type has already been checked, but it is possible
* that "gddDbrToAit" will not track with changes in
@@ -799,7 +806,7 @@ static caStatus createDBRDD ( unsigned dbrType,
// fix the value element count
caStatus status = convertContainerMemberToAtomic (
- *pDescRet, gddAppType_value, elemCount );
+ *pDescRet, gddAppType_value, requestedCount, nativeCount );
if ( status != S_cas_success ) {
pDescRet->unreference ();
return status;
@@ -849,11 +856,15 @@ caStatus casStrmClient::monitorResponse (
casChannelI & chan, const caHdrLargeArray & msg,
const gdd & desc, const caStatus completionStatus )
{
+ ca_uint32_t count = (msg.m_count == 0) ?
+ (ca_uint32_t)desc.getDataSizeElements() :
+ msg.m_count;
+
void * pPayload = 0;
{
- ca_uint32_t size = dbr_size_n ( msg.m_dataType, msg.m_count );
+ ca_uint32_t size = dbr_size_n ( msg.m_dataType, count );
caStatus status = out.copyInHeader ( msg.m_cmmd, size,
- msg.m_dataType, msg.m_count, ECA_NORMAL,
+ msg.m_dataType, count, ECA_NORMAL,
msg.m_available, & pPayload );
if ( status ) {
if ( status == S_cas_hugeRequest ) {
@@ -871,7 +882,8 @@ caStatus casStrmClient::monitorResponse (
gdd * pDBRDD = 0;
if ( completionStatus == S_cas_success ) {
- caStatus status = createDBRDD ( msg.m_dataType, msg.m_count, pDBRDD );
+ caStatus status = createDBRDD ( msg.m_dataType, count,
+ chan.getPVI().nativeCount(), pDBRDD );
if ( status != S_cas_success ) {
caStatus ecaStatus;
if ( status == S_cas_badType ) {
@@ -892,7 +904,7 @@ caStatus casStrmClient::monitorResponse (
pDBRDD->unreference ();
errPrintf ( S_cas_noConvert, __FILE__, __LINE__,
"no conversion between event app type=%d and DBR type=%d Element count=%d",
- desc.applicationType (), msg.m_dataType, msg.m_count);
+ desc.applicationType (), msg.m_dataType, count);
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
}
@@ -915,14 +927,14 @@ caStatus casStrmClient::monitorResponse (
}
int mapDBRStatus = gddMapDbr[msg.m_dataType].conv_dbr (
- pPayload, msg.m_count, *pDBRDD, chan.enumStringTable() );
+ pPayload, count, *pDBRDD, chan.enumStringTable() );
if ( mapDBRStatus < 0 ) {
pDBRDD->unreference ();
return monitorFailureResponse ( guard, msg, ECA_NOCONVERT );
}
int cacStatus = caNetConvert (
- msg.m_dataType, pPayload, pPayload, true, msg.m_count );
+ msg.m_dataType, pPayload, pPayload, true, count );
if ( cacStatus != ECA_NORMAL ) {
pDBRDD->unreference ();
return this->sendErrWithEpicsStatus (
@@ -932,7 +944,7 @@ caStatus casStrmClient::monitorResponse (
//
// force string message size to be the true size
//
- if ( msg.m_dataType == DBR_STRING && msg.m_count == 1u ) {
+ if ( msg.m_dataType == DBR_STRING && count == 1u ) {
ca_uint32_t reducedPayloadSize = strlen ( static_cast < char * > ( pPayload ) ) + 1u;
this->out.commitMsg ( reducedPayloadSize );
}
@@ -1940,7 +1952,7 @@ caStatus casStrmClient::eventAddAction (
casChannelI *pciu;
{
- caStatus status = casStrmClient::verifyRequest ( pciu );
+ caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) );
if ( status != ECA_NORMAL ) {
if ( pciu ) {
return this->sendErr ( guard, mp,
@@ -2601,8 +2613,8 @@ caStatus casStrmClient::read ()
{
gdd * pDD = 0;
- caStatus status = createDBRDD ( pHdr->m_dataType,
- pHdr->m_count, pDD );
+ caStatus status = createDBRDD ( pHdr->m_dataType, pHdr->m_count,
+ this->ctx.getChannel()->getPVI().nativeCount(), pDD );
if ( status != S_cas_success ) {
return status;
}
diff --git a/src/ca/legacy/pcas/generic/casStrmClient.h b/src/ca/legacy/pcas/generic/casStrmClient.h
index 3f6c0a51b..0fdd36bb4 100644
--- a/src/ca/legacy/pcas/generic/casStrmClient.h
+++ b/src/ca/legacy/pcas/generic/casStrmClient.h
@@ -69,7 +69,7 @@ private:
bool responseIsPending;
caStatus createChannel ( const char * pName );
- caStatus verifyRequest ( casChannelI * & pChan );
+ caStatus verifyRequest ( casChannelI * & pChan, bool allowdyn = false );
typedef caStatus ( casStrmClient :: * pCASMsgHandler )
( epicsGuard < casClientMutex > & );
static pCASMsgHandler const msgHandlers[CA_PROTO_LAST_CMMD+1u];
diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp
index b85b67b8e..af4fae25d 100644
--- a/src/libCom/osi/epicsTime.cpp
+++ b/src/libCom/osi/epicsTime.cpp
@@ -60,11 +60,13 @@ static const unsigned long NTP_TIME_AT_EPICS_EPOCH =
//
// epicsTime (const unsigned long secIn, const unsigned long nSecIn)
//
-inline epicsTime::epicsTime (const unsigned long secIn,
- const unsigned long nSecIn) :
- secPastEpoch ( nSecIn / nSecPerSec + secIn ),
- nSec ( nSecIn % nSecPerSec )
+inline epicsTime::epicsTime (const unsigned long secIn, const unsigned long nSecIn) :
+ secPastEpoch ( secIn ), nSec ( nSecIn )
{
+ if (nSecIn >= nSecPerSec) {
+ this->secPastEpoch += nSecIn / nSecPerSec;
+ this->nSec = nSecIn % nSecPerSec;
+ }
}
//
@@ -113,47 +115,26 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit ()
}
//
-// epicsTime::addNanoSec ()
+// private epicsTime::addNanoSec ()
//
-// The nano-second field of several of the the UNIX time stamp formats
-// field is stored in the C type "long".
+// Most formats keep the nSec value as an unsigned long, so are +ve.
+// struct timeval's tv_usec may be -1, but I think that means error,
+// so this private method never needs to handle -ve offsets.
//
void epicsTime :: addNanoSec ( long nSecAdj )
{
- //
- // After optimizing this function we now have a larger code which
- // uses only unsigned integer, and not floating point, arithmetic.
- // This change benefits embedded CPU's lacking a floating point
- // co-processor at the expense of some additional code to maintain.
- //
- // We hope that all CPU's we run on provide at least an integer
- // divide instruction which should enable this implementation
- // to be more efficient than implementations based on branching;
- // this is presuming that we will run on pipelined architectures.
- //
- // Overflow and underflow is expected; in the future we might
- // operate close to, the modulo of, the EPICS epic.
- //
- // We are depending on the normalize operation in the private
- // constructor used below.
- //
- // joh 11-04-2012
- //
- if ( nSecAdj >= 0 ) {
- const unsigned long nSecPlus =
- static_cast