From d1ddbad053cf092e70c593a67fdd41494005eda7 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 18 May 2021 12:24:07 +0100 Subject: [PATCH] Fix issue with very large timeout passed to epicsEventWaitWithTimeout() A very large timeout was getting converted to a 0 wait and causing some unit tests to fail in strange and random ways. Not trapping large timeouts was an oversight when converting to waitable timers on WIN32 --- src/libCom/osi/os/WIN32/osdEvent.c | 14 ++++++++++++-- src/libCom/osi/os/WIN32/osdThread.c | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libCom/osi/os/WIN32/osdEvent.c b/src/libCom/osi/os/WIN32/osdEvent.c index fb67d6c79..e39608255 100644 --- a/src/libCom/osi/os/WIN32/osdEvent.c +++ b/src/libCom/osi/os/WIN32/osdEvent.c @@ -92,17 +92,27 @@ epicsShareFunc epicsEventStatus epicsEventWait ( epicsEventId pSem ) epicsShareFunc epicsEventStatus epicsEventWaitWithTimeout ( epicsEventId pSem, double timeOut ) { - static const unsigned nSec100PerSec = 10000000u; + /* waitable timers use 100 nanosecond intervals, like FILETIME */ + static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */ + static const unsigned mSecPerSec = 1000u; /* milliseconds per second */ HANDLE handles[2]; DWORD status; LARGE_INTEGER tmo; HANDLE timer; + LONGLONG nIvals; /* number of intervals */ if ( timeOut <= 0.0 ) { tmo.QuadPart = 0u; } + else if ( timeOut >= INFINITE / mSecPerSec ) { + /* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds, + to be compatible with previous WaitForSingleObject() implementation */ + nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec); + tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */ + } else { - tmo.QuadPart = -((LONGLONG)(timeOut * nSec100PerSec + 0.5)); + nIvals = (LONGLONG)(timeOut * ivalPerSec + 0.999999); + tmo.QuadPart = -nIvals; } if (tmo.QuadPart < 0) { diff --git a/src/libCom/osi/os/WIN32/osdThread.c b/src/libCom/osi/os/WIN32/osdThread.c index 0057ee953..092432e71 100644 --- a/src/libCom/osi/os/WIN32/osdThread.c +++ b/src/libCom/osi/os/WIN32/osdThread.c @@ -807,15 +807,25 @@ HANDLE osdThreadGetTimer() */ epicsShareFunc void epicsShareAPI epicsThreadSleep ( double seconds ) { - static const unsigned nSec100PerSec = 10000000u; + /* waitable timers use 100 nanosecond intervals, like FILETIME */ + static const unsigned ivalPerSec = 10000000u; /* number of 100ns intervals per second */ + static const unsigned mSecPerSec = 1000u; /* milliseconds per second */ LARGE_INTEGER tmo; HANDLE timer; + LONGLONG nIvals; /* number of intervals */ if ( seconds <= 0.0 ) { tmo.QuadPart = 0u; } + else if ( seconds >= INFINITE / mSecPerSec ) { + /* we need to apply a maximum wait time to stop an overflow. We choose (INFINITE - 1) milliseconds, + to be compatible with previous WaitForSingleObject() implementation */ + nIvals = (LONGLONG)(INFINITE - 1) * (ivalPerSec / mSecPerSec); + tmo.QuadPart = -nIvals; /* negative value means a relative time offset for timer */ + } else { - tmo.QuadPart = -((LONGLONG)(seconds * nSec100PerSec + 0.5)); + nIvals = (LONGLONG)(seconds * ivalPerSec + 0.999999); + tmo.QuadPart = -nIvals; } if (tmo.QuadPart == 0) {