From 695f516cbfd0b897d76ad21168dab58dafff7810 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 10 Dec 2015 13:26:21 -0600 Subject: [PATCH 01/13] Fix softIoc build with space in path to Base Also improved error messages from makeInstallDir.pl. --- src/softIoc/Makefile | 2 +- src/softIoc/makeInstallDir.pl | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/softIoc/Makefile b/src/softIoc/Makefile index c3e867963..0ddf54187 100644 --- a/src/softIoc/Makefile +++ b/src/softIoc/Makefile @@ -33,7 +33,7 @@ softMain$(OBJ) : epicsInstallDir.h epicsInstallDir.h: $(ECHO) "FINAL_LOCATION=$(FINAL_LOCATION)" - $(PERL) ../makeInstallDir.pl '$(FINAL_LOCATION)' > $@ + $(PERL) ../makeInstallDir.pl "$(FINAL_LOCATION)" > $@ clean:: @$(RM) epicsInstallDir.h diff --git a/src/softIoc/makeInstallDir.pl b/src/softIoc/makeInstallDir.pl index 96c305711..61f271f15 100644 --- a/src/softIoc/makeInstallDir.pl +++ b/src/softIoc/makeInstallDir.pl @@ -9,7 +9,8 @@ eval 'exec perl -S $0 ${1+"$@"}' # -*- Mode: perl -*- use strict; -die "Path to INSTALL_LOCATION missing\n" unless @ARGV == 1; +die "$0: Argument missing, INSTALL_LOCATION\n" if @ARGV == 0; +die "$0: Too many arguments, expecting one\n" unless @ARGV == 1; my $path = shift; From 05d3dbf45365b1aa2334e94deb5ea41461961ce6 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 21 Dec 2015 11:13:36 -0500 Subject: [PATCH 02/13] add epicsTimeZoneTest --- src/libCom/test/Makefile | 4 + src/libCom/test/epicsTimeZoneTest.c | 117 ++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/libCom/test/epicsTimeZoneTest.c diff --git a/src/libCom/test/Makefile b/src/libCom/test/Makefile index e8e94a3e6..7e1b5a020 100644 --- a/src/libCom/test/Makefile +++ b/src/libCom/test/Makefile @@ -68,6 +68,10 @@ epicsTimeTest_SRCS += epicsTimeTest.cpp testHarness_SRCS += epicsTimeTest.cpp TESTS += epicsTimeTest +TESTPROD_HOST += epicsTimeZoneTest +epicsTimeZoneTest_SRCS += epicsTimeZoneTest.c +TESTS += epicsTimeZoneTest + TESTPROD_HOST += epicsThreadTest epicsThreadTest_SRCS += epicsThreadTest.cpp testHarness_SRCS += epicsThreadTest.cpp diff --git a/src/libCom/test/epicsTimeZoneTest.c b/src/libCom/test/epicsTimeZoneTest.c new file mode 100644 index 000000000..dd12b1acf --- /dev/null +++ b/src/libCom/test/epicsTimeZoneTest.c @@ -0,0 +1,117 @@ +/*************************************************************************\ +* Copyright (c) 2015 Michael Davidsaver +* EPICS BASE is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +\*************************************************************************/ + +#include + +#include "envDefs.h" +#include "epicsTime.h" +#include "epicsUnitTest.h" + +#include "testMain.h" + +#if defined(_WIN32) +# define tzset _tzset +#endif + +static +void setTZ(const char *base, const char *dst, int offset) +{ + char tz[20]; + if(offset!=0 || dst) + sprintf(tz, "%s%d%s", base, offset/3600, dst); + else + sprintf(tz, "%s", base); + testDiag("TZ=\"%s\"", tz); + + epicsEnvSet("TZ", tz); + tzset(); +} + +static +void test_localtime(time_t T, int sec, int min, int hour, + int mday, int mon, int year, + int wday, int yday, int isdst) +{ + struct tm B; + testDiag("test_localtime(%ld, ...)", (long)T); + if(epicsTime_localtime(&T, &B)!=epicsTimeOK) { + testFail("epicsTime_localtime() error"); + testSkip(9, "epicsTime_localtime() failed"); + } else { + B.tm_year += 1900; /* for readability */ + testPass("epicsTime_localtime() success"); +#define TEST(FLD) testOk(B.tm_##FLD==FLD, "%s %d==%d", #FLD, B.tm_##FLD, FLD) + TEST(sec); + TEST(min); + TEST(hour); + TEST(mday); + TEST(mon); + TEST(year); + TEST(wday); + TEST(yday); + TEST(isdst); +#undef TEST + } +} + +static +void test_gmtime(time_t T, int sec, int min, int hour, + int mday, int mon, int year, + int wday, int yday, int isdst) +{ + struct tm B; + testDiag("test_gmtime(%ld, ...)", (long)T); + if(epicsTime_gmtime(&T, &B)!=epicsTimeOK) { + testFail("epicsTime_localtime() error"); + testSkip(9, "epicsTime_localtime() failed"); + } else { + B.tm_year += 1900; /* for readability */ + testPass("epicsTime_localtime() success"); +#define TEST(FLD) testOk(B.tm_##FLD==FLD, "%s %d==%d", #FLD, B.tm_##FLD, FLD) + TEST(sec); + TEST(min); + TEST(hour); + TEST(mday); + TEST(mon); + TEST(year); + TEST(wday); + TEST(yday); + TEST(isdst); +#undef TEST + } +} + +MAIN(epicsTimeZoneTest) +{ + testPlan(80); + /* 1445259616 + * Mon Oct 19 09:00:16 2015 EDT + * Mon Oct 19 08:00:16 2015 CDT + * Mon Oct 19 13:00:16 2015 UTC + */ + testDiag("POSIX 1445259616"); + setTZ("EST", "EDT", 5*3600); + test_localtime(1445259616ul, 16, 0, 9, 19, 9, 2015, 1, 291, 1); + setTZ("CST", "CDT", 6*3600); + test_localtime(1445259616ul, 16, 0, 8, 19, 9, 2015, 1, 291, 1); + setTZ("UTC", NULL, 0); + test_localtime(1445259616ul, 16, 0, 13, 19, 9, 2015, 1, 291, 0); + test_gmtime(1445259616ul, 16, 0, 13, 19, 9, 2015, 1, 291, 0); + /* 1421244931 + * Wed Jan 14 09:15:31 2015 EST + * Wed Jan 14 08:15:31 2015 CST + * Wed Jan 14 14:15:31 2015 UTC + */ + testDiag("POSIX 1421244931"); + setTZ("EST", "EDT", 5*3600); + test_localtime(1421244931ul, 31, 15, 9, 14, 0, 2015, 3, 13, 0); + setTZ("CST", "CDT", 6*3600); + test_localtime(1421244931ul, 31, 15, 8, 14, 0, 2015, 3, 13, 0); + setTZ("UTC", NULL, 0); + test_localtime(1421244931ul, 31, 15, 14, 14, 0, 2015, 3, 13, 0); + test_gmtime(1421244931ul, 31, 15, 14, 14, 0, 2015, 3, 13, 0); + return testDone(); +} From 2d9c529f5e9ff59a29b2da350b3d38c923458df4 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 21 Dec 2015 11:15:04 -0500 Subject: [PATCH 03/13] osdTime: win32 use C89 localtime/gmtime as recommended by Freddie Akeroyd --- src/libCom/osi/os/WIN32/osdTime.cpp | 143 +++------------------------- 1 file changed, 13 insertions(+), 130 deletions(-) diff --git a/src/libCom/osi/os/WIN32/osdTime.cpp b/src/libCom/osi/os/WIN32/osdTime.cpp index eb2c7ad9d..239d21a2c 100644 --- a/src/libCom/osi/os/WIN32/osdTime.cpp +++ b/src/libCom/osi/os/WIN32/osdTime.cpp @@ -121,148 +121,31 @@ static int osdTimeGetCurrent ( epicsTimeStamp *pDest ) return epicsTimeOK; } -inline void UnixTimeToFileTime ( const time_t * pAnsiTime, LPFILETIME pft ) -{ - LONGLONG ll = Int32x32To64 ( *pAnsiTime, 10000000 ) + LL_CONSTANT(116444736000000000); - pft->dwLowDateTime = static_cast < DWORD > ( ll ); - pft->dwHighDateTime = static_cast < DWORD > ( ll >>32 ); -} - -static int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, - 31, 30, 31, 30, 31 }; - -static bool isLeapYear ( DWORD year ) -{ - if ( (year % 4) == 0 ) { - return ( ( year % 100 ) != 0 || ( year % 400 ) == 0 ); - } else { - return false; - } -} - -static int dayOfYear ( DWORD day, DWORD month, DWORD year ) -{ - DWORD nDays = 0; - for ( unsigned m = 1; m < month; m++ ) { - nDays += daysInMonth[m-1]; - if ( m == 2 && isLeapYear(year) ) { - nDays++; - } - } - return nDays + day; -} - // synthesize a reentrant gmtime on WIN32 int epicsShareAPI epicsTime_gmtime ( const time_t *pAnsiTime, struct tm *pTM ) { - FILETIME ft; - UnixTimeToFileTime ( pAnsiTime, &ft ); - - SYSTEMTIME st; - BOOL status = FileTimeToSystemTime ( &ft, &st ); - if ( ! status ) { - return epicsTimeERROR; + struct tm * pRet = gmtime ( pAnsiTime ); + if ( pRet ) { + *pTM = *pRet; + return epicsTimeOK; + } + else { + return errno; } - - pTM->tm_sec = st.wSecond; // seconds after the minute - [0,59] - pTM->tm_min = st.wMinute; // minutes after the hour - [0,59] - pTM->tm_hour = st.wHour; // hours since midnight - [0,23] - assert ( st.wDay >= 1 && st.wDay <= 31 ); - pTM->tm_mday = st.wDay; // day of the month - [1,31] - assert ( st.wMonth >= 1 && st.wMonth <= 12 ); - pTM->tm_mon = st.wMonth - 1; // months since January - [0,11] - assert ( st.wYear >= 1900 ); - pTM->tm_year = st.wYear - 1900; // years since 1900 - pTM->tm_wday = st.wDayOfWeek; // days since Sunday - [0,6] - pTM->tm_yday = dayOfYear ( st.wDay, st.wMonth, st.wYear ) - 1; - pTM->tm_isdst = 0; - - return epicsTimeOK; } // synthesize a reentrant localtime on WIN32 int epicsShareAPI epicsTime_localtime ( const time_t * pAnsiTime, struct tm * pTM ) { - FILETIME ft; - UnixTimeToFileTime ( pAnsiTime, & ft ); - - TIME_ZONE_INFORMATION tzInfo; - DWORD tzStatus = GetTimeZoneInformation ( & tzInfo ); - if ( tzStatus == TIME_ZONE_ID_INVALID ) { - return epicsTimeERROR; + struct tm * pRet = localtime ( pAnsiTime ); + if ( pRet ) { + *pTM = *pRet; + return epicsTimeOK; } - - // - // There are remarkable weaknessess in the FileTimeToLocalFileTime - // interface so we dont use it here. Unfortunately, there is no - // corresponding function that works on file time. - // - SYSTEMTIME st; - BOOL success = FileTimeToSystemTime ( & ft, & st ); - if ( ! success ) { - return epicsTimeERROR; + else { + return errno; } - SYSTEMTIME lst; - success = SystemTimeToTzSpecificLocalTime ( - & tzInfo, & st, & lst ); - if ( ! success ) { - return epicsTimeERROR; - } - - // - // We must convert back to file time so that we can determine if DST - // is active... - // - FILETIME lft; - success = SystemTimeToFileTime ( & lst, & lft ); - if ( ! success ) { - return epicsTimeERROR; - } - - int is_dst = -1; // unknown state of dst - if ( tzStatus != TIME_ZONE_ID_UNKNOWN && - tzInfo.StandardDate.wMonth != 0 && - tzInfo.DaylightDate.wMonth != 0) { - // determine if the specified date is - // in daylight savings time - tzInfo.StandardDate.wYear = st.wYear; - FILETIME StandardDateFT; - success = SystemTimeToFileTime ( - & tzInfo.StandardDate, & StandardDateFT ); - if ( ! success ) { - return epicsTimeERROR; - } - tzInfo.DaylightDate.wYear = st.wYear; - FILETIME DaylightDateFT; - success = SystemTimeToFileTime ( - & tzInfo.DaylightDate, & DaylightDateFT ); - if ( ! success ) { - return epicsTimeERROR; - } - if ( CompareFileTime ( & lft, & DaylightDateFT ) >= 0 - && CompareFileTime ( & lft, & StandardDateFT ) < 0 ) { - is_dst = 1; - } - else { - is_dst = 0; - } - } - - pTM->tm_sec = lst.wSecond; // seconds after the minute - [0,59] - pTM->tm_min = lst.wMinute; // minutes after the hour - [0,59] - pTM->tm_hour = lst.wHour; // hours since midnight - [0,23] - assert ( lst.wDay >= 1 && lst.wDay <= 31 ); - pTM->tm_mday = lst.wDay; // day of the month - [1,31] - assert ( lst.wMonth >= 1 && lst.wMonth <= 12 ); - pTM->tm_mon = lst.wMonth - 1; // months since January - [0,11] - assert ( lst.wYear >= 1900 ); - pTM->tm_year = lst.wYear - 1900; // years since 1900 - pTM->tm_wday = lst.wDayOfWeek; // days since Sunday - [0,6] - pTM->tm_yday = dayOfYear ( lst.wDay, lst.wMonth, lst.wYear ) - 1; - pTM->tm_isdst = is_dst; - - return epicsTimeOK; } currentTime::currentTime () : From 04fee51795877a213a41273b8d8d0b5db7131850 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 21 Jan 2016 13:00:50 -0500 Subject: [PATCH 04/13] ipAddrToAsciiAsync.: don't try to join the daemon thread This isn't really necessary and may unnecessarily delay things (~10 sec. on Linux) if a query to an unreachable DNS server is in progress. --- src/libCom/misc/ipAddrToAsciiAsynchronous.cpp | 78 +++---------------- 1 file changed, 12 insertions(+), 66 deletions(-) diff --git a/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp b/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp index b3c216d04..4800f3110 100644 --- a/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp +++ b/src/libCom/misc/ipAddrToAsciiAsynchronous.cpp @@ -82,7 +82,6 @@ template class tsFreeList extern "C" { static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * ); -static void ipAddrToAsciiEngineShutdownRequest ( void * ); } // - this class executes the synchronous DNS query @@ -108,10 +107,7 @@ private: unsigned cancelPendingCount; bool exitFlag; bool callbackInProgress; - static epicsMutex * pGlobalMutex; static ipAddrToAsciiEnginePrivate * pEngine; - static unsigned numberOfReferences; - static bool shutdownRequest; ipAddrToAsciiTransaction & createTransaction (); void release (); void run (); @@ -119,15 +115,11 @@ private: ipAddrToAsciiEnginePrivate & operator = ( const ipAddrToAsciiEngine & ); friend class ipAddrToAsciiEngine; friend class ipAddrToAsciiTransactionPrivate; - friend void ipAddrToAsciiEngineShutdownRequest ( void * ); friend void ipAddrToAsciiEngineGlobalMutexConstruct ( void * ); }; -epicsMutex * ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0; ipAddrToAsciiEnginePrivate * ipAddrToAsciiEnginePrivate :: pEngine = 0; -unsigned ipAddrToAsciiEnginePrivate :: numberOfReferences = 0u; -bool ipAddrToAsciiEnginePrivate :: shutdownRequest = false; -static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = 0; +static epicsThreadOnceId ipAddrToAsciiEngineGlobalMutexOnceFlag = EPICS_THREAD_ONCE_INIT; // the users are not required to supply a show routine // for there transaction callback class @@ -138,26 +130,13 @@ ipAddrToAsciiCallBack::~ipAddrToAsciiCallBack () {} ipAddrToAsciiTransaction::~ipAddrToAsciiTransaction () {} ipAddrToAsciiEngine::~ipAddrToAsciiEngine () {} -static void ipAddrToAsciiEngineShutdownRequest ( void * ) -{ - bool deleteGlobalMutexCondDetected = false; - { - epicsGuard < epicsMutex > - guard ( * ipAddrToAsciiEnginePrivate :: pGlobalMutex ); - ipAddrToAsciiEnginePrivate :: shutdownRequest = true; - deleteGlobalMutexCondDetected = - ( ipAddrToAsciiEnginePrivate :: numberOfReferences == 0 ); - } - if ( deleteGlobalMutexCondDetected ) { - delete ipAddrToAsciiEnginePrivate :: pGlobalMutex; - ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0; - } -} - static void ipAddrToAsciiEngineGlobalMutexConstruct ( void * ) { - ipAddrToAsciiEnginePrivate :: pGlobalMutex = new epicsMutex (); - epicsAtExit ( ipAddrToAsciiEngineShutdownRequest, 0 ); + try{ + ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate (); + }catch(std::exception& e){ + errlogPrintf("ipAddrToAsciiEnginePrivate ctor fails with: %s\n", e.what()); + } } // for now its probably sufficent to allocate one @@ -169,21 +148,8 @@ ipAddrToAsciiEngine & ipAddrToAsciiEngine::allocate () epicsThreadOnce ( & ipAddrToAsciiEngineGlobalMutexOnceFlag, ipAddrToAsciiEngineGlobalMutexConstruct, 0 ); - // since we must not own lock when checking this flag - // this diagnostic has imperfect detection, but never - // incorrect detection - if ( ipAddrToAsciiEnginePrivate :: shutdownRequest ) { - throw std :: runtime_error ( - "ipAddrToAsciiEngine::allocate (): " - "attempts to create an " - "ipAddrToAsciiEngine while the exit " - "handlers are running are rejected"); - } - epicsGuard < epicsMutex > guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex ); - if ( ! ipAddrToAsciiEnginePrivate::pEngine ) { - ipAddrToAsciiEnginePrivate::pEngine = new ipAddrToAsciiEnginePrivate (); - } - ipAddrToAsciiEnginePrivate::numberOfReferences++; + if(!ipAddrToAsciiEnginePrivate::pEngine) + throw std::runtime_error("ipAddrToAsciiEngine::allocate fails"); return * ipAddrToAsciiEnginePrivate::pEngine; } @@ -207,32 +173,8 @@ ipAddrToAsciiEnginePrivate::~ipAddrToAsciiEnginePrivate () this->thread.exitWait (); } -// for now its probably sufficent to allocate one -// DNS transaction thread for all codes sharing -// the same process that need DNS services but we -// leave our options open for the future void ipAddrToAsciiEnginePrivate::release () { - bool deleteGlobalMutexCondDetected = false; - epicsThreadOnce ( - & ipAddrToAsciiEngineGlobalMutexOnceFlag, - ipAddrToAsciiEngineGlobalMutexConstruct, 0 ); - { - epicsGuard < epicsMutex > - guard ( * ipAddrToAsciiEnginePrivate::pGlobalMutex ); - assert ( ipAddrToAsciiEnginePrivate::numberOfReferences > 0u ); - ipAddrToAsciiEnginePrivate::numberOfReferences--; - if ( ipAddrToAsciiEnginePrivate::numberOfReferences == 0u ) { - deleteGlobalMutexCondDetected = - ipAddrToAsciiEnginePrivate :: shutdownRequest; - delete ipAddrToAsciiEnginePrivate :: pEngine; - ipAddrToAsciiEnginePrivate :: pEngine = 0; - } - } - if ( deleteGlobalMutexCondDetected ) { - delete ipAddrToAsciiEnginePrivate :: pGlobalMutex; - ipAddrToAsciiEnginePrivate :: pGlobalMutex = 0; - } } void ipAddrToAsciiEnginePrivate::show ( unsigned level ) const @@ -373,6 +315,8 @@ ipAddrToAsciiTransactionPrivate::~ipAddrToAsciiTransactionPrivate () if ( this->engine.pCurrent == this && this->engine.callbackInProgress && ! this->engine.thread.isCurrentThread() ) { + // cancel from another thread while callback in progress + // waits for callback to complete assert ( this->engine.cancelPendingCount < UINT_MAX ); this->engine.cancelPendingCount++; { @@ -390,9 +334,11 @@ ipAddrToAsciiTransactionPrivate::~ipAddrToAsciiTransactionPrivate () } else { if ( this->engine.pCurrent == this ) { + // cancel from callback, or while lookup in progress this->engine.pCurrent = 0; } else { + // cancel before lookup starts this->engine.labor.remove ( *this ); } this->pending = false; From 0aeba281beffac1127dcfeea4e0517848400cc47 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 21 Jan 2016 13:05:56 -0500 Subject: [PATCH 05/13] update release notes --- documentation/RELEASE_NOTES.html | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 3de7d4b4f..e4105ad72 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,14 @@ +

ipAddrToAsciiAsync.: don't try to join the daemon thread

+ +

On process exit, no longer try to stop the worker thread used by +to make DNS lookups asynchronous. +Previously this would wait for any cancelled, but still in progress, lookups. +This was most obvious with catools (eg. cainfo). +lp:1527636

+

Fix epicsTime_localtime() on Windows

Simpler versions of the epicsTime_gmtime() and epicsTime_localtime() From 99d331e50a87c9448435b034656feb459379c029 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 11 Feb 2016 14:36:48 -0600 Subject: [PATCH 06/13] Print timestamp with bad UDP msg errors --- src/rsrv/cast_server.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rsrv/cast_server.c b/src/rsrv/cast_server.c index 27cbea355..1f6f76ced 100644 --- a/src/rsrv/cast_server.c +++ b/src/rsrv/cast_server.c @@ -274,19 +274,27 @@ void cast_server(void *pParm) if(prsrv_cast_client->recv.cnt != prsrv_cast_client->recv.stk){ char buf[40]; - + ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n", prsrv_cast_client->recv.cnt-prsrv_cast_client->recv.stk, buf); + + epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", + &prsrv_cast_client->time_at_last_recv); + epicsPrintf ("CAS: message received at %s\n", buf); } } else { char buf[40]; - + ipAddrToDottedIP (&prsrv_cast_client->addr, buf, sizeof(buf)); epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf); + + epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", + &prsrv_cast_client->time_at_last_recv); + epicsPrintf ("CAS: message received at %s\n", buf); } if (CASDEBUG>2) { From 9eedf0581e05033e82c5c4cdeaf3fdfa324a8256 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Feb 2016 14:44:43 +0100 Subject: [PATCH 07/13] libCom/calc: Use epics(U)Int32 for all integer calculations Adapted backport of 3.15 revision 12308 --- src/libCom/calc/calcPerform.c | 43 ++++++++++++++++++----------------- src/libCom/calc/postfix.c | 27 ++++++++++++---------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 6de3f9dc6..0e8fcd5e9 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -21,6 +21,7 @@ #include "osiUnistd.h" #include "dbDefs.h" #include "epicsMath.h" +#include "epicsTypes.h" #include "errlog.h" #include "postfix.h" #include "postfixPvt.h" @@ -43,7 +44,7 @@ epicsShareFunc long double stack[CALCPERFORM_STACK+1]; /* zero'th entry not used */ double *ptop; /* stack pointer */ double top; /* value from top of stack */ - int itop; /* integer from top of stack */ + epicsInt32 itop; /* integer from top of stack */ int op; int nargs; @@ -55,14 +56,14 @@ epicsShareFunc long switch (op){ case LITERAL_DOUBLE: - memcpy((void *)++ptop, pinst, sizeof(double)); + memcpy(++ptop, pinst, sizeof(double)); pinst += sizeof(double); break; case LITERAL_INT: - memcpy(&itop, pinst, sizeof(int)); + memcpy(&itop, pinst, sizeof(epicsInt32)); *++ptop = itop; - pinst += sizeof(int); + pinst += sizeof(epicsInt32); break; case FETCH_VAL: @@ -136,11 +137,11 @@ epicsShareFunc long break; case MODULO: - itop = (long) *ptop--; + itop = (epicsInt32) *ptop--; if (itop) - *ptop = (long) *ptop % itop; + *ptop = (epicsInt32) *ptop % itop; else - *ptop = epicsNAN; /* NaN */ + *ptop = epicsNAN; break; case POWER: @@ -261,7 +262,7 @@ epicsShareFunc long case NINT: top = *ptop; - *ptop = (double)(long)(top >= 0 ? top + 0.5 : top - 0.5); + *ptop = (double)(epicsInt32)(top >= 0 ? top + 0.5 : top - 0.5); break; case RANDOM: @@ -283,33 +284,33 @@ epicsShareFunc long break; case BIT_OR: - itop = (long) *ptop--; - *ptop = (long) *ptop | itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop | itop; break; case BIT_AND: - itop = (long) *ptop--; - *ptop = (long) *ptop & itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop & itop; break; case BIT_EXCL_OR: - itop = (long) *ptop--; - *ptop = (long) *ptop ^ itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop ^ itop; break; case BIT_NOT: - itop = (long) *ptop; + itop = (epicsInt32) *ptop; *ptop = ~itop; break; case RIGHT_SHIFT: - itop = (long) *ptop--; - *ptop = (long) *ptop >> itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop >> itop; break; case LEFT_SHIFT: - itop = (long) *ptop--; - *ptop = (long) *ptop << itop; + itop = (epicsInt32) *ptop--; + *ptop = (epicsInt32) *ptop << itop; break; case NOT_EQ: @@ -381,7 +382,7 @@ calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores) pinst += sizeof(double); break; case LITERAL_INT: - pinst += sizeof(int); + pinst += sizeof(epicsInt32); break; case MIN: case MAX: @@ -468,7 +469,7 @@ static int cond_search(const char **ppinst, int match) pinst += sizeof(double); break; case LITERAL_INT: - pinst += sizeof(int); + pinst += sizeof(epicsInt32); break; case MIN: case MAX: diff --git a/src/libCom/calc/postfix.c b/src/libCom/calc/postfix.c index ca25bea42..4ad57f910 100644 --- a/src/libCom/calc/postfix.c +++ b/src/libCom/calc/postfix.c @@ -22,6 +22,7 @@ #include "dbDefs.h" #include "epicsStdlib.h" #include "epicsString.h" +#include "epicsTypes.h" #include "postfix.h" #include "postfixPvt.h" #include "shareLib.h" @@ -216,7 +217,7 @@ epicsShareFunc long char * const pdest = pout; char *pnext; double lit_d; - int lit_i; + epicsInt32 lit_i; if (psrc == NULL || *psrc == '\0' || pout == NULL || perror == NULL) { @@ -249,27 +250,29 @@ epicsShareFunc long goto bad; } psrc = pnext; - lit_i = (int) lit_d; + lit_i = (epicsInt32) lit_d; if (lit_d != (double) lit_i) { *pout++ = pel->code; - memcpy(pout, (void *)&lit_d, sizeof(double)); + memcpy(pout, &lit_d, sizeof(double)); pout += sizeof(double); } else { *pout++ = LITERAL_INT; - memcpy(pout, (void *)&lit_i, sizeof(int)); - pout += sizeof(int); + memcpy(pout, &lit_i, sizeof(epicsInt32)); + pout += sizeof(epicsInt32); } } else { - lit_i = strtoul(psrc, &pnext, 0); + epicsUInt32 lit_ui; + + lit_ui = (epicsUInt32) strtoul(psrc, &pnext, 0); if (pnext == psrc) { *perror = CALC_ERR_BAD_LITERAL; goto bad; } psrc = pnext; *pout++ = LITERAL_INT; - memcpy(pout, (void *)&lit_i, sizeof(int)); - pout += sizeof(int); + memcpy(pout, &lit_ui, sizeof(epicsUInt32)); + pout += sizeof(epicsUInt32); } operand_needed = FALSE; @@ -594,18 +597,18 @@ epicsShareFunc void }; char op; double lit_d; - int lit_i; + epicsInt32 lit_i; while ((op = *pinst) != END_EXPRESSION) { switch (op) { case LITERAL_DOUBLE: - memcpy((void *)&lit_d, ++pinst, sizeof(double)); + memcpy(&lit_d, ++pinst, sizeof(double)); printf("\tDouble %g\n", lit_d); pinst += sizeof(double); break; case LITERAL_INT: - memcpy((void *)&lit_i, ++pinst, sizeof(int)); - printf("\tInteger %d\n", lit_i); + memcpy(&lit_i, ++pinst, sizeof(epicsInt32)); + printf("\tInteger %d (0x%x)\n", lit_i, lit_i); pinst += sizeof(int); break; case MIN: From 4241b4e6cbf0f38d1b0e8ac9e82802eec3f88b12 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Feb 2016 15:17:52 +0100 Subject: [PATCH 08/13] libCom/test: add calc tests for bit31 operators (lp:1514520) --- src/libCom/test/epicsCalcTest.cpp | 88 +++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 3fee4923b..5b17694f9 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -8,6 +8,7 @@ // Author: Andrew Johnson #include "epicsUnitTest.h" +#include "epicsTypes.h" #include "epicsMath.h" #include "epicsAlgorithm.h" #include "postfix.h" @@ -38,30 +39,59 @@ void testCalc(const char *expr, double expected) { /* Evaluate expression, test against expected result */ bool pass = false; double args[CALCPERFORM_NARGS] = { - 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 }; char rpn[MAX_POSTFIX_SIZE]; short err; double result = 0.0; result /= result; /* Start as NaN */ - + if (postfix(expr, rpn, &err)) { - testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr); + testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr); } else - if (calcPerform(args, &result, rpn) && finite(result)) { - testDiag("calcPerform: error evaluating '%s'", expr); - } - + if (calcPerform(args, &result, rpn) && finite(result)) { + testDiag("calcPerform: error evaluating '%s'", expr); + } + if (finite(expected) && finite(result)) { - pass = fabs(expected - result) < 1e-8; + pass = fabs(expected - result) < 1e-8; } else if (isnan(expected)) { - pass = (bool) isnan(result); + pass = (bool) isnan(result); } else { - pass = (result == expected); + pass = (result == expected); } if (!testOk(pass, "%s", expr)) { - testDiag("Expected result is %g, actually got %g", expected, result); - calcExprDump(rpn); + testDiag("Expected result is %g, actually got %g", expected, result); + calcExprDump(rpn); + } + return; +} + +void testUInt32Calc(const char *expr, epicsUInt32 expected) { + /* Evaluate expression, test against expected result */ + bool pass = false; + double args[CALCPERFORM_NARGS] = { + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 + }; + char rpn[MAX_POSTFIX_SIZE]; + short err; + epicsUInt32 uresult; + double result = 0.0; + result /= result; /* Start as NaN */ + + if (postfix(expr, rpn, &err)) { + testDiag("postfix: %s in expression '%s'", calcErrorStr(err), expr); + } else + if (calcPerform(args, &result, rpn) && finite(result)) { + testDiag("calcPerform: error evaluating '%s'", expr); + } + + uresult = (epicsUInt32) result; + pass = (uresult == expected); + if (!testOk(pass, "%s", expr)) { + testDiag("Expected result is 0x%x (%u), actually got 0x%x (%u)", + expected, expected, uresult, uresult); + calcExprDump(rpn); } return; } @@ -238,8 +268,8 @@ MAIN(epicsCalcTest) const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0, g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0; - testPlan(577); - + testPlan(598); + /* LITERAL_OPERAND elements */ testExpr(0); testExpr(1); @@ -883,7 +913,35 @@ MAIN(epicsCalcTest) testBadExpr("1?", CALC_ERR_CONDITIONAL); testBadExpr("1?1", CALC_ERR_CONDITIONAL); testBadExpr(":1", CALC_ERR_SYNTAX); - + + // Bit manipulations wrt bit 31 (bug lp:1514520) + // using integer literals + testUInt32Calc("0xaaaaaaaa AND 0xffff0000", 0xaaaa0000u); + testUInt32Calc("0xaaaaaaaa OR 0xffff0000", 0xffffaaaau); + testUInt32Calc("0xaaaaaaaa XOR 0xffff0000", 0x5555aaaau); + testUInt32Calc("~0xaaaaaaaa", 0x55555555u); + testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau); + testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau); + testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u); + // using integer literals, assigned to operands + testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u); + testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau); + testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a XOR b", 0x5555aaaau); + testUInt32Calc("a:=0xaaaaaaaa; ~a", 0x55555555u); + testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau); + testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau); + testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u); + // using double operands (what the calc record does) + // 0xaaaaaaaa = 2863311530.0 + // 0xffff0000 = 4294901760.0 + testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a AND b", 0xaaaa0000u); + testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a OR b", 0xffffaaaau); + testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a XOR b", 0x5555aaaau); + testUInt32Calc("a:=2863311530.0; ~a", 0x55555555u); + testUInt32Calc("a:=2863311530.0; ~~a", 0xaaaaaaaau); + testUInt32Calc("a:=2863311530.0; a >> 8", 0xffaaaaaau); + testUInt32Calc("a:=2863311530.0; a << 8", 0xaaaaaa00u); + return testDone(); } From 599e6635fbd970af8cb80b92622da8b5c1758532 Mon Sep 17 00:00:00 2001 From: Ralph Lange Date: Thu, 18 Feb 2016 15:19:01 +0100 Subject: [PATCH 09/13] libCom/calc: fix bit31 bit manipulations --- src/libCom/calc/calcPerform.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 0e8fcd5e9..76c0e1623 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -284,33 +284,33 @@ epicsShareFunc long break; case BIT_OR: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop | itop; + itop = (epicsUInt32) *ptop--; + *ptop = (epicsInt32) ((epicsUInt32)*ptop | itop); break; case BIT_AND: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop & itop; + itop = (epicsUInt32) *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop & itop); break; case BIT_EXCL_OR: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop ^ itop; + itop = (epicsUInt32) *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop ^ itop); break; case BIT_NOT: - itop = (epicsInt32) *ptop; + itop = (epicsUInt32) *ptop; *ptop = ~itop; break; case RIGHT_SHIFT: itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop >> itop; + *ptop = (epicsInt32) (epicsUInt32) *ptop >> itop; break; case LEFT_SHIFT: itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) *ptop << itop; + *ptop = (epicsInt32) ((epicsUInt32) *ptop << itop); break; case NOT_EQ: From 89e6fdbca058a8c88b1f56512fb6f695841b3e1e Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 19 Feb 2016 15:57:44 -0600 Subject: [PATCH 10/13] Fixed conversion overflows in tests Minor tidying-up, added comments about casting for bitwise operations. --- src/libCom/calc/calcPerform.c | 38 ++++++++++++++++++++----------- src/libCom/calc/postfix.c | 6 ++--- src/libCom/test/epicsCalcTest.cpp | 22 ++++++++---------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 76c0e1623..2221f169f 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -45,6 +45,7 @@ epicsShareFunc long double *ptop; /* stack pointer */ double top; /* value from top of stack */ epicsInt32 itop; /* integer from top of stack */ + epicsUInt32 utop; /* unsigned integer from top of stack */ int op; int nargs; @@ -262,7 +263,7 @@ epicsShareFunc long case NINT: top = *ptop; - *ptop = (double)(epicsInt32)(top >= 0 ? top + 0.5 : top - 0.5); + *ptop = (epicsInt32) (top >= 0 ? top + 0.5 : top - 0.5); break; case RANDOM: @@ -283,34 +284,45 @@ epicsShareFunc long *ptop = ! *ptop; break; + /* For bitwise operations on values with bit 31 set, double values + * must first be cast to unsigned to correctly set that bit; the + * double value must be negative in that case. The result must be + * cast to a signed integer before converting to the double result. + */ + case BIT_OR: - itop = (epicsUInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32)*ptop | itop); + utop = *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop | utop); break; case BIT_AND: - itop = (epicsUInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32) *ptop & itop); + utop = *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop & utop); break; case BIT_EXCL_OR: - itop = (epicsUInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32) *ptop ^ itop); + utop = *ptop--; + *ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop); break; case BIT_NOT: - itop = (epicsUInt32) *ptop; - *ptop = ~itop; + utop = *ptop; + *ptop = (epicsInt32) ~utop; break; + /* The shift operators use signed integers, so a right-shift will + * extend the sign bit into the left-hand end of the value. The + * double-casting through unsigned here is important, see above. + */ + case RIGHT_SHIFT: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) (epicsUInt32) *ptop >> itop; + utop = *ptop--; + *ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31); break; case LEFT_SHIFT: - itop = (epicsInt32) *ptop--; - *ptop = (epicsInt32) ((epicsUInt32) *ptop << itop); + utop = *ptop--; + *ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31); break; case NOT_EQ: diff --git a/src/libCom/calc/postfix.c b/src/libCom/calc/postfix.c index 4ad57f910..d64d00d85 100644 --- a/src/libCom/calc/postfix.c +++ b/src/libCom/calc/postfix.c @@ -602,13 +602,13 @@ epicsShareFunc void while ((op = *pinst) != END_EXPRESSION) { switch (op) { case LITERAL_DOUBLE: - memcpy(&lit_d, ++pinst, sizeof(double)); + memcpy(&lit_d, ++pinst, sizeof(double)); printf("\tDouble %g\n", lit_d); pinst += sizeof(double); break; case LITERAL_INT: - memcpy(&lit_i, ++pinst, sizeof(epicsInt32)); - printf("\tInteger %d (0x%x)\n", lit_i, lit_i); + memcpy(&lit_i, ++pinst, sizeof(epicsInt32)); + printf("\tInteger %d (0x%x)\n", lit_i, lit_i); pinst += sizeof(int); break; case MIN: diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index 5b17694f9..b5199ac15 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -64,7 +64,6 @@ void testCalc(const char *expr, double expected) { testDiag("Expected result is %g, actually got %g", expected, result); calcExprDump(rpn); } - return; } void testUInt32Calc(const char *expr, epicsUInt32 expected) { @@ -93,7 +92,6 @@ void testUInt32Calc(const char *expr, epicsUInt32 expected) { expected, expected, uresult, uresult); calcExprDump(rpn); } - return; } void testArgs(const char *expr, unsigned long einp, unsigned long eout) { @@ -931,16 +929,16 @@ MAIN(epicsCalcTest) testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u); - // using double operands (what the calc record does) - // 0xaaaaaaaa = 2863311530.0 - // 0xffff0000 = 4294901760.0 - testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a AND b", 0xaaaa0000u); - testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a OR b", 0xffffaaaau); - testUInt32Calc("a:=2863311530.0; b:=4294901760.0; a XOR b", 0x5555aaaau); - testUInt32Calc("a:=2863311530.0; ~a", 0x55555555u); - testUInt32Calc("a:=2863311530.0; ~~a", 0xaaaaaaaau); - testUInt32Calc("a:=2863311530.0; a >> 8", 0xffaaaaaau); - testUInt32Calc("a:=2863311530.0; a << 8", 0xaaaaaa00u); + // using double operands (add 0.1 to force as double) + // 0xaaaaaaaa = -1431655766 + // 0xffff0000 = -65536 + testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a AND b", 0xaaaa0000u); + testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a OR b", 0xffffaaaau); + testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a XOR b", 0x5555aaaau); + testUInt32Calc("a:=-1431655766.1; ~a", 0x55555555u); + testUInt32Calc("a:=-1431655766.1; ~~a", 0xaaaaaaaau); + testUInt32Calc("a:=-1431655766.1; a >> 8", 0xffaaaaaau); + testUInt32Calc("a:=-1431655766.1; a << 8", 0xaaaaaa00u); return testDone(); } From b45622ac5e3a230d3d1ee55526bb2bd71bf75361 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 23 Feb 2016 12:42:00 -0600 Subject: [PATCH 11/13] Test each bitwise cast individually for overflow --- src/libCom/test/epicsCalcTest.cpp | 40 +++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/libCom/test/epicsCalcTest.cpp b/src/libCom/test/epicsCalcTest.cpp index b5199ac15..ae129c449 100644 --- a/src/libCom/test/epicsCalcTest.cpp +++ b/src/libCom/test/epicsCalcTest.cpp @@ -266,7 +266,7 @@ MAIN(epicsCalcTest) const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0, g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0; - testPlan(598); + testPlan(613); /* LITERAL_OPERAND elements */ testExpr(0); @@ -921,7 +921,7 @@ MAIN(epicsCalcTest) testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau); testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau); testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u); - // using integer literals, assigned to operands + // using integer literals assigned to variables testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u); testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau); testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a XOR b", 0x5555aaaau); @@ -929,16 +929,32 @@ MAIN(epicsCalcTest) testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau); testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u); - // using double operands (add 0.1 to force as double) - // 0xaaaaaaaa = -1431655766 - // 0xffff0000 = -65536 - testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a AND b", 0xaaaa0000u); - testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a OR b", 0xffffaaaau); - testUInt32Calc("a:=-1431655766.1; b:=-65536.1; a XOR b", 0x5555aaaau); - testUInt32Calc("a:=-1431655766.1; ~a", 0x55555555u); - testUInt32Calc("a:=-1431655766.1; ~~a", 0xaaaaaaaau); - testUInt32Calc("a:=-1431655766.1; a >> 8", 0xffaaaaaau); - testUInt32Calc("a:=-1431655766.1; a << 8", 0xaaaaaa00u); + + // Test proper conversion of double values (+ 0.1 enforces double literal) + // when used as inputs to the bitwise operations. + // 0xaaaaaaaa = -1431655766 or 2863311530u + testUInt32Calc("-1431655766.1 OR 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 OR 0", 0xaaaaaaaau); + testUInt32Calc("0 OR -1431655766.1", 0xaaaaaaaau); + testUInt32Calc("0 OR 2863311530.1", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 XOR 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 XOR 0", 0xaaaaaaaau); + testUInt32Calc("0 XOR -1431655766.1", 0xaaaaaaaau); + testUInt32Calc("0 XOR 2863311530.1", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 AND 0xffffffff", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 AND 0xffffffff", 0xaaaaaaaau); + testUInt32Calc("0xffffffff AND -1431655766.1", 0xaaaaaaaau); + testUInt32Calc("0xffffffff AND 2863311530.1", 0xaaaaaaaau); + testUInt32Calc("~ -1431655766.1", 0x55555555u); + testUInt32Calc("~ 2863311530.1", 0x55555555u); + testUInt32Calc("-1431655766.1 >> 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 >> 0", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 >> 0.1", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 >> 0.1", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 << 0", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 << 0", 0xaaaaaaaau); + testUInt32Calc("-1431655766.1 << 0.1", 0xaaaaaaaau); + testUInt32Calc("2863311530.1 << 0.1", 0xaaaaaaaau); return testDone(); } From 76d7ce1f76e72ea6176102bd3606e4feab05d654 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 24 Feb 2016 15:06:59 -0600 Subject: [PATCH 12/13] Fix MSVC (de)-optimizer issue --- src/libCom/calc/calcPerform.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libCom/calc/calcPerform.c b/src/libCom/calc/calcPerform.c index 2221f169f..e53d860e2 100644 --- a/src/libCom/calc/calcPerform.c +++ b/src/libCom/calc/calcPerform.c @@ -33,6 +33,10 @@ static int cond_search(const char **ppinst, int match); #define PI 3.14159265358979323 #endif +/* Turn off global optimization for 64-bit MSVC builds */ +#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW) +# pragma optimize("g", off) +#endif /* calcPerform * @@ -379,6 +383,9 @@ epicsShareFunc long *presult = *ptop; return 0; } +#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW) +# pragma optimize("", on) +#endif epicsShareFunc long From d943f6966f7ff02c0e4d5e502ac154ffc18307b0 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 24 Feb 2016 17:39:29 -0600 Subject: [PATCH 13/13] Minor updates to the extensions/configure template --- src/makeBaseExt/top/configure/CONFIG | 49 ++++++++++------------ src/makeBaseExt/top/configure/RELEASE | 23 +++++----- src/makeBaseExt/top/configure/RULES | 8 +++- src/makeBaseExt/top/configure/RULES_PYTHON | 4 ++ 4 files changed, 44 insertions(+), 40 deletions(-) diff --git a/src/makeBaseExt/top/configure/CONFIG b/src/makeBaseExt/top/configure/CONFIG index ab213ce52..321f6cea2 100644 --- a/src/makeBaseExt/top/configure/CONFIG +++ b/src/makeBaseExt/top/configure/CONFIG @@ -1,48 +1,43 @@ -# $Revision-Id$ +# CONFIG - Load build configuration data +# +# Do not make changes in this file, any site-specific +# overrides should be given in a CONFIG_SITE file. -# You might want to change this to some shared set of rules, e.g. -# RULES=/path/to/epics/support/modules/rules/x-y -RULES=$(EPICS_BASE) +# Where the build rules come from +RULES = $(EPICS_BASE) INSTALL_IDLFILE = $(INSTALL) include $(TOP)/configure/RELEASE -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH) -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common + ifdef T_A --include $(TOP)/configure/RELEASE.Common.$(T_A) --include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) + -include $(TOP)/configure/RELEASE.Common.$(T_A) + -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) endif -CONFIG=$(RULES)/configure +CONFIG = $(RULES)/configure include $(CONFIG)/CONFIG -# Override for definition in base +# Override some Base definitions INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain build configuration overrides include $(TOP)/configure/CONFIG_SITE -ifdef INSTALL_LOCATION_EXTENSIONS -INSTALL_LOCATION = $(INSTALL_LOCATION_EXTENSIONS) -endif - -# Site specific host architecture definitions +# Host-arch specific settings -include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).Common +ifdef INSTALL_LOCATION_EXTENSIONS + INSTALL_LOCATION = $(INSTALL_LOCATION_EXTENSIONS) +endif + ifdef T_A + # Target-arch specific settings + -include $(TOP)/configure/os/CONFIG_SITE.Common.$(T_A) -# Site specific target architecture definitions --include $(TOP)/configure/os/CONFIG_SITE.Common.$(T_A) - -# Cross compile specific definitions -ifneq ($(EPICS_HOST_ARCH),$(T_A)) --include $(TOP)/configure/CONFIG.CrossCommon -endif - -# Site specific host-target combination definitions --include $(TOP)/configure/os/CONFIG.$(EPICS_HOST_ARCH).$(T_A) --include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - --include $(TOP)/configure/O.$(T_A)/CONFIG_APP_INCLUDE - + # Host & target specific combination settings + -include $(TOP)/configure/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) endif diff --git a/src/makeBaseExt/top/configure/RELEASE b/src/makeBaseExt/top/configure/RELEASE index cb4c9cce2..2a7ad2714 100644 --- a/src/makeBaseExt/top/configure/RELEASE +++ b/src/makeBaseExt/top/configure/RELEASE @@ -1,22 +1,23 @@ -#RELEASE Location of external products +# RELEASE Locations of external modules # # NOTE: The build does not check dependancies on files # external to this application. Thus you should run # "gnumake clean uninstall install" in the top directory -# each time EPICS_BASE, SNCSEQ, or any other external -# module defined in a RELEASE* file is rebuilt. +# each time EPICS_BASE or any other external module that +# is defined in a RELEASE* file gets rebuilt. # -# Host/target specific settings can be specified in files named -# RELEASE.$(EPICS_HOST_ARCH).Common -# RELEASE.Common.$(T_A) -# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# Host/target specific paths can be specified in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) # Define INSTALL_LOCATION in CONFIG_SITE -# Location of external products -EPICS_BASE=_EPICS_BASE_ EPICS_EXTENSIONS = $(TOP) -# OAG_APPS may be needed by extension SDDS -#OAG_APPS=$(TOP)/../../oag/apps +# Locations of external modules +# OAG_APPS may be needed by the SDDS extension +#OAG_APPS = $(TOP)/../../oag/apps + +EPICS_BASE = _EPICS_BASE_ diff --git a/src/makeBaseExt/top/configure/RULES b/src/makeBaseExt/top/configure/RULES index 1ba776797..87f23cc85 100644 --- a/src/makeBaseExt/top/configure/RULES +++ b/src/makeBaseExt/top/configure/RULES @@ -1,5 +1,9 @@ # $Revision-Id$ include $(CONFIG)/RULES -include $(TOP)/configure/RULES_PYTHON -include $(TOP)/configure/RULES_IDL +-include $(TOP)/configure/RULES_PYTHON +-include $(TOP)/configure/RULES_IDL + +ifdef BASE_3_15 + -include $(TOP)/configure/RULES_JAVA +endif diff --git a/src/makeBaseExt/top/configure/RULES_PYTHON b/src/makeBaseExt/top/configure/RULES_PYTHON index c8522e01e..41bdc9e65 100644 --- a/src/makeBaseExt/top/configure/RULES_PYTHON +++ b/src/makeBaseExt/top/configure/RULES_PYTHON @@ -43,7 +43,11 @@ $(PYTHON_PACKAGE_PTH): %_wrap.c: ../%.i $(SWIG) -python -o $@ $< +ifdef BASE_3_15 +clean: +else clean:: +endif @$(RM) *.py *.so *.pth endif