From 2819d7ea3d856dd7e9b2b1fc508b66c9cbbccd95 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Wed, 14 Jun 2017 10:01:23 -0500 Subject: [PATCH] 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(); }