From 370240117101e85d7728cb48b947efadf278192c Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 4 Oct 2016 16:16:42 +0200 Subject: [PATCH 01/14] libCom/osi: add full epicsTime conversion from/to UTC struct tm (without timezone mechanism) --- src/libCom/osi/epicsTime.cpp | 89 ++++++++++++++++++++++++++++++++++-- src/libCom/osi/epicsTime.h | 13 +++++- 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp index 414bd5d4f..474515170 100644 --- a/src/libCom/osi/epicsTime.cpp +++ b/src/libCom/osi/epicsTime.cpp @@ -287,11 +287,80 @@ epicsTime::epicsTime (const local_tm_nano_sec &tm) throwWithLocation ( formatProblemWithStructTM () ); } + // Do the epoch conversion *this = epicsTime (ansiTimeTicks); + // Add the nSec part + *this = epicsTime (this->secPastEpoch, tm.nSec); +} - unsigned long nSecAdj = tm.nSec % nSecPerSec; - unsigned long secAdj = tm.nSec / nSecPerSec; - *this = epicsTime ( this->secPastEpoch+secAdj, this->nSec+nSecAdj ); +// +// epicsTime (const gm_tm_nano_sec &tm) +// + +// do conversion avoiding the timezone mechanism +static inline epicsInt32 is_leap(epicsInt32 year) +{ + if (year % 400 == 0) + return 1; + if (year % 100 == 0) + return 0; + if (year % 4 == 0) + return 1; + return 0; +} + +static inline epicsInt32 days_from_0(epicsInt32 year) +{ + year--; + return 365 * year + (year / 400) - (year / 100) + (year / 4); +} + +static inline epicsInt32 days_from_1970(epicsInt32 year) +{ + static const int days_from_0_to_1970 = days_from_0(1970); + return days_from_0(year) - days_from_0_to_1970; +} + +static inline epicsInt32 days_from_1jan(epicsInt32 year, + epicsInt32 month, + epicsInt32 day) +{ + static const epicsInt32 days[2][12] = + { + { 0,31,59,90,120,151,181,212,243,273,304,334}, + { 0,31,60,91,121,152,182,213,244,274,305,335} + }; + return days[is_leap(year)][month-1] + day - 1; +} + +epicsTime::epicsTime (const gm_tm_nano_sec &tm) +{ + time_t_wrapper ansiTimeTicks; + int year = tm.ansi_tm.tm_year + 1900; + int month = tm.ansi_tm.tm_mon; + if (month > 11) { + year += month / 12; + month %= 12; + } else if (month < 0) { + int years_diff = (-month + 11) / 12; + year -= years_diff; + month += 12 * years_diff; + } + month++; + int day = tm.ansi_tm.tm_mday; + int day_of_year = days_from_1jan(year, month, day); + int days_since_epoch = days_from_1970(year) + day_of_year; + + const time_t seconds_in_day = 3600 * 24; + ansiTimeTicks.ts = seconds_in_day * days_since_epoch + + 3600 * tm.ansi_tm.tm_hour + + 60 * tm.ansi_tm.tm_min + + tm.ansi_tm.tm_sec; + + // Do the epoch conversion + *this = epicsTime (ansiTimeTicks); + // Add the nSec part + *this = epicsTime (this->secPastEpoch, tm.nSec); } // @@ -905,6 +974,19 @@ extern "C" { } return epicsTimeOK; } + epicsShareFunc int epicsShareAPI epicsTimeFromGMTM (epicsTimeStamp *pDest, const struct tm *pSrc, unsigned long nSecSrc) + { + try { + gm_tm_nano_sec tmns; + tmns.ansi_tm = *pSrc; + tmns.nSec = nSecSrc; + *pDest = epicsTime (tmns); + } + catch (...) { + return epicsTimeERROR; + } + return epicsTimeOK; + } epicsShareFunc int epicsShareAPI epicsTimeToTimespec (struct timespec *pDest, const epicsTimeStamp *pSrc) { try { @@ -1036,4 +1118,3 @@ extern "C" { } } } - diff --git a/src/libCom/osi/epicsTime.h b/src/libCom/osi/epicsTime.h index a36d6afe3..1cb3733bc 100644 --- a/src/libCom/osi/epicsTime.h +++ b/src/libCom/osi/epicsTime.h @@ -105,10 +105,12 @@ public: epicsTime & operator = ( const local_tm_nano_sec & ); /* - * convert to ANSI Cs "struct tm" (with nano seconds) + * convert to and from ANSI Cs "struct tm" (with nano seconds) * adjusted for GM time (UTC) */ operator gm_tm_nano_sec () const; + epicsTime ( const gm_tm_nano_sec & ); + epicsTime & operator = ( const gm_tm_nano_sec & ); /* convert to and from POSIX RTs "struct timespec" */ operator struct timespec () const; @@ -194,13 +196,15 @@ epicsShareFunc int epicsShareAPI epicsTimeToTime_t ( epicsShareFunc int epicsShareAPI epicsTimeFromTime_t ( epicsTimeStamp * pDest, time_t src ); -/*convert to and from ANSI C's "struct tm" with nano seconds */ +/* convert to and from ANSI C's "struct tm" with nano seconds */ epicsShareFunc int epicsShareAPI epicsTimeToTM ( struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc ); epicsShareFunc int epicsShareAPI epicsTimeToGMTM ( struct tm * pDest, unsigned long * pNSecDest, const epicsTimeStamp * pSrc ); epicsShareFunc int epicsShareAPI epicsTimeFromTM ( epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc ); +epicsShareFunc int epicsShareAPI epicsTimeFromGMTM ( + epicsTimeStamp * pDest, const struct tm * pSrc, unsigned long nSecSrc ); /* convert to and from POSIX RT's "struct timespec" */ epicsShareFunc int epicsShareAPI epicsTimeToTimespec ( @@ -312,6 +316,11 @@ inline epicsTime & epicsTime::operator = ( const local_tm_nano_sec & rhs ) return *this = epicsTime ( rhs ); } +inline epicsTime & epicsTime::operator = ( const gm_tm_nano_sec & rhs ) +{ + return *this = epicsTime ( rhs ); +} + inline epicsTime & epicsTime::operator = ( const struct timespec & rhs ) { *this = epicsTime ( rhs ); From 67323441ec002b7088f662015b50c7eea1a507c7 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 4 Oct 2016 16:17:45 +0200 Subject: [PATCH 02/14] libCom/test: add roundtrip test for epicsTime from/to UTC struct tm conversion --- src/libCom/test/epicsTimeTest.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libCom/test/epicsTimeTest.cpp b/src/libCom/test/epicsTimeTest.cpp index 83d0a8a07..823f57b6f 100644 --- a/src/libCom/test/epicsTimeTest.cpp +++ b/src/libCom/test/epicsTimeTest.cpp @@ -48,7 +48,7 @@ MAIN(epicsTimeTest) const int wasteTime = 100000; const int nTimes = 10; - testPlan(15 + nTimes * 18); + testPlan(15 + nTimes * 19); try { const epicsTimeStamp epochTS = {0, 0}; @@ -205,6 +205,11 @@ MAIN(epicsTimeTest) epicsTime beginANSI = ansiDate; testOk1(beginANSI + diff == now); + // test struct gmtm round-trip conversion + gm_tm_nano_sec ansiGmDate = begin; + epicsTime beginGMANSI = ansiGmDate; + testOk1(beginGMANSI + diff == now); + // test struct timespec round-trip conversion struct timespec ts = begin; epicsTime beginTS = ts; From 4da0e2c27ec87f42afe9cf91af87e152dec69e67 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 5 Oct 2016 09:41:49 +0200 Subject: [PATCH 03/14] Add release note info for the epicsTime change --- documentation/RELEASE_NOTES.html | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index bf44e11ab..52ef97063 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,15 @@ +

Additional epicsTime conversion

+ +

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.

+

MinGW Cross-builds from Linux

Build configuration files have been back-ported from the 3.15 branch that From 2fd298b4403cf5ba49118a2ec78c001ac9ee6712 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 5 Oct 2016 15:11:57 -0500 Subject: [PATCH 04/14] Fixed issues with previous epicsTime.cpp changes --- src/libCom/osi/epicsTime.cpp | 55 ++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp index eedf8860d..23c236da2 100644 --- a/src/libCom/osi/epicsTime.cpp +++ b/src/libCom/osi/epicsTime.cpp @@ -60,7 +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 ) {} + secPastEpoch ( secIn ), nSec ( nSecIn ) +{ + if (nSecIn >= nSecPerSec) { + this->secPastEpoch += nSecIn / nSecPerSec; + this->nSec = nSecIn % nSecPerSec; + } +} // // epicsTimeLoadTimeInit @@ -108,14 +114,27 @@ epicsTimeLoadTimeInit::epicsTimeLoadTimeInit () } // -// epicsTime::addNanoSec () +// private epicsTime::addNanoSec () // -// many of the UNIX timestamp formats have nano sec stored as a 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. // inline void epicsTime::addNanoSec (long nSecAdj) { - double secAdj = static_cast (nSecAdj) / nSecPerSec; - *this += secAdj; + if (nSecAdj <= 0) + return; + + if (static_cast(nSecAdj) >= nSecPerSec) { + this->secPastEpoch += nSecAdj / nSecPerSec; + nSecAdj %= nSecPerSec; + } + + this->nSec += nSecAdj; // Can't overflow + if (this->nSec >= nSecPerSec) { + this->secPastEpoch++; + this->nSec -= nSecPerSec; + } } // @@ -286,17 +305,8 @@ epicsTime::epicsTime (const local_tm_nano_sec &tm) throwWithLocation ( formatProblemWithStructTM () ); } - unsigned long nSec = tm.nSec; - // Handle nSec overflows - if (nSec >= nSecPerSec) { - ansiTimeTicks.ts += nSec / nSecPerSec; - nSec %= nSecPerSec; - } - - // Do the epoch conversion - *this = epicsTime (ansiTimeTicks); - // Set the nSec part - this->nSec = nSec; + *this = epicsTime(ansiTimeTicks); + this->addNanoSec(tm.nSec); } // @@ -361,17 +371,8 @@ epicsTime::epicsTime (const gm_tm_nano_sec &tm) * 60 + tm.ansi_tm.tm_min) * 60 + tm.ansi_tm.tm_sec; - unsigned long nSec = tm.nSec; - // Handle nSec overflows - if (nSec >= nSecPerSec) { - ansiTimeTicks.ts += nSec / nSecPerSec; - nSec %= nSecPerSec; - } - - // Do the epoch conversion *this = epicsTime(ansiTimeTicks); - // Set the nSec part - this->nSec = nSec; + this->addNanoSec(tm.nSec); } // @@ -770,7 +771,7 @@ double epicsTime::operator - (const epicsTime &rhs) const // so the unsigned to signed conversion is ok // if (this->nSec>=rhs.nSec) { - nSecRes = this->nSec - rhs.nSec; + nSecRes = this->nSec - rhs.nSec; } else { nSecRes = rhs.nSec - this->nSec; From 928ebe82bd51d92b82bb98eafda4648d3ab0b97f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 6 Oct 2016 13:13:59 -0500 Subject: [PATCH 05/14] Build rules: Enable tests only when we can run them --- configure/RULES_BUILD | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/configure/RULES_BUILD b/configure/RULES_BUILD index 80494cb84..978d616e5 100644 --- a/configure/RULES_BUILD +++ b/configure/RULES_BUILD @@ -91,13 +91,17 @@ include $(CONFIG)/RULES_TARGET 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 @@ -337,7 +341,7 @@ $(MODNAME): %$(MODEXT): %$(EXE) $(LINK.mod) 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 @@ -352,7 +356,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 From 6e2705c23f87ea693a8fd8676c10db18037fd6e9 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 10 Oct 2016 15:12:26 -0500 Subject: [PATCH 06/14] Merged commit 12741 from Michael's pcas-fake-dynamic branch --- documentation/RELEASE_NOTES.html | 9 +++++++++ src/cas/generic/caHdrLargeArray.h | 2 +- src/cas/generic/casCtx.h | 3 +++ src/cas/generic/casStrmClient.cc | 26 +++++++++++++++++--------- src/cas/generic/casStrmClient.h | 2 +- 5 files changed, 31 insertions(+), 11 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 52ef97063..14258f352 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,15 @@ +

Add dynamic (variable length) array support to PCAS

+ +

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 will have to be modified slightly to provide full support for variable +length arrays, but unmodified applications will continue to build and work as +before against this release.

+

Additional epicsTime conversion

The EPICS timestamp library (epicsTime) inside libCom's OSI layer has diff --git a/src/cas/generic/caHdrLargeArray.h b/src/cas/generic/caHdrLargeArray.h index 89b0d6d4b..7bda002e9 100644 --- a/src/cas/generic/caHdrLargeArray.h +++ b/src/cas/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/cas/generic/casCtx.h b/src/cas/generic/casCtx.h index 706376e77..eab644685 100644 --- a/src/cas/generic/casCtx.h +++ b/src/cas/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/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index 5bcefb682..468aa17a5 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -390,14 +390,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; @@ -406,14 +404,24 @@ 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 ( allowdyn && ctx.msg.m_count==0 && + CA_V413 ( this->minor_version_number ) ) { + // Hack + // Since GDD interface doesn't support variable sized arrays + // we present dynamic requests as max size. + // This allows PCAS to claim support for dynamic arrays w/o + // going to the trouble of fixing GDD. + ctx.msg.m_count = pChan->getPVI().nativeCount(); + } + else if ( ctx.msg.m_count > pChan->getPVI().nativeCount() || + ctx.msg.m_count == 0u ) { return ECA_BADCOUNT; } @@ -446,7 +454,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard ) casChannelI * pChan; { - caStatus status = this->verifyRequest ( pChan ); + caStatus status = this->verifyRequest ( pChan, true ); if ( status != ECA_NORMAL ) { if ( pChan ) { return this->sendErr ( guard, mp, pChan->getCID(), @@ -587,7 +595,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard casChannelI * pChan; { - caStatus status = this->verifyRequest ( pChan ); + caStatus status = this->verifyRequest ( pChan, true ); if ( status != ECA_NORMAL ) { return this->readNotifyFailureResponse ( guard, * mp, status ); } @@ -1942,7 +1950,7 @@ caStatus casStrmClient::eventAddAction ( casChannelI *pciu; { - caStatus status = casStrmClient::verifyRequest ( pciu ); + caStatus status = casStrmClient::verifyRequest ( pciu, true ); if ( status != ECA_NORMAL ) { if ( pciu ) { return this->sendErr ( guard, mp, diff --git a/src/cas/generic/casStrmClient.h b/src/cas/generic/casStrmClient.h index 3f6c0a51b..0fdd36bb4 100644 --- a/src/cas/generic/casStrmClient.h +++ b/src/cas/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]; From f73d48bb6a3e4015b9c82512cda38b4e07464bb5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 10 Oct 2016 17:19:10 -0500 Subject: [PATCH 07/14] Apply fix for lp:1581505 --- src/libCom/osi/os/default/osdNetIntf.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libCom/osi/os/default/osdNetIntf.c b/src/libCom/osi/os/default/osdNetIntf.c index 1ad6360c1..21ccfa7bc 100644 --- a/src/libCom/osi/os/default/osdNetIntf.c +++ b/src/libCom/osi/os/default/osdNetIntf.c @@ -196,14 +196,22 @@ epicsShareFunc void epicsShareAPI osiSockDiscoverBroadcastAddresses * 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; } - pNewNode->addr.sa = pIfreqList->ifr_broadaddr; - ifDepenDebugPrintf ( ( "found broadcast addr = %x\n", ntohl ( pNewNode->addr.ia.sin_addr.s_addr ) ) ); + 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 = \n", ntohl ( baddr.ia.sin_addr.s_addr ) ) ); + free ( pNewNode ); + continue; + } } #if defined (IFF_POINTOPOINT) else if ( pIfreqList->ifr_flags & IFF_POINTOPOINT ) { From 9ac237b3dee4e9e1a023970304d7ca821a1c5ff3 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 12 Oct 2016 13:41:55 +0200 Subject: [PATCH 08/14] cas: Add real implementation for variable length arrays (Bruce Hill, Matej Sekoranja) --- src/cas/generic/casStrmClient.cc | 69 +++++++++++++++++--------------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/src/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index 468aa17a5..b1e321120 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -411,17 +411,8 @@ caStatus casStrmClient::verifyRequest (casChannelI * & pChan , bool allowdyn) // // element count out of range ? // - if ( allowdyn && ctx.msg.m_count==0 && - CA_V413 ( this->minor_version_number ) ) { - // Hack - // Since GDD interface doesn't support variable sized arrays - // we present dynamic requests as max size. - // This allows PCAS to claim support for dynamic arrays w/o - // going to the trouble of fixing GDD. - ctx.msg.m_count = pChan->getPVI().nativeCount(); - } - else if ( ctx.msg.m_count > pChan->getPVI().nativeCount() || - ctx.msg.m_count == 0u ) { + if ( ctx.msg.m_count > pChan->getPVI().nativeCount() || + ( !allowdyn && ctx.msg.m_count == 0u ) ) { return ECA_BADCOUNT; } @@ -454,7 +445,7 @@ caStatus casStrmClient::readAction ( epicsGuard < casClientMutex > & guard ) casChannelI * pChan; { - caStatus status = this->verifyRequest ( pChan, true ); + caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) ); if ( status != ECA_NORMAL ) { if ( pChan ) { return this->sendErr ( guard, mp, pChan->getCID(), @@ -541,11 +532,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 ) { @@ -561,21 +556,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 ); } @@ -595,7 +590,7 @@ caStatus casStrmClient::readNotifyAction ( epicsGuard < casClientMutex > & guard casChannelI * pChan; { - caStatus status = this->verifyRequest ( pChan, true ); + caStatus status = this->verifyRequest ( pChan, CA_V413 ( this->minor_version_number ) ); if ( status != ECA_NORMAL ) { return this->readNotifyFailureResponse ( guard, * mp, status ); } @@ -666,11 +661,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 ) { @@ -685,23 +684,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 ); } @@ -859,11 +858,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 ) { @@ -881,7 +884,7 @@ 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, pDBRDD ); if ( status != S_cas_success ) { caStatus ecaStatus; if ( status == S_cas_badType ) { @@ -902,7 +905,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 ); } } @@ -925,14 +928,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 ( @@ -942,7 +945,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 ); } @@ -1950,7 +1953,7 @@ caStatus casStrmClient::eventAddAction ( casChannelI *pciu; { - caStatus status = casStrmClient::verifyRequest ( pciu, true ); + caStatus status = casStrmClient::verifyRequest ( pciu, CA_V413 ( this->minor_version_number ) ); if ( status != ECA_NORMAL ) { if ( pciu ) { return this->sendErr ( guard, mp, From 1351eceead91ccae73cfb20cd627523c30db7990 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 14 Oct 2016 13:48:56 -0500 Subject: [PATCH 09/14] Clean up unused code warnings from Clang --- src/ca/cac.cpp | 6 +++--- src/ca/iocinf.h | 7 ------- src/ca/tcpiiu.cpp | 25 ------------------------- src/cas/generic/casStrmClient.cc | 2 -- src/libCom/logClient/logClient.c | 3 --- src/libCom/test/epicsCalcTest.cpp | 16 ---------------- 6 files changed, 3 insertions(+), 56 deletions(-) diff --git a/src/ca/cac.cpp b/src/ca/cac.cpp index 8a756c746..60f737ad7 100644 --- a/src/ca/cac.cpp +++ b/src/ca/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/iocinf.h b/src/ca/iocinf.h index 8a26fdbf5..0d3b57db1 100644 --- a/src/ca/iocinf.h +++ b/src/ca/iocinf.h @@ -61,13 +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 status ) : code ( status ) {}; -private: - int code; -}; - /* * CA internal functions */ diff --git a/src/ca/tcpiiu.cpp b/src/ca/tcpiiu.cpp index 377e3ac3c..69009c264 100644 --- a/src/ca/tcpiiu.cpp +++ b/src/ca/tcpiiu.cpp @@ -44,9 +44,6 @@ using namespace std; -const unsigned mSecPerSec = 1000u; -const unsigned uSecPerSec = 1000u * mSecPerSec; - tcpSendThread::tcpSendThread ( class tcpiiu & iiuIn, const char * pName, unsigned stackSize, unsigned priority ) : @@ -805,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/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index 468aa17a5..bf83a7f45 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -34,8 +34,6 @@ const nothrow_t nothrow ; } #endif -static const caHdr nill_msg = { 0u, 0u, 0u, 0u, 0u, 0u }; - casStrmClient::pCASMsgHandler const casStrmClient::msgHandlers[] = { & casStrmClient::versionAction, diff --git a/src/libCom/logClient/logClient.c b/src/libCom/logClient/logClient.c index adaaa7f95..4f5daaab1 100644 --- a/src/libCom/logClient/logClient.c +++ b/src/libCom/logClient/logClient.c @@ -34,9 +34,6 @@ #include "logClient.h" -static const int logClientSuccess = 0; -static const int logClientError = -1; - typedef struct { char msgBuf[0x4000]; struct sockaddr_in addr; diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 5a4d44aa7..f4d5a4660 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -198,14 +198,6 @@ static inline double MAX(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j) { return MAX(MAX(a,b,c,d,e,f,g,h,i),j); } -static inline double MAX(double a, double b, double c, double d, double e, - double f, double g, double h, double i, double j, double k) { - return MAX(MAX(a,b,c,d,e,f,g,h,i,j),k); -} -static inline double MAX(double a, double b, double c, double d, double e, - double f, double g, double h, double i, double j, double k, double l) { - return MAX(MAX(a,b,c,d,e,f,g,h,i,j,k),l); -} static inline double MIN(double a) { return a; @@ -242,14 +234,6 @@ static inline double MIN(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j) { return MIN(MIN(a,b,c,d,e,f,g,h,i),j); } -static inline double MIN(double a, double b, double c, double d, double e, - double f, double g, double h, double i, double j, double k) { - return MIN(MIN(a,b,c,d,e,f,g,h,i,j),k); -} -static inline double MIN(double a, double b, double c, double d, double e, - double f, double g, double h, double i, double j, double k, double l) { - return MIN(MIN(a,b,c,d,e,f,g,h,i,j,k),l); -} /* The test code below generates lots of spurious warnings because * it's making sure that our operator priorities match those of C. From 92ffe1d7267970ac392d770a071c858dc671a14f Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Tue, 18 Oct 2016 11:39:38 +0200 Subject: [PATCH 10/14] cas: fix first subscription update returning only 1 element when 0 were requested --- src/cas/generic/caServerI.h | 9 +++++++-- src/cas/generic/casStrmClient.cc | 25 +++++++++++++++++-------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/cas/generic/caServerI.h b/src/cas/generic/caServerI.h index 6037d8c20..b45d9373a 100644 --- a/src/cas/generic/caServerI.h +++ b/src/cas/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/cas/generic/casStrmClient.cc b/src/cas/generic/casStrmClient.cc index b1e321120..d8d36d926 100644 --- a/src/cas/generic/casStrmClient.cc +++ b/src/cas/generic/casStrmClient.cc @@ -737,7 +737,9 @@ caStatus casStrmClient::readNotifyFailureResponse ( // than the destination) // caStatus convertContainerMemberToAtomic ( gdd & dd, - aitUint32 appType, aitUint32 elemCount ) + aitUint32 appType, + aitUint32 requestedCount, + aitUint32 nativeCount ) { gdd * pVal; if ( dd.isContainer() ) { @@ -764,13 +766,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; @@ -780,7 +782,9 @@ caStatus convertContainerMemberToAtomic ( gdd & dd, // createDBRDD () // static caStatus createDBRDD ( unsigned dbrType, - unsigned elemCount, gdd * & pDD ) + unsigned requestedCount, + unsigned nativeCount, + gdd * & pDD ) { /* * DBR type has already been checked, but it is possible @@ -808,7 +812,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; @@ -884,7 +888,10 @@ caStatus casStrmClient::monitorResponse ( gdd * pDBRDD = 0; if ( completionStatus == S_cas_success ) { - caStatus status = createDBRDD ( msg.m_dataType, 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 ) { @@ -2614,8 +2621,10 @@ 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; } From 994cf0ff07c7fbde81de6548255a4b077f5a42d4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 18 Oct 2016 16:34:25 -0500 Subject: [PATCH 11/14] Add whole-program optimization control for MSVS Introduce a new config variable OPT_WHOLE_PROGRAM for Microsoft builds to control compiler and linker flags. Static builds with MSVS-2010 don't work properly with whole-program optimization enabled; this lets the static targets be built with normal optimization enabled and just the whole-program flags turned off. This commit also makes the CONFIG file for Microsoft builds more like the 3.15 version. --- configure/os/CONFIG.win32-x86.win32-x86 | 124 +++++++++--------- ...FIG_SITE.win32-x86-static.win32-x86-static | 8 ++ ...SITE.windows-x64-static.windows-x64-static | 8 ++ 3 files changed, 76 insertions(+), 64 deletions(-) create mode 100644 configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static create mode 100644 configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static diff --git a/configure/os/CONFIG.win32-x86.win32-x86 b/configure/os/CONFIG.win32-x86.win32-x86 index d6592dced..96cde4cf4 100644 --- a/configure/os/CONFIG.win32-x86.win32-x86 +++ b/configure/os/CONFIG.win32-x86.win32-x86 @@ -8,6 +8,8 @@ VALID_BUILDS = Host Ioc +OPT_WHOLE_PROGRAM = YES + # convert UNIX path to native path PATH_FILTER = $(subst /,\\,$(1)) @@ -35,34 +37,30 @@ HDEPENDS_METHOD = CMD # Compiler flags for C files (C++ is below) # -# /W display warnings at level d -# /W4 is for maximum (lint type) warnings -# /W3 is for production quality warnings -# /W2 displays significant warnings -# /W1 is the default and shows severe warnings only -# /w Set warning C to be shown at level -WARN_CFLAGS_YES = /W3 -WARN_CFLAGS_NO = /W1 +# -W display warnings at level d +# -W4 is for maximum (lint type) warnings +# -W3 is for production quality warnings +# -W2 displays significant warnings +# -W1 is the default and shows severe warnings only +# -w Set warning C to be shown at level +WARN_CFLAGS_YES = -W3 +WARN_CFLAGS_NO = -W1 # -# /Ox maximum optimizations -# /MD use MSVCRT (run-time as DLL, multi-thread support) -# /GL whole program optimization -# /Zi generate program database for debugging information -OPT_CFLAGS_YES = /Ox /GL +# -Ox maximum optimizations +# -GL whole program optimization +# -Oy- re-enable creation of frame pointers +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 -# /Z7 include debugging info in object files -# /Fr create source browser file -# /GZ catch bugs occurring only in optimized code -# /D_CRTDBG_MAP_ALLOC -# /RTCsu catch bugs occuring only inoptimized code -# /DEPICS_FREELIST_DEBUG good for detecting mem mrg bugs -OPT_CFLAGS_NO = /Zi /RTCsu +# -Zi generate program database for debugging information +# -RTCsu enable run-time error checks +OPT_CFLAGS_NO = -Zi -RTCsu # specify object file name and location -OBJ_CFLAG = /Fo +OBJ_CFLAG = -Fo # # the following options are required when @@ -87,53 +85,44 @@ CPP = cl /nologo /C /E # Configure OS vendor C++ compiler # -# __STDC__=0 is a real great idea of Jeff that gives us both: +# __STDC__=0 gives us both: # 1) define STDC for code (pretend ANSI conformance) # 2) set it to 0 to use MS C "extensions" (open for _open etc.) # because MS uses: if __STDC__ ... disable many nice things # -# Use of /Za would dissable DLL import/export keywords which -# include/excludes using architecture neutral macros -# -# /EHsc - generate code for exceptions -# /GR - generate code for run time type identification +# -EHsc - generate code for exceptions +# -GR - generate code for run time type identification # -CCC = cl /nologo /EHsc /GR -CODE_CPPFLAGS += /nologo /D__STDC__=0 -CODE_CPPFLAGS += /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE +CCC = cl -EHsc -GR +CODE_CPPFLAGS += -nologo -D__STDC__=0 +CODE_CPPFLAGS += -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE # Compiler flags for C++ files # -# /W display warnings at level d -# /W4 is for maximum (lint type) warnings -# /W3 is for production quality warnings -# /W2 displays significant warnings -# /W1 is the default and shows severe warnings only -# /w Set warning C to be shown at level -# /w44355 "'this' used in the base initializer list" -# /w44344 "behavior change: use of explicit template arguments results in ..." -WARN_CXXFLAGS_YES = /W3 /w44355 /w44344 -WARN_CXXFLAGS_NO = /W1 +# -W use warning level N +# (maximum lint level warnings at level 4) +# -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 # -# /Ox maximum optimizations -# /GL whole program optimization -# /Zi generate program database for debugging information -OPT_CXXFLAGS_YES = /Ox /GL +# -Ox maximum optimizations +# -GL whole program optimization +# -Oy- re-enable creation of frame pointers +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 -# /Z7 include debugging info in object files -# /Fr create source browser file -# /D_CRTDBG_MAP_ALLOC -# /RTCsu catch bugs occurring only in optimized code -# /DEPICS_FREELIST_DEBUG good for detecting mem mrg bugs -OPT_CXXFLAGS_NO = /RTCsu /Zi +# -Zi generate program database for debugging information +# -RTCsu enable run-time error checks +OPT_CXXFLAGS_NO = -RTCsu -Zi # specify object file name and location -OBJ_CXXFLAG = /Fo +OBJ_CXXFLAG = -Fo # # the following options are required when @@ -152,14 +141,20 @@ STATIC_LDLIBS_NO= STATIC_LDFLAGS= RANLIB= -# add /profile here to run the ms profiler -# /LTCG - whole program optimization -# /fixed:no good for programs such as purify and quantify -# /debug good for programs such as purify and quantify -LINK_OPT_FLAGS_YES = /LTCG /incremental:no /opt:ref /release $(PROD_VERSION:%=/version:%) -LINK_OPT_FLAGS_NO = /debug /incremental:no /fixed:no +# add -profile here to run the ms profiler +# -LTCG whole program optimization +# -incremental:no full linking +# -fixed:no generate relocatable code +# -version:. - only 2 components allowed, 0-65535 each +# -debug generate debugging info +LINK_OPT_FLAGS_WHOLE_YES = -LTCG +LINK_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM)) +LINK_OPT_FLAGS_YES += -incremental:no -opt:ref +LINK_OPT_FLAGS_YES += -release $(PROD_VERSION:%=-version:%) +LINK_OPT_FLAGS_NO = -debug -incremental:no -fixed:no OPT_LDFLAGS = $(LINK_OPT_FLAGS_$(HOST_OPT)) -LIB_OPT_FLAGS_YES = /LTCG + +LIB_OPT_FLAGS_YES = $(LINK_OPT_FLAGS_WHOLE_$(OPT_WHOLE_PROGRAM)) LIB_OPT_LDFLAGS = $(LIB_OPT_FLAGS_$(HOST_OPT)) ARCH_DEP_CFLAGS= @@ -288,8 +283,8 @@ SHRLIB_LDLIBS += $(addsuffix .lib, \ #-------------------------------------------------- # Linker definition -LINK.cpp = $(WINLINK) -nologo $(STATIC_LDFLAGS) $(LDFLAGS) $(PROD_LDFLAGS) -out:$@ \ - $(call PATH_FILTER, $(PROD_LD_OBJS) $(PROD_LD_RESS) $(PROD_LDLIBS)) +LINK.cpp = $(WINLINK) -nologo $(STATIC_LDFLAGS) $(LDFLAGS) $(PROD_LDFLAGS) \ + -out:$@ $(call PATH_FILTER, $(PROD_LD_OBJS) $(PROD_LD_RESS) $(PROD_LDLIBS)) #-------------------------------------------------- # UseManifestTool.pl checks MS Visual c++ compiler version number to @@ -297,9 +292,10 @@ LINK.cpp = $(WINLINK) -nologo $(STATIC_LDFLAGS) $(LDFLAGS) $(PROD_LDFLAGS) -out: # linker created .manifest file into a library or product target. # useManifestTool.pl returns 0(don't use) or 1(use). # -MT_DLL_COMMAND1 = mt.exe /manifest $@.manifest "/outputresource:$@;\#2" +MT.exe = mt.exe -nologo -manifest $@.manifest +MT_DLL_COMMAND1 = $(MT.exe) "-outputresource:$@;\#2" MT_EXE_COMMAND_YES = -MT_EXE_COMMAND_NO = mt.exe /manifest $@.manifest "/outputresource:$@;\#1" +MT_EXE_COMMAND_NO = $(MT.exe) "-outputresource:$@;\#1" MT_EXE_COMMAND1 = $(MT_EXE_COMMAND_$(STATIC_BUILD)) MT_DLL_COMMAND = $(MT_DLL_COMMAND$(shell $(PERL) $(TOOLS)/useManifestTool.pl)) MT_EXE_COMMAND = $(MT_EXE_COMMAND$(shell $(PERL) $(TOOLS)/useManifestTool.pl)) diff --git a/configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static b/configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static new file mode 100644 index 000000000..789a0ceeb --- /dev/null +++ b/configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static @@ -0,0 +1,8 @@ +# CONFIG_SITE.win32-x86-static.win32-x86-static +# +# Site-specific settings for the win32-x86-static target + +# Whole-program optimization doesn't work with Visual Studio 2010 when +# building static binaries. Newer versions of Visual Studio than 2010 +# may work though, comment out or set this to YES to try. +OPT_WHOLE_PROGRAM = NO diff --git a/configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static b/configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static new file mode 100644 index 000000000..23e489b1c --- /dev/null +++ b/configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static @@ -0,0 +1,8 @@ +# CONFIG_SITE.windows-x64-static.windows-x64-static +# +# Site-specific settings for the windows-x64-static target + +# Whole-program optimization doesn't work with Visual Studio 2010 when +# building static binaries. Newer versions of Visual Studio than 2010 +# may work though, comment out or set this to YES to try. +OPT_WHOLE_PROGRAM = NO From 5d5cc1029ef9d181db23ca3b0053656eda8f73be Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 19 Oct 2016 11:57:13 +0200 Subject: [PATCH 12/14] gdd: make put() write full array if requested size=0 --- src/gdd/gdd.cc | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/gdd/gdd.cc b/src/gdd/gdd.cc index 1a84808c6..438986ad1 100644 --- a/src/gdd/gdd.cc +++ b/src/gdd/gdd.cc @@ -1355,11 +1355,14 @@ gddStatus gdd::put ( const gdd * dd ) } aitUint32 srcAvailSize = srcElemCount - unusedSrcBelow; - if ( srcAvailSize > this->getBounds()->size() ) { - srcCopySize = this->getBounds()->size(); - } - else { - srcCopySize = srcAvailSize; + { + aitUint32 destSize = this->getBounds()->size(); + if ( destSize > 0 && srcAvailSize > destSize ) { + srcCopySize = destSize; + } + else { + srcCopySize = srcAvailSize; + } } if ( dataVoid() == NULL ) From ac6b8bfcc77d3077f2013b0b83874f910b183b9a Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Wed, 19 Oct 2016 14:22:25 +0200 Subject: [PATCH 13/14] templates: make caServerApp use variable size vectors --- src/makeBaseApp/top/caServerApp/exPV.cc | 2 +- src/makeBaseApp/top/caServerApp/exServer.h | 35 +++++++++++------ src/makeBaseApp/top/caServerApp/exVectorPV.cc | 39 ++++++++++--------- 3 files changed, 46 insertions(+), 30 deletions(-) diff --git a/src/makeBaseApp/top/caServerApp/exPV.cc b/src/makeBaseApp/top/caServerApp/exPV.cc index bc88b15bb..d35a4dbfa 100644 --- a/src/makeBaseApp/top/caServerApp/exPV.cc +++ b/src/makeBaseApp/top/caServerApp/exPV.cc @@ -42,7 +42,7 @@ exPV::exPV ( exServer & casIn, pvInfo & setup, // // no dataless PV allowed // - assert (this->info.getElementCount()>=1u); + assert (this->info.getCapacity()>=1u); // // start a very slow background scan diff --git a/src/makeBaseApp/top/caServerApp/exServer.h b/src/makeBaseApp/top/caServerApp/exServer.h index 5fb6adaf7..8336fda1a 100644 --- a/src/makeBaseApp/top/caServerApp/exServer.h +++ b/src/makeBaseApp/top/caServerApp/exServer.h @@ -76,8 +76,10 @@ public: double getLopr () const; aitEnum getType () const; excasIoType getIOType () const; - unsigned getElementCount () const; - void unlinkPV (); + unsigned getCapacity () const; + unsigned getElementCount () const; + void setElementCount (unsigned); + void unlinkPV (); exPV *createPV ( exServer & exCAS, bool preCreateFlag, bool scanOn, double asyncDelay ); void deletePV (); @@ -88,7 +90,8 @@ private: const double lopr; aitEnum type; const excasIoType ioType; - const unsigned elementCount; + const unsigned capacity; + unsigned elementCount; exPV * pPV; pvInfo & operator = ( const pvInfo & ); }; @@ -441,8 +444,8 @@ inline pvInfo::pvInfo ( double scanPeriodIn, const char *pNameIn, scanPeriod ( scanPeriodIn ), pName ( pNameIn ), hopr ( hoprIn ), lopr ( loprIn ), type ( typeIn ), - ioType ( ioTypeIn ), elementCount ( countIn ), - pPV ( 0 ) + ioType ( ioTypeIn ), capacity ( countIn ), + elementCount ( 0 ), pPV ( 0 ) { } @@ -454,8 +457,8 @@ inline pvInfo::pvInfo ( const pvInfo & copyIn ) : scanPeriod ( copyIn.scanPeriod ), pName ( copyIn.pName ), hopr ( copyIn.hopr ), lopr ( copyIn.lopr ), type ( copyIn.type ), - ioType ( copyIn.ioType ), elementCount ( copyIn.elementCount ), - pPV ( copyIn.pPV ) + ioType ( copyIn.ioType ), capacity ( copyIn.capacity ), + elementCount ( copyIn.elementCount ), pPV ( copyIn.pPV ) { } @@ -509,12 +512,22 @@ inline excasIoType pvInfo::getIOType () const return this->ioType; } -inline unsigned pvInfo::getElementCount () const -{ - return this->elementCount; +inline unsigned pvInfo::getCapacity () const +{ + return this->capacity; } -inline void pvInfo::unlinkPV () +inline unsigned pvInfo::getElementCount () const +{ + return this->elementCount; +} + +inline void pvInfo::setElementCount (unsigned newCount) +{ + this->elementCount = newCount; +} + +inline void pvInfo::unlinkPV () { this->pPV = NULL; } diff --git a/src/makeBaseApp/top/caServerApp/exVectorPV.cc b/src/makeBaseApp/top/caServerApp/exVectorPV.cc index da357831f..3308f8b20 100644 --- a/src/makeBaseApp/top/caServerApp/exVectorPV.cc +++ b/src/makeBaseApp/top/caServerApp/exVectorPV.cc @@ -48,7 +48,7 @@ unsigned exVectorPV::maxDimension() const aitIndex exVectorPV::maxBound (unsigned dimension) const // X aCC 361 { if (dimension==0u) { - return this->info.getElementCount(); + return this->info.getCapacity(); } else { return 0u; @@ -79,7 +79,7 @@ void exVectorPV::scan() this->currentTime = epicsTime::getCurrent(); pDD = new gddAtomic (gddAppType_value, aitEnumFloat64, - 1u, this->info.getElementCount()); + 1u, this->info.getCapacity()); if ( ! pDD.valid () ) { return; } @@ -93,7 +93,7 @@ void exVectorPV::scan() // // allocate array buffer // - pF = new aitFloat32 [this->info.getElementCount()]; + pF = new aitFloat32 [this->info.getCapacity()]; if (!pF) { return; } @@ -118,13 +118,13 @@ void exVectorPV::scan() if ( this->pValue.valid () ) { if (this->pValue->dimension()==1u) { const gddBounds *pB = this->pValue->getBounds(); - if (pB[0u].size()==this->info.getElementCount()) { + if (pB[0u].size()==this->info.getCapacity()) { pCF = *this->pValue; } } } - pFE = &pF[this->info.getElementCount()]; + pFE = &pF[this->info.getCapacity()]; while (pFsetTimeStamp ( & gddts ); status = this->update ( *pDD ); + this->info.setElementCount(this->info.getCapacity()); + if ( status != S_casApp_success ) { errMessage (status, "vector scan update failed\n"); } @@ -166,7 +168,7 @@ void exVectorPV::scan() // caStatus exVectorPV::updateValue ( const gdd & value ) { - + aitUint32 newSize = 0; // // Check bounds of incoming request // (and see if we are replacing all elements - @@ -180,10 +182,11 @@ caStatus exVectorPV::updateValue ( const gdd & value ) return S_casApp_badDimension; } const gddBounds* pb = value.getBounds (); + newSize = pb[0u].size(); if ( pb[0u].first() != 0u ) { return S_casApp_outOfBounds; } - else if ( pb[0u].size() > this->info.getElementCount() ) { + else if ( newSize > this->info.getCapacity() ) { return S_casApp_outOfBounds; } } @@ -193,14 +196,14 @@ caStatus exVectorPV::updateValue ( const gdd & value ) // return S_casApp_outOfBounds; } - + // // Create a new array data descriptor // (so that old values that may be referenced on the // event queue are not replaced) // - smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64, - 1u, this->info.getElementCount() ) ); + smartGDDPointer pNewValue ( new gddAtomic ( gddAppType_value, aitEnumFloat64, + 1u, newSize ) ); if ( ! pNewValue.valid() ) { return S_casApp_noMemory; } @@ -211,21 +214,20 @@ caStatus exVectorPV::updateValue ( const gdd & value ) // gddStatus gdds = pNewValue->unreference( ); assert ( ! gdds ); - + // // allocate array buffer // - aitFloat64 * pF = new aitFloat64 [this->info.getElementCount()]; + aitFloat64 * pF = new aitFloat64 [newSize]; if (!pF) { return S_casApp_noMemory; } - + // // Install (and initialize) array buffer // if no old values exist // - unsigned count = this->info.getElementCount(); - for ( unsigned i = 0u; i < count; i++ ) { + for ( unsigned i = 0u; i < newSize; i++ ) { pF[i] = 0.0f; } @@ -240,7 +242,7 @@ caStatus exVectorPV::updateValue ( const gdd & value ) // (do this before we increment pF) // pNewValue->putRef ( pF, pDest ); - + // // copy in the values that they are writing // @@ -248,9 +250,10 @@ caStatus exVectorPV::updateValue ( const gdd & value ) if ( gdds ) { return S_cas_noConvert; } - + this->pValue = pNewValue; - + this->info.setElementCount(newSize); + return S_casApp_success; } From ba555ee49675d9f469f14e0ffd8effecd97b2513 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 20 Oct 2016 12:23:06 -0500 Subject: [PATCH 14/14] Fix Whole Program opt settings (windows only) --- ...tic.win32-x86-static => CONFIG_SITE.Common.win32-x86-static} | 2 +- ...windows-x64-static => CONFIG_SITE.Common.windows-x64-static} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename configure/os/{CONFIG_SITE.win32-x86-static.win32-x86-static => CONFIG_SITE.Common.win32-x86-static} (85%) rename configure/os/{CONFIG_SITE.windows-x64-static.windows-x64-static => CONFIG_SITE.Common.windows-x64-static} (84%) diff --git a/configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static b/configure/os/CONFIG_SITE.Common.win32-x86-static similarity index 85% rename from configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static rename to configure/os/CONFIG_SITE.Common.win32-x86-static index 789a0ceeb..de4e61760 100644 --- a/configure/os/CONFIG_SITE.win32-x86-static.win32-x86-static +++ b/configure/os/CONFIG_SITE.Common.win32-x86-static @@ -1,4 +1,4 @@ -# CONFIG_SITE.win32-x86-static.win32-x86-static +# CONFIG_SITE.Common.win32-x86-static # # Site-specific settings for the win32-x86-static target diff --git a/configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static b/configure/os/CONFIG_SITE.Common.windows-x64-static similarity index 84% rename from configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static rename to configure/os/CONFIG_SITE.Common.windows-x64-static index 23e489b1c..5db619b11 100644 --- a/configure/os/CONFIG_SITE.windows-x64-static.windows-x64-static +++ b/configure/os/CONFIG_SITE.Common.windows-x64-static @@ -1,4 +1,4 @@ -# CONFIG_SITE.windows-x64-static.windows-x64-static +# CONFIG_SITE.Common.windows-x64-static # # Site-specific settings for the windows-x64-static target