From 3658b2b580c9e8b84058df11cdc1bfd68a5eec14 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Mon, 5 Mar 2018 08:36:10 -0800 Subject: [PATCH] Problem: pthread condvar timeouts are broken (#2967) * fix pthread condvar timeouts This fixes a race condition / hang for threadsafe sockets. Context: https://github.com/zeromq/czmq/issues/1873#issuecomment-370279244 --- src/condition_variable.hpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/condition_variable.hpp b/src/condition_variable.hpp index 73ad6a201e..e01ad41033 100644 --- a/src/condition_variable.hpp +++ b/src/condition_variable.hpp @@ -174,6 +174,13 @@ class condition_variable_t #include +#if defined(__ANDROID_API__) && __ANDROID_API__ < 21 +#define ANDROID_LEGACY +extern "C" int pthread_cond_timedwait_monotonic_np (pthread_cond_t *, + pthread_mutex_t *, + const struct timespec *); +#endif + namespace zmq { class condition_variable_t @@ -181,7 +188,12 @@ class condition_variable_t public: inline condition_variable_t () { - int rc = pthread_cond_init (&cond, NULL); + pthread_condattr_t attr; + pthread_condattr_init (&attr); +#if !defined(ZMQ_HAVE_OSX) && !defined(ANDROID_LEGACY) + pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); +#endif + int rc = pthread_cond_init (&cond, &attr); posix_assert (rc); } @@ -198,9 +210,9 @@ class condition_variable_t if (timeout_ != -1) { struct timespec timeout; -#if defined ZMQ_HAVE_OSX \ - && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12 - alt_clock_gettime (SYSTEM_CLOCK, &timeout); +#ifdef ZMQ_HAVE_OSX + timeout.tv_sec = 0; + timeout.tv_nsec = 0; #else clock_gettime (CLOCK_MONOTONIC, &timeout); #endif @@ -212,8 +224,15 @@ class condition_variable_t timeout.tv_sec++; timeout.tv_nsec -= 1000000000; } - +#ifdef ZMQ_HAVE_OSX + rc = pthread_cond_timedwait_relative_np ( + &cond, mutex_->get_mutex (), &timeout); +#elif defined(ANDROID_LEGACY) + rc = pthread_cond_timedwait_monotonic_np ( + &cond, mutex_->get_mutex (), &timeout); +#else rc = pthread_cond_timedwait (&cond, mutex_->get_mutex (), &timeout); +#endif } else rc = pthread_cond_wait (&cond, mutex_->get_mutex ());