diff --git a/src/essos/pxTimerNative.cpp b/src/essos/pxTimerNative.cpp old mode 100755 new mode 100644 index b3ed6da52b..b6c06c17a6 --- a/src/essos/pxTimerNative.cpp +++ b/src/essos/pxTimerNative.cpp @@ -18,9 +18,12 @@ limitations under the License. // pxTimerNative.cpp +#if __cplusplus < 201103L + #include "../pxTimer.h" #include +#include #define USE_CGT @@ -69,10 +72,39 @@ double pxMicroseconds() #endif } +void pxSleepUS(uint64_t usToSleep) +{ + struct timespec res; + + res.tv_sec = (usToSleep / 1000000UL); + res.tv_nsec = (usToSleep * 1000UL) % 1000000000UL; + + while (true) + { + struct timespec remain; + const int rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &res, &remain); + + if (rv == 0) + { + break; + } + + if (errno == EINTR) + { + res = remain; + continue; + } + + // Theoretically impossible case in our case :-) + // At this point something went wrong but we cannot + // return any error code as pxSleepMS returns void. + abort(); + } +} + void pxSleepMS(uint32_t msToSleep) { - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000 * msToSleep; - select(0, NULL, NULL, NULL, &tv); + pxSleepUS(msToSleep * 1000UL); } + +#endif // __cplusplus < 201103L diff --git a/src/gles/pxTimerNative.cpp b/src/gles/pxTimerNative.cpp index b3ed6da52b..b6c06c17a6 100644 --- a/src/gles/pxTimerNative.cpp +++ b/src/gles/pxTimerNative.cpp @@ -18,9 +18,12 @@ limitations under the License. // pxTimerNative.cpp +#if __cplusplus < 201103L + #include "../pxTimer.h" #include +#include #define USE_CGT @@ -69,10 +72,39 @@ double pxMicroseconds() #endif } +void pxSleepUS(uint64_t usToSleep) +{ + struct timespec res; + + res.tv_sec = (usToSleep / 1000000UL); + res.tv_nsec = (usToSleep * 1000UL) % 1000000000UL; + + while (true) + { + struct timespec remain; + const int rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &res, &remain); + + if (rv == 0) + { + break; + } + + if (errno == EINTR) + { + res = remain; + continue; + } + + // Theoretically impossible case in our case :-) + // At this point something went wrong but we cannot + // return any error code as pxSleepMS returns void. + abort(); + } +} + void pxSleepMS(uint32_t msToSleep) { - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000 * msToSleep; - select(0, NULL, NULL, NULL, &tv); + pxSleepUS(msToSleep * 1000UL); } + +#endif // __cplusplus < 201103L diff --git a/src/glut/pxTimerNative.cpp b/src/glut/pxTimerNative.cpp index f91dd0a931..263d872bdc 100644 --- a/src/glut/pxTimerNative.cpp +++ b/src/glut/pxTimerNative.cpp @@ -18,11 +18,14 @@ limitations under the License. // pxTimerNative.cpp -#include "../pxTimer.h" +#if __cplusplus < 201103L -#include "pxConfigNative.h" +#include "../pxTimer.h" #include +#include + +#include "pxConfigNative.h" #ifndef USE_CGT #include @@ -30,60 +33,78 @@ limitations under the License. #include #endif -#ifdef USE_SELECT_FOR_SLEEP -#include -#else -#include -#endif - double pxSeconds() { #ifndef USE_CGT - timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec + ((double)tv.tv_usec/1000000); + timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec + ((double)tv.tv_usec/1000000); #else - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ts.tv_sec + ((double)ts.tv_nsec/1000000000); + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec + ((double)ts.tv_nsec/1000000000); #endif } double pxMilliseconds() { #ifndef USE_CGT - timeval tv; - gettimeofday(&tv, NULL); - return ((double)(tv.tv_sec * 1000) + ((double)tv.tv_usec/1000)); + timeval tv; + gettimeofday(&tv, NULL); + return ((double)(tv.tv_sec * 1000) + ((double)tv.tv_usec/1000)); #else - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ((double)(ts.tv_sec * 1000) + ((double)ts.tv_nsec/1000000)); + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ((double)(ts.tv_sec * 1000) + ((double)ts.tv_nsec/1000000)); #endif } double pxMicroseconds() { #ifndef USE_CGT - timeval tv; - gettimeofday(&tv, NULL); - return (tv.tv_sec * 1000000) + tv.tv_usec; + timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec * 1000000) + tv.tv_usec; #else - timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - return ((double)(ts.tv_sec * 1000000) + ((double)ts.tv_nsec/1000)); + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ((double)(ts.tv_sec * 1000000) + ((double)ts.tv_nsec/1000)); #endif } +void pxSleepUS(uint64_t usToSleep) +{ + struct timespec res; + + res.tv_sec = (usToSleep / 1000000UL); + res.tv_nsec = (usToSleep * 1000UL) % 1000000000UL; + + while (true) + { + struct timespec remain; + const int rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &res, &remain); + + if (rv == 0) + { + break; + } + + if (errno == EINTR) + { + res = remain; + continue; + } + + // Theoretically impossible case in our case :-) + // At this point something went wrong but we cannot + // return any error code as pxSleepMS returns void. + abort(); + } +} + void pxSleepMS(uint32_t msToSleep) { -#ifdef USE_SELECT_FOR_SLEEP - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000 * msToSleep; - select(0, NULL, NULL, NULL, &tv); -#else - useconds_t s = (useconds_t)msToSleep*1000; - usleep(s); -#endif + pxSleepUS(msToSleep * 1000UL); } + +#endif // __cplusplus < 201103L diff --git a/src/mac/pxTimerNative.mm b/src/mac/pxTimerNative.mm index 1493af7e95..e246e80037 100644 --- a/src/mac/pxTimerNative.mm +++ b/src/mac/pxTimerNative.mm @@ -1,7 +1,9 @@ -// pxCore CopyRight 2005-2007 John Robinson +// pxCore CopyRight 2005-2018 John Robinson // Portable Framebuffer and Windowing Library // pxTimerNative.cpp +#if __cplusplus < 201103L + #include "pxTimer.h" #if 0 @@ -60,7 +62,14 @@ #endif } +void pxSleepUS(uint64_t usToSleep) +{ + usleep(usToSleep); +} + void pxSleepMS(uint32_t msToSleep) { - usleep(msToSleep*1000); + pxSleepUS(msToSleep*(uint64_t)1000); } + +#endif // __cplusplus < 201103L diff --git a/src/pxTimer.h b/src/pxTimer.h index 54ffd657b4..e7ee098a32 100644 --- a/src/pxTimer.h +++ b/src/pxTimer.h @@ -23,10 +23,47 @@ #include -double pxSeconds(); -double pxMilliseconds(); -double pxMicroseconds(); +#if __cplusplus >= 201103L // { + // Common implementation for all modern platforms supporting >= c++11 -void pxSleepMS(uint32_t msToSleep); +# include +# include +# include -#endif + inline double pxMicroseconds() + { + const auto t_now = std::chrono::steady_clock::now(); + const auto t_us = std::chrono::time_point_cast(t_now).time_since_epoch(); + return t_us.count(); + } + + inline double pxMilliseconds() + { + return pxMicroseconds() / 1000.0; + } + + inline double pxSeconds() + { + return pxMilliseconds() / 1000.0; + } + + inline void pxSleepUS(const uint64_t usToSleep) + { + std::this_thread::sleep_for(std::chrono::microseconds(usToSleep)); + } + + inline void pxSleepMS(const uint32_t msToSleep) + { + pxSleepUS(msToSleep * 1000UL); + } +#else // }{ + // Legacy, platform specific, implementation for old platforms not supporting c++11 + double pxMicroseconds(); + double pxMilliseconds(); + double pxSeconds(); + + void pxSleepMS(uint32_t msToSleep); + void pxSleepUS(uint64_t usToSleep); +#endif // } __cplusplus >= 201103L + +#endif // PX_TIMER_H diff --git a/src/wayland/pxTimerNative.cpp b/src/wayland/pxTimerNative.cpp old mode 100755 new mode 100644 index b3ed6da52b..b6c06c17a6 --- a/src/wayland/pxTimerNative.cpp +++ b/src/wayland/pxTimerNative.cpp @@ -18,9 +18,12 @@ limitations under the License. // pxTimerNative.cpp +#if __cplusplus < 201103L + #include "../pxTimer.h" #include +#include #define USE_CGT @@ -69,10 +72,39 @@ double pxMicroseconds() #endif } +void pxSleepUS(uint64_t usToSleep) +{ + struct timespec res; + + res.tv_sec = (usToSleep / 1000000UL); + res.tv_nsec = (usToSleep * 1000UL) % 1000000000UL; + + while (true) + { + struct timespec remain; + const int rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &res, &remain); + + if (rv == 0) + { + break; + } + + if (errno == EINTR) + { + res = remain; + continue; + } + + // Theoretically impossible case in our case :-) + // At this point something went wrong but we cannot + // return any error code as pxSleepMS returns void. + abort(); + } +} + void pxSleepMS(uint32_t msToSleep) { - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000 * msToSleep; - select(0, NULL, NULL, NULL, &tv); + pxSleepUS(msToSleep * 1000UL); } + +#endif // __cplusplus < 201103L diff --git a/src/wayland_egl/pxTimerNative.cpp b/src/wayland_egl/pxTimerNative.cpp old mode 100755 new mode 100644 index b3ed6da52b..b6c06c17a6 --- a/src/wayland_egl/pxTimerNative.cpp +++ b/src/wayland_egl/pxTimerNative.cpp @@ -18,9 +18,12 @@ limitations under the License. // pxTimerNative.cpp +#if __cplusplus < 201103L + #include "../pxTimer.h" #include +#include #define USE_CGT @@ -69,10 +72,39 @@ double pxMicroseconds() #endif } +void pxSleepUS(uint64_t usToSleep) +{ + struct timespec res; + + res.tv_sec = (usToSleep / 1000000UL); + res.tv_nsec = (usToSleep * 1000UL) % 1000000000UL; + + while (true) + { + struct timespec remain; + const int rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &res, &remain); + + if (rv == 0) + { + break; + } + + if (errno == EINTR) + { + res = remain; + continue; + } + + // Theoretically impossible case in our case :-) + // At this point something went wrong but we cannot + // return any error code as pxSleepMS returns void. + abort(); + } +} + void pxSleepMS(uint32_t msToSleep) { - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000 * msToSleep; - select(0, NULL, NULL, NULL, &tv); + pxSleepUS(msToSleep * 1000UL); } + +#endif // __cplusplus < 201103L diff --git a/src/wayland_egl/pxWindowNative.cpp b/src/wayland_egl/pxWindowNative.cpp index 1e58670a7a..7ee7d00fef 100755 --- a/src/wayland_egl/pxWindowNative.cpp +++ b/src/wayland_egl/pxWindowNative.cpp @@ -545,7 +545,7 @@ void pxWindowNative::runEventLoopOnce() pxWindowNative* w = (*i); w->animateAndRender(); } - usleep(1000); //TODO - find out why pxSleepMS causes a crash on some devices + pxSleepMS(1); } @@ -579,7 +579,7 @@ void pxWindowNative::runEventLoop() int pollResult = 0; int pollTimeout = 1000 / framerate; #endif //PXCORE_WL_DISPLAY_READ_EVENTS - double maxSleepTime = (1000 / framerate) * 1000; + const double maxSleepTime = (1000.0 / framerate) * 1000; rtLogInfo("max sleep time in microseconds: %f", maxSleepTime); while(!exitFlag) { @@ -605,15 +605,12 @@ void pxWindowNative::runEventLoop() #endif //PXCORE_WL_DISPLAY_READ_EVENTS wl_display_dispatch_pending(display->display); - double processTime = (int)pxMicroseconds() - (int)startMicroseconds; - if (processTime < 0) - { - processTime = 0; - } + const double processTime = pxMicroseconds() - startMicroseconds; + if (processTime < maxSleepTime) { - int sleepTime = (int)maxSleepTime-(int)processTime; - usleep(sleepTime); + const double sleepTime = maxSleepTime - (processTime > 0.0 ? processTime : 0.0); + pxSleepUS(sleepTime); } } } diff --git a/src/win/pxTimerNative.cpp b/src/win/pxTimerNative.cpp old mode 100755 new mode 100644 index 42f25df579..677cd92cbb --- a/src/win/pxTimerNative.cpp +++ b/src/win/pxTimerNative.cpp @@ -18,8 +18,11 @@ limitations under the License. // pxTimerNative.cpp +#if __cplusplus < 201103L + #include #include +#include static bool gFreqInitialized = false; static LARGE_INTEGER gFreq; @@ -66,7 +69,14 @@ double pxMicroseconds() return (c.QuadPart * 1000000) / (double)gFreq.QuadPart; } -void pxSleepMS(uint32_t sleepMS) +void pxSleepUS(uint64_t usToSleep) { - Sleep(sleepMS); + abort(); // simply not implemented } + +void pxSleepMS(uint32_t msToSleep) +{ + Sleep(msToSleep); +} + +#endif // __cplusplus < 201103L diff --git a/src/x11/pxTimerNative.cpp b/src/x11/pxTimerNative.cpp index 6d586c5475..b200b85e75 100644 --- a/src/x11/pxTimerNative.cpp +++ b/src/x11/pxTimerNative.cpp @@ -18,9 +18,12 @@ limitations under the License. // pxTimerNative.cpp +#if __cplusplus < 201103L + #include "../pxTimer.h" #include +#include #define USE_CGT @@ -69,29 +72,41 @@ double pxMicroseconds() #endif } - -#if 1 - -void pxSleepMS(uint32_t msToSleep) +void pxSleepUS(uint64_t usToSleep) { - uint32_t ms = msToSleep; - struct timespec res; - res.tv_sec = (ms / 1000); - res.tv_nsec = (ms * 1000000) % 1000000000; - - clock_nanosleep(CLOCK_MONOTONIC, 0, &res, NULL); + res.tv_sec = (usToSleep / 1000000UL); + res.tv_nsec = (usToSleep * 1000UL) % 1000000000UL; + + while (true) + { + struct timespec remain; + const int rv = clock_nanosleep(CLOCK_MONOTONIC, 0, &res, &remain); + + if (rv == 0) + { + break; + } + + if (errno == EINTR) + { + res = remain; + continue; + } + + // Theoretically impossible case in our case :-) + // At this point something went wrong but we cannot + // return any error code as pxSleepMS returns void. + abort(); + } } #else void pxSleepMS(uint32_t msToSleep) { - timeval tv; - tv.tv_sec = 0; - tv.tv_usec = 1000 * msToSleep; - select(0, NULL, NULL, NULL, &tv); + pxSleepUS(msToSleep * 1000UL); } -#endif +#endif // __cplusplus < 201103L diff --git a/tests/pxScene2d/test_pxTimerNative.cpp b/tests/pxScene2d/test_pxTimerNative.cpp index a0d5a2ada1..7d4d156277 100644 --- a/tests/pxScene2d/test_pxTimerNative.cpp +++ b/tests/pxScene2d/test_pxTimerNative.cpp @@ -39,22 +39,22 @@ class pxTimerNativeTest : public testing::Test double startTime = 0.0; double endTime = 0.0; double opTime = 0.0; - + opTime = pxSeconds(); EXPECT_TRUE(opTime > 0); - + opTime = pxMilliseconds(); EXPECT_TRUE(opTime > 0); - + opTime = pxMicroseconds(); EXPECT_TRUE(opTime > 0); - - startTime = pxSeconds(); - pxSleepMS(TEST_TIME * 1000); - endTime = pxSeconds(); - EXPECT_TRUE((int)(endTime - startTime) == TEST_TIME); - } + startTime = pxMilliseconds(); + const uint32_t toWaitMS = TEST_TIME * 1000; + pxSleepMS(toWaitMS); + endTime = pxMilliseconds(); + EXPECT_TRUE((uint32_t)(endTime - startTime) >= toWaitMS); + } }; TEST_F(pxTimerNativeTest, pxTimerNativeTestS)