From c853234e01a3f932079ba87114aadc2e3db58644 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 8 Jun 2017 09:53:07 -0400 Subject: [PATCH 1/6] Remove artificial 60-minute timeout limit (Posix) --- src/libCom/osi/os/Darwin/osdTime.cpp | 4 +--- src/libCom/osi/os/posix/osdTime.cpp | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libCom/osi/os/Darwin/osdTime.cpp b/src/libCom/osi/os/Darwin/osdTime.cpp index f3e6db5dd..bf16aea3a 100644 --- a/src/libCom/osi/os/Darwin/osdTime.cpp +++ b/src/libCom/osi/os/Darwin/osdTime.cpp @@ -69,10 +69,8 @@ convertDoubleToWakeTime(double timeout, struct timespec *wakeTime) clock_get_time(host_clock, &now); - if (timeout<0.0) + if (timeout < 0.0) timeout = 0.0; - else if(timeout>3600.0) - timeout = 3600.0; wait.tv_sec = static_cast< long >(timeout); wait.tv_nsec = static_cast< long >((timeout - (double)wait.tv_sec) * 1e9); diff --git a/src/libCom/osi/os/posix/osdTime.cpp b/src/libCom/osi/os/posix/osdTime.cpp index 8a075f8ae..718b1d95d 100644 --- a/src/libCom/osi/os/posix/osdTime.cpp +++ b/src/libCom/osi/os/posix/osdTime.cpp @@ -90,8 +90,8 @@ extern "C" epicsShareFunc void struct timespec wait; int status; - if(timeout<0.0) timeout = 0.0; - else if(timeout>3600.0) timeout = 3600.0; + if (timeout < 0.0) + timeout = 0.0; #ifdef CLOCK_REALTIME status = clock_gettime(CLOCK_REALTIME, wakeTime); #else From b369aa67f163ed8f9703aaee57067a420173091c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 8 Jun 2017 21:55:12 -0500 Subject: [PATCH 2/6] Use 1000 years as 'forever' in timers DBL_MAX causes problems... --- src/libCom/timer/timerPrivate.h | 3 ++- src/libCom/timer/timerQueue.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libCom/timer/timerPrivate.h b/src/libCom/timer/timerPrivate.h index 228085d65..9701cf02a 100644 --- a/src/libCom/timer/timerPrivate.h +++ b/src/libCom/timer/timerPrivate.h @@ -107,7 +107,8 @@ private: epicsTime exceptMsgTimeStamp; bool cancelPending; static const double exceptMsgMinPeriod; - void printExceptMsg ( const char * pName, + static const double maxDelay; + void printExceptMsg ( const char * pName, const type_info & type ); timerQueue ( const timerQueue & ); timerQueue & operator = ( const timerQueue & ); diff --git a/src/libCom/timer/timerQueue.cpp b/src/libCom/timer/timerQueue.cpp index 5a798d4d4..915c6153f 100644 --- a/src/libCom/timer/timerQueue.cpp +++ b/src/libCom/timer/timerQueue.cpp @@ -21,6 +21,7 @@ #include "errlog.h" const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds +const double timerQueue :: maxDelay = 60 * 60 * 24 * 365242.5; // ~1000 years epicsTimerQueue::~epicsTimerQueue () {} @@ -57,7 +58,7 @@ void timerQueue :: } } catch ( ... ) { - delay = DBL_MAX; + delay = maxDelay; strcpy ( date, "UKN DATE" ); } if ( delay >= exceptMsgMinPeriod ) { @@ -91,7 +92,7 @@ double timerQueue::process ( const epicsTime & currentTime ) return delay; } else { - return DBL_MAX; + return maxDelay; } } @@ -116,14 +117,14 @@ double timerQueue::process ( const epicsTime & currentTime ) } } else { - return DBL_MAX; + return maxDelay; } # ifdef DEBUG unsigned N = 0u; # endif - double delay = DBL_MAX; + double delay = maxDelay; while ( true ) { epicsTimerNotify *pTmpNotify = this->pExpireTmr->pNotify; this->pExpireTmr->pNotify = 0; @@ -194,7 +195,7 @@ double timerQueue::process ( const epicsTime & currentTime ) } else { this->processThread = 0; - delay = DBL_MAX; + delay = maxDelay; break; } } From 18dee384ecaf72b8f38cd51c479157907b296a79 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 9 Jun 2017 12:20:16 -0500 Subject: [PATCH 3/6] Fix tv_sec casts to use time_t, not long --- src/libCom/fdmgr/fdManager.cpp | 2 +- src/libCom/osi/os/Darwin/osdTime.cpp | 2 +- src/libCom/osi/os/posix/osdTime.cpp | 2 +- src/libCom/test/fdmgrTest.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libCom/fdmgr/fdManager.cpp b/src/libCom/fdmgr/fdManager.cpp index 4cc67d360..d8498ed5c 100644 --- a/src/libCom/fdmgr/fdManager.cpp +++ b/src/libCom/fdmgr/fdManager.cpp @@ -116,7 +116,7 @@ epicsShareFunc void fdManager::process (double delay) if ( ioPending ) { struct timeval tv; - tv.tv_sec = static_cast ( minDelay ); + tv.tv_sec = static_cast ( minDelay ); tv.tv_usec = static_cast ( (minDelay-tv.tv_sec) * uSecPerSec ); fd_set * pReadSet = & this->fdSetsPtr[fdrRead]; diff --git a/src/libCom/osi/os/Darwin/osdTime.cpp b/src/libCom/osi/os/Darwin/osdTime.cpp index bf16aea3a..03c549cad 100644 --- a/src/libCom/osi/os/Darwin/osdTime.cpp +++ b/src/libCom/osi/os/Darwin/osdTime.cpp @@ -72,7 +72,7 @@ convertDoubleToWakeTime(double timeout, struct timespec *wakeTime) if (timeout < 0.0) timeout = 0.0; - wait.tv_sec = static_cast< long >(timeout); + wait.tv_sec = static_cast< time_t >(timeout); wait.tv_nsec = static_cast< long >((timeout - (double)wait.tv_sec) * 1e9); wakeTime->tv_sec = now.tv_sec + wait.tv_sec; diff --git a/src/libCom/osi/os/posix/osdTime.cpp b/src/libCom/osi/os/posix/osdTime.cpp index 718b1d95d..b0d288969 100644 --- a/src/libCom/osi/os/posix/osdTime.cpp +++ b/src/libCom/osi/os/posix/osdTime.cpp @@ -107,7 +107,7 @@ extern "C" epicsShareFunc void perror("convertDoubleToWakeTime"); cantProceed("convertDoubleToWakeTime"); } - wait.tv_sec = static_cast< long >(timeout); + wait.tv_sec = static_cast< time_t >(timeout); wait.tv_nsec = static_cast< long >((timeout - (double)wait.tv_sec) * 1e9); wakeTime->tv_sec += wait.tv_sec; wakeTime->tv_nsec += wait.tv_nsec; diff --git a/src/libCom/test/fdmgrTest.c b/src/libCom/test/fdmgrTest.c index 86857c6f5..e41784ccf 100644 --- a/src/libCom/test/fdmgrTest.c +++ b/src/libCom/test/fdmgrTest.c @@ -74,13 +74,13 @@ void testTimer (fdctx *pfdm, double delay) epicsTimeGetCurrent (&begin); cbs.done = 0; - tmo.tv_sec = (unsigned long) delay; + tmo.tv_sec = (time_t) delay; tmo.tv_usec = (unsigned long) ((delay - tmo.tv_sec) * uSecPerSec); aid = fdmgr_add_timeout (pfdm, &tmo, alarmCB, &cbs); verify (aid!=fdmgrNoAlarm); while (!cbs.done) { - tmo.tv_sec = (unsigned long) delay; + tmo.tv_sec = (time_t) delay; tmo.tv_usec = (unsigned long) ((delay - tmo.tv_sec) * uSecPerSec); status = fdmgr_pend_event (pfdm, &tmo); verify (status==0); From 6ef995525a5d81d4d5fb422e14010af9bdbe3ce7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 9 Jun 2017 13:44:30 -0500 Subject: [PATCH 4/6] Restore the use of DBL_MAX in timerQueue.cpp --- src/libCom/timer/timerPrivate.h | 1 - src/libCom/timer/timerQueue.cpp | 11 +++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/libCom/timer/timerPrivate.h b/src/libCom/timer/timerPrivate.h index 9701cf02a..305d3bc6f 100644 --- a/src/libCom/timer/timerPrivate.h +++ b/src/libCom/timer/timerPrivate.h @@ -107,7 +107,6 @@ private: epicsTime exceptMsgTimeStamp; bool cancelPending; static const double exceptMsgMinPeriod; - static const double maxDelay; void printExceptMsg ( const char * pName, const type_info & type ); timerQueue ( const timerQueue & ); diff --git a/src/libCom/timer/timerQueue.cpp b/src/libCom/timer/timerQueue.cpp index 915c6153f..5a798d4d4 100644 --- a/src/libCom/timer/timerQueue.cpp +++ b/src/libCom/timer/timerQueue.cpp @@ -21,7 +21,6 @@ #include "errlog.h" const double timerQueue :: exceptMsgMinPeriod = 60.0 * 5.0; // seconds -const double timerQueue :: maxDelay = 60 * 60 * 24 * 365242.5; // ~1000 years epicsTimerQueue::~epicsTimerQueue () {} @@ -58,7 +57,7 @@ void timerQueue :: } } catch ( ... ) { - delay = maxDelay; + delay = DBL_MAX; strcpy ( date, "UKN DATE" ); } if ( delay >= exceptMsgMinPeriod ) { @@ -92,7 +91,7 @@ double timerQueue::process ( const epicsTime & currentTime ) return delay; } else { - return maxDelay; + return DBL_MAX; } } @@ -117,14 +116,14 @@ double timerQueue::process ( const epicsTime & currentTime ) } } else { - return maxDelay; + return DBL_MAX; } # ifdef DEBUG unsigned N = 0u; # endif - double delay = maxDelay; + double delay = DBL_MAX; while ( true ) { epicsTimerNotify *pTmpNotify = this->pExpireTmr->pNotify; this->pExpireTmr->pNotify = 0; @@ -195,7 +194,7 @@ double timerQueue::process ( const epicsTime & currentTime ) } else { this->processThread = 0; - delay = maxDelay; + delay = DBL_MAX; break; } } From 2819d7ea3d856dd7e9b2b1fc508b66c9cbbccd95 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 14 Jun 2017 10:01:23 -0500 Subject: [PATCH 5/6] Posix epicsEventWaitWithTimeout() max delay Limit timeouts on Posix to max-out at 10 years. Adds a test that will fail when that time-out hits Y2038 on systems where time_t is still a 32-bit integer. --- documentation/RELEASE_NOTES.html | 10 +++++++++ src/libCom/osi/os/Darwin/osdTime.cpp | 6 ++++-- src/libCom/osi/os/posix/osdTime.cpp | 17 +++++++++------ src/libCom/test/epicsTimeTest.cpp | 32 +++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 9 deletions(-) diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html index 78964d5ee..20ff8f460 100644 --- a/documentation/RELEASE_NOTES.html +++ b/documentation/RELEASE_NOTES.html @@ -13,6 +13,16 @@ +

Extend maximum Posix epicsEventWaitWithTimeout() delay

+ +

The Posix implementation of epicsEventWaitWithTimeout() was limiting the +timeout delay to at most 60 minutes (3600.0 seconds). This has been changed to +10 years; significantly longer maximum delays cause problems on systems where +time_t is still a signed 32-bit integer so cannot represent absolute +time-stamps after 2038-01-19. Our assumption is that such 32-bit systems will +have been retired before the year 2028, but some additional tests have been +added to the epicsTimeTest program to detect and fail if this assumption is +violated.

New test-related make targets

diff --git a/src/libCom/osi/os/Darwin/osdTime.cpp b/src/libCom/osi/os/Darwin/osdTime.cpp index 03c549cad..17e9cead9 100644 --- a/src/libCom/osi/os/Darwin/osdTime.cpp +++ b/src/libCom/osi/os/Darwin/osdTime.cpp @@ -67,10 +67,12 @@ convertDoubleToWakeTime(double timeout, struct timespec *wakeTime) mach_timespec_t now; struct timespec wait; - clock_get_time(host_clock, &now); - if (timeout < 0.0) timeout = 0.0; + else if (timeout > 60 * 60 * 24 * 3652.5) + timeout = 60 * 60 * 24 * 3652.5; /* 10 years */ + + clock_get_time(host_clock, &now); wait.tv_sec = static_cast< time_t >(timeout); wait.tv_nsec = static_cast< long >((timeout - (double)wait.tv_sec) * 1e9); diff --git a/src/libCom/osi/os/posix/osdTime.cpp b/src/libCom/osi/os/posix/osdTime.cpp index b0d288969..82b464937 100644 --- a/src/libCom/osi/os/posix/osdTime.cpp +++ b/src/libCom/osi/os/posix/osdTime.cpp @@ -87,30 +87,35 @@ int epicsTime_localtime ( const time_t *clock, // X aCC 361 extern "C" epicsShareFunc void convertDoubleToWakeTime(double timeout,struct timespec *wakeTime) { - struct timespec wait; + struct timespec now, wait; int status; if (timeout < 0.0) timeout = 0.0; + else if (timeout > 60 * 60 * 24 * 3652.5) + timeout = 60 * 60 * 24 * 3652.5; /* 10 years */ + #ifdef CLOCK_REALTIME - status = clock_gettime(CLOCK_REALTIME, wakeTime); + status = clock_gettime(CLOCK_REALTIME, &now); #else { struct timeval tv; struct timezone tz; status = gettimeofday(&tv, &tz); - wakeTime->tv_sec = tv.tv_sec; - wakeTime->tv_nsec = tv.tv_usec * 1000; + now.tv_sec = tv.tv_sec; + now.tv_nsec = tv.tv_usec * 1000; } #endif if (status) { perror("convertDoubleToWakeTime"); cantProceed("convertDoubleToWakeTime"); } + wait.tv_sec = static_cast< time_t >(timeout); wait.tv_nsec = static_cast< long >((timeout - (double)wait.tv_sec) * 1e9); - wakeTime->tv_sec += wait.tv_sec; - wakeTime->tv_nsec += wait.tv_nsec; + + wakeTime->tv_sec = now.tv_sec + wait.tv_sec; + wakeTime->tv_nsec = now.tv_nsec + wait.tv_nsec; if (wakeTime->tv_nsec >= 1000000000L) { wakeTime->tv_nsec -= 1000000000L; ++wakeTime->tv_sec; diff --git a/src/libCom/test/epicsTimeTest.cpp b/src/libCom/test/epicsTimeTest.cpp index 823f57b6f..110ae21a4 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 * 19); + testPlan(17 + nTimes * 19); try { const epicsTimeStamp epochTS = {0, 0}; @@ -216,5 +216,35 @@ MAIN(epicsTimeTest) testOk1(beginTS + diff == now); } + epicsTime ten_years_hence; + try { + now = epicsTime::getCurrent(); + ten_years_hence = now + 60 * 60 * 24 * 3652.5; + testPass("epicsTime can represent 10 years hence"); + } + catch ( ... ) { + testFail("epicsTime exception for value 10 years hence"); + } + + try { + /* This test exists because in libCom/osi/os/posix/osdTime.cpp + * the convertDoubleToWakeTime() routine limits the timeout delay + * to 10 years. libCom/timer/timerQueue.cpp returns DBL_MAX for + * queues with no timers present, and convertDoubleToWakeTime() + * has to return an absolute Posix timestamp. On 2028-01-19 any + * systems that still implement time_t as a signed 32-bit integer + * will be unable to represent that timestamp, so this will fail. + */ + time_t_wrapper os_time_t = ten_years_hence; + epicsTime then = os_time_t; // No fractional seconds + double delta = ten_years_hence - then; + + testOk(delta >= 0 && delta < 1.0, + "OS time_t can represent 10 years hence"); + } + catch ( ... ) { + testFail("OS time_t conversion exception for value 10 years hence"); + } + return testDone(); } From a1dc16848c8ab0ff26501060873fde0bd1e6d6dc Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 14 Jun 2017 10:03:43 -0500 Subject: [PATCH 6/6] configure: Fix include CONFIG_APP_INCLUDE which needs to happen *after* CONFIG_SITE overrides. --- configure/CONFIG | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/configure/CONFIG b/configure/CONFIG index 24efbff86..6fe6b9b55 100644 --- a/configure/CONFIG +++ b/configure/CONFIG @@ -75,17 +75,17 @@ ifdef T_A # -include $(CONFIG)/os/CONFIG.$(EPICS_HOST_ARCH).$(T_A) + # Site specific target and host-target definitions and overrides + # + -include $(CONFIG)/os/CONFIG_SITE.Common.$(T_A) + -include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + # RELEASE file specific definitions # ifneq ($(CONFIG),$(TOP)/configure) -include $(CONFIG)/CONFIG_APP_INCLUDE endif - # Site specific target and host-target definitions - # - -include $(CONFIG)/os/CONFIG_SITE.Common.$(T_A) - -include $(CONFIG)/os/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) - endif # ifdef T_A