threads_posix: Use monotonic clock for condition variables where possible
The pthread_condattr_setclock() function allows one to specify that the
condition variable use CLOCK_MONOTONIC as the base for timed waits. This
is desirable to avoid premature timeouts if the system time is adjusted
while a timed wait is occurring. Add a check for the availability of
this function and use it where possible.
Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
diff --git a/configure.ac b/configure.ac
index ef6927d..041eab8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -202,7 +202,11 @@
AC_CHECK_FUNCS([clock_gettime], [have_clock_gettime=yes], [have_clock_gettime=])
if test "x$have_clock_gettime" = xyes; then
AC_CHECK_DECL([CLOCK_MONOTONIC], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_MONOTONIC])], [[#include <time.h>]])
- AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]])
+ dnl use the monotonic clock for condition variable timed waits if possible
+ AC_CHECK_FUNCS([pthread_condattr_setclock], [need_clock_realtime=], [need_clock_realtime=yes])
+ if test "x$need_clock_realtime" = xyes; then
+ AC_CHECK_DECL([CLOCK_REALTIME], [], [AC_MSG_ERROR([C library headers missing definition for CLOCK_REALTIME])], [[#include <time.h>]])
+ fi
elif test "x$backend" != xdarwin; then
AC_MSG_ERROR([clock_gettime() is required on this platform])
fi
diff --git a/libusb/os/threads_posix.c b/libusb/os/threads_posix.c
index c1745b3..0e0e221 100644
--- a/libusb/os/threads_posix.c
+++ b/libusb/os/threads_posix.c
@@ -39,13 +39,31 @@
# include <sys/lwp.h>
#endif
+void usbi_cond_init(pthread_cond_t *cond)
+{
+#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
+ pthread_condattr_t condattr;
+
+ PTHREAD_CHECK(pthread_condattr_init(&condattr));
+ PTHREAD_CHECK(pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC));
+ PTHREAD_CHECK(pthread_cond_init(cond, &condattr));
+ PTHREAD_CHECK(pthread_condattr_destroy(&condattr));
+#else
+ PTHREAD_CHECK(pthread_cond_init(cond, NULL));
+#endif
+}
+
int usbi_cond_timedwait(pthread_cond_t *cond,
pthread_mutex_t *mutex, const struct timeval *tv)
{
struct timespec timeout;
int r;
+#ifdef HAVE_PTHREAD_CONDATTR_SETCLOCK
+ usbi_get_monotonic_time(&timeout);
+#else
usbi_get_real_time(&timeout);
+#endif
timeout.tv_sec += tv->tv_sec;
timeout.tv_nsec += tv->tv_usec * 1000L;
diff --git a/libusb/os/threads_posix.h b/libusb/os/threads_posix.h
index e187c69..8a59fe2 100644
--- a/libusb/os/threads_posix.h
+++ b/libusb/os/threads_posix.h
@@ -63,10 +63,7 @@
}
typedef pthread_cond_t usbi_cond_t;
-static inline void usbi_cond_init(pthread_cond_t *cond)
-{
- PTHREAD_CHECK(pthread_cond_init(cond, NULL));
-}
+void usbi_cond_init(pthread_cond_t *cond);
static inline void usbi_cond_wait(usbi_cond_t *cond, usbi_mutex_t *mutex)
{
PTHREAD_CHECK(pthread_cond_wait(cond, mutex));
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 2c1248a..c859d43 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11558
+#define LIBUSB_NANO 11559