Use CLOCK_MONOTONIC for condition variables used by pthread_cond_timedwait()
authorBart Van Assche <bvanassche@acm.org>
Wed, 1 Jan 2020 00:23:32 +0000 (16:23 -0800)
committerBart Van Assche <bvanassche@acm.org>
Thu, 2 Jan 2020 04:16:00 +0000 (20:16 -0800)
This patch ensures that the time during which pthread_cond_timedwait()
waits is not affected by wall clock adjustments by e.g. ntpd.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
configure
fio_sem.c
helper_thread.c
idletime.c
pshared.c
t/read-to-pipe-async.c

index a1279693a550ac45ffd4da9e1c3722c17100f9ca..9020b158ab4a38c90d8fea3d16242d43cb2bfba4 100755 (executable)
--- a/configure
+++ b/configure
@@ -704,6 +704,25 @@ if compile_prog "" "$LIBS" "posix_pshared" ; then
 fi
 print_config "POSIX pshared support" "$posix_pshared"
 
+##########################################
+# POSIX pthread_condattr_setclock() probe
+if test "$pthread_condattr_setclock" != "yes" ; then
+  pthread_condattr_setclock="no"
+fi
+cat > $TMPC <<EOF
+#include <pthread.h>
+int main(void)
+{
+  pthread_condattr_t condattr;
+  pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
+  return 0;
+}
+EOF
+if compile_prog "" "$LIBS" "pthread_condattr_setclock" ; then
+  pthread_condattr_setclock=yes
+fi
+print_config "pthread_condattr_setclock() support" "$pthread_condattr_setclock"
+
 ##########################################
 # solaris aio probe
 if test "$solaris_aio" != "yes" ; then
@@ -2456,6 +2475,9 @@ fi
 if test "$posix_pshared" = "yes" ; then
   output_sym "CONFIG_PSHARED"
 fi
+if test "$pthread_condattr_setclock" = "yes" ; then
+  output_sym "CONFIG_PTHREAD_CONDATTR_SETCLOCK"
+fi
 if test "$have_asprintf" = "yes" ; then
     output_sym "CONFIG_HAVE_ASPRINTF"
 fi
index 3b48061cd266cc9f6629a5d52df0dc6e55317f54..c34d8bf76565ab7f93be9b9d2f6bbf41808f3950 100644 (file)
--- a/fio_sem.c
+++ b/fio_sem.c
@@ -85,16 +85,19 @@ static bool sem_timed_out(struct timespec *t, unsigned int msecs)
 
 int fio_sem_down_timeout(struct fio_sem *sem, unsigned int msecs)
 {
-       struct timeval tv_s;
        struct timespec base;
        struct timespec t;
        int ret = 0;
 
        assert(sem->magic == FIO_SEM_MAGIC);
 
-       gettimeofday(&tv_s, NULL);
-       base.tv_sec = t.tv_sec = tv_s.tv_sec;
-       base.tv_nsec = t.tv_nsec = tv_s.tv_usec * 1000;
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+       clock_gettime(CLOCK_MONOTONIC, &t);
+#else
+       clock_gettime(CLOCK_REALTIME, &t);
+#endif
+
+       base = t;
 
        t.tv_sec += msecs / 1000;
        t.tv_nsec += ((msecs * 1000000ULL) % 1000000000);
index f0c717f5026db994509d88f6d86d21cebc447c3a..eba2898a24b6cf22bb4ad2f58e584f8765f78f68 100644 (file)
@@ -78,15 +78,16 @@ static void *helper_thread_main(void *data)
 {
        struct helper_data *hd = data;
        unsigned int msec_to_next_event, next_log, next_ss = STEADYSTATE_MSEC;
-       struct timeval tv;
        struct timespec ts, last_du, last_ss;
        int ret = 0;
 
        sk_out_assign(hd->sk_out);
 
-       gettimeofday(&tv, NULL);
-       ts.tv_sec = tv.tv_sec;
-       ts.tv_nsec = tv.tv_usec * 1000;
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+       clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
+       clock_gettime(CLOCK_REALTIME, &ts);
+#endif
        memcpy(&last_du, &ts, sizeof(ts));
        memcpy(&last_ss, &ts, sizeof(ts));
 
@@ -101,9 +102,11 @@ static void *helper_thread_main(void *data)
                pthread_mutex_lock(&hd->lock);
                pthread_cond_timedwait(&hd->cond, &hd->lock, &ts);
 
-               gettimeofday(&tv, NULL);
-               ts.tv_sec = tv.tv_sec;
-               ts.tv_nsec = tv.tv_usec * 1000;
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+               clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
+               clock_gettime(CLOCK_REALTIME, &ts);
+#endif
 
                if (hd->reset) {
                        memcpy(&last_du, &ts, sizeof(ts));
index 2f59f5104b4152c7b156a1bd255f898eb1ba7c72..fc1df8e9d009a49059558c6ca576a6e553f304c7 100644 (file)
@@ -186,6 +186,7 @@ void fio_idle_prof_init(void)
        int i, ret;
        struct timespec ts;
        pthread_attr_t tattr;
+       pthread_condattr_t cattr;
        struct idle_prof_thread *ipt;
 
        ipc.nr_cpus = cpus_online();
@@ -194,6 +195,13 @@ void fio_idle_prof_init(void)
        if (ipc.opt == IDLE_PROF_OPT_NONE)
                return;
 
+       ret = pthread_condattr_init(&cattr);
+       assert(ret == 0);
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+       ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
+       assert(ret == 0);
+#endif
+
        if ((ret = pthread_attr_init(&tattr))) {
                log_err("fio: pthread_attr_init %s\n", strerror(ret));
                return;
@@ -239,7 +247,7 @@ void fio_idle_prof_init(void)
                        break;
                }
 
-               if ((ret = pthread_cond_init(&ipt->cond, NULL))) {
+               if ((ret = pthread_cond_init(&ipt->cond, &cattr))) {
                        ipc.status = IDLE_PROF_STATUS_ABORT;
                        log_err("fio: pthread_cond_init %s\n", strerror(ret));
                        break;
@@ -282,7 +290,11 @@ void fio_idle_prof_init(void)
                pthread_mutex_lock(&ipt->init_lock);
                while ((ipt->state != TD_EXITED) &&
                       (ipt->state!=TD_INITIALIZED)) {
-                       fio_gettime(&ts, NULL);
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+                       clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
+                       clock_gettime(CLOCK_REALTIME, &ts);
+#endif
                        ts.tv_sec += 1;
                        pthread_cond_timedwait(&ipt->cond, &ipt->init_lock, &ts);
                }
index 74812ede35ecc0ecf51f09b9c3a444ca4563110c..211925564b9fb543e4edf1d4c6a26df4bd60db21 100644 (file)
--- a/pshared.c
+++ b/pshared.c
@@ -21,6 +21,15 @@ int cond_init_pshared(pthread_cond_t *cond)
                return ret;
        }
 #endif
+
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+       ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
+       if (ret) {
+               log_err("pthread_condattr_setclock: %s\n", strerror(ret));
+               return ret;
+       }
+#endif
+
        ret = pthread_cond_init(cond, &cattr);
        if (ret) {
                log_err("pthread_cond_init: %s\n", strerror(ret));
index ebdd8f1066f7c29588f620792ad12046838f0f8c..03fe9ea464bf3a25d9d93c0150f0663aa0f5f5d5 100644 (file)
@@ -20,6 +20,7 @@
  * Copyright (C) 2016 Jens Axboe
  *
  */
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -461,8 +462,17 @@ static void show_latencies(struct stats *s, const char *msg)
 
 static void init_thread(struct thread_data *thread)
 {
-       pthread_cond_init(&thread->cond, NULL);
-       pthread_cond_init(&thread->done_cond, NULL);
+       pthread_condattr_t cattr;
+       int ret;
+
+       ret = pthread_condattr_init(&cattr);
+       assert(ret == 0);
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+       ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
+       assert(ret == 0);
+#endif
+       pthread_cond_init(&thread->cond, &cattr);
+       pthread_cond_init(&thread->done_cond, &cattr);
        pthread_mutex_init(&thread->lock, NULL);
        pthread_mutex_init(&thread->done_lock, NULL);
        thread->exit = 0;
@@ -479,12 +489,14 @@ static void exit_thread(struct thread_data *thread,
                pthread_mutex_lock(&thread->done_lock);
 
                if (fn) {
-                       struct timeval tv;
                        struct timespec ts;
 
-                       gettimeofday(&tv, NULL);
-                       ts.tv_sec = tv.tv_sec + 1;
-                       ts.tv_nsec = tv.tv_usec * 1000ULL;
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+                       clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
+                       clock_gettime(CLOCK_REALTIME, &ts);
+#endif
+                       ts.tv_sec++;
 
                        pthread_cond_timedwait(&thread->done_cond, &thread->done_lock, &ts);
                        fn(wt);
@@ -562,6 +574,7 @@ static void prune_done_entries(struct writer_thread *wt)
 
 int main(int argc, char *argv[])
 {
+       pthread_condattr_t cattr;
        struct timeval s, re, we;
        struct reader_thread *rt;
        struct writer_thread *wt;
@@ -570,6 +583,7 @@ int main(int argc, char *argv[])
        size_t bytes;
        off_t off;
        int fd, seq;
+       int ret;
 
        if (parse_options(argc, argv))
                return 1;
@@ -605,13 +619,19 @@ int main(int argc, char *argv[])
        seq = 0;
        bytes = 0;
 
+       ret = pthread_condattr_init(&cattr);
+       assert(ret == 0);
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+       ret = pthread_condattr_setclock(&cattr, CLOCK_MONOTONIC);
+       assert(ret == 0);
+#endif
+
        gettimeofday(&s, NULL);
 
        while (sb.st_size) {
                struct work_item *work;
                size_t this_len;
                struct timespec ts;
-               struct timeval tv;
 
                prune_done_entries(wt);
 
@@ -627,14 +647,16 @@ int main(int argc, char *argv[])
                work->seq = ++seq;
                work->writer = wt;
                work->reader = rt;
-               pthread_cond_init(&work->cond, NULL);
+               pthread_cond_init(&work->cond, &cattr);
                pthread_mutex_init(&work->lock, NULL);
 
                queue_work(rt, work);
 
-               gettimeofday(&tv, NULL);
-               ts.tv_sec = tv.tv_sec;
-               ts.tv_nsec = tv.tv_usec * 1000ULL;
+#ifdef CONFIG_PTHREAD_CONDATTR_SETCLOCK
+               clock_gettime(CLOCK_MONOTONIC, &ts);
+#else
+               clock_gettime(CLOCK_REALTIME, &ts);
+#endif
                ts.tv_nsec += max_us * 1000ULL;
                if (ts.tv_nsec >= 1000000000ULL) {
                        ts.tv_nsec -= 1000000000ULL;