From 2d02cea40c5bedb7be3426547a809dc3210d23bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A4=D0=BE=D0=BC=D0=B5=D0=BD=D0=BA=D0=BE=20=D0=A1=D1=82?= =?UTF-8?q?=D0=B5=D0=BF=D0=B0=D0=BD=20=D0=92=D0=BB=D0=B0=D0=B4=D0=B8=D0=BC?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Fri, 25 Sep 2020 12:01:53 +0300 Subject: [PATCH] Fix waitFor timeout behaviour --- libs/main/thread/piconditionvar.cpp | 35 ++++++++++++++------ tests/concurrent/BlockingDequeueUnitTest.cpp | 4 --- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/libs/main/thread/piconditionvar.cpp b/libs/main/thread/piconditionvar.cpp index 9ad6538b..f7743d0a 100644 --- a/libs/main/thread/piconditionvar.cpp +++ b/libs/main/thread/piconditionvar.cpp @@ -35,7 +35,6 @@ PRIVATE_DEFINITION_START(PIConditionVariable) CONDITION_VARIABLE nativeHandle; #else pthread_cond_t nativeHandle; - PIMutex * currentLock; #endif bool isDestroying; PRIVATE_DEFINITION_END(PIConditionVariable) @@ -46,9 +45,12 @@ PIConditionVariable::PIConditionVariable() { InitializeConditionVariable(&PRIVATE->nativeHandle); #else PRIVATE->isDestroying = false; - PRIVATE->currentLock = nullptr; - memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle)); - pthread_cond_init(&PRIVATE->nativeHandle, NULL); + + pthread_condattr_t condattr; + pthread_condattr_init(&condattr); + pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); + memset(&(PRIVATE->nativeHandle), 0, sizeof(PRIVATE->nativeHandle)); + pthread_cond_init(&PRIVATE->nativeHandle, &condattr); #endif } @@ -84,23 +86,38 @@ void PIConditionVariable::wait(PIMutex& lk, const std::function& conditi } } +void timespec_add_ms(timespec* ts, int ms) { + ts->tv_sec += ms / 1000; + ts->tv_nsec += ms % 1000 * 1000000; + if (ts->tv_nsec > 1000 * 1000 * 1000) { + ts->tv_sec++; + ts->tv_nsec /= 1000 * 1000 * 1000; + } +} bool PIConditionVariable::waitFor(PIMutex &lk, int timeoutMs) { bool isNotTimeout; #ifdef WINDOWS isNotTimeout = SleepConditionVariableCS(&PRIVATE->nativeHandle, (PCRITICAL_SECTION)lk.handle(), timeoutMs) != 0; #else - timespec abstime = {.tv_sec = timeoutMs / 1000, .tv_nsec = timeoutMs % 1000 * 1000000}; - isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) == 0; + timespec expire_ts; + clock_gettime(CLOCK_MONOTONIC, &expire_ts); + timespec_add_ms(&expire_ts, timeoutMs); + isNotTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) == 0; #endif if (PRIVATE->isDestroying) return false; return isNotTimeout; } - bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::function &condition) { bool isCondition; +#ifdef WINDOWS PITimeMeasurer measurer; +#else + timespec expire_ts; + clock_gettime(CLOCK_MONOTONIC, &expire_ts); + timespec_add_ms(&expire_ts, timeoutMs); +#endif while (true) { isCondition = condition(); if (isCondition) break; @@ -110,9 +127,7 @@ bool PIConditionVariable::waitFor(PIMutex& lk, int timeoutMs, const std::functio (PCRITICAL_SECTION)lk.handle(), timeoutMs - (int)measurer.elapsed_m()) == 0; #else - int timeoutCurr = timeoutMs - (int)measurer.elapsed_m(); - timespec abstime = {.tv_sec = timeoutCurr / 1000, .tv_nsec = timeoutCurr % 1000 * 1000000}; - bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &abstime) != 0; + bool isTimeout = pthread_cond_timedwait(&PRIVATE->nativeHandle, (pthread_mutex_t*)lk.handle(), &expire_ts) != 0; #endif if (isTimeout) return false; if (PRIVATE->isDestroying) return false; diff --git a/tests/concurrent/BlockingDequeueUnitTest.cpp b/tests/concurrent/BlockingDequeueUnitTest.cpp index 993326dd..8c9c8818 100644 --- a/tests/concurrent/BlockingDequeueUnitTest.cpp +++ b/tests/concurrent/BlockingDequeueUnitTest.cpp @@ -14,9 +14,7 @@ public: void wait(PIMutex& lk, const std::function& condition) override { isWaitCalled = true; - lk.lock(); isTrueCondition = condition(); - lk.unlock(); } bool waitFor(PIMutex& lk, int timeoutMs) override { @@ -27,10 +25,8 @@ public: bool waitFor(PIMutex& lk, int timeoutMs, const std::function& condition) override { isWaitForCalled = true; - lk.lock(); isTrueCondition = condition(); timeout = timeoutMs; - lk.unlock(); return isTrueCondition; } };