From 78b66d32c2952d13d1ba73a2e2c15739585535a9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 31 Dec 2019 16:23:32 -0800 Subject: [PATCH] Use CLOCK_MONOTONIC for condition variables used by pthread_cond_timedwait() 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 --- configure | 22 +++++++++++++++++++++ fio_sem.c | 11 +++++++---- helper_thread.c | 17 +++++++++------- idletime.c | 16 +++++++++++++-- pshared.c | 9 +++++++++ t/read-to-pipe-async.c | 44 +++++++++++++++++++++++++++++++----------- 6 files changed, 95 insertions(+), 24 deletions(-) diff --git a/configure b/configure index a1279693..9020b158 100755 --- 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 < +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 diff --git a/fio_sem.c b/fio_sem.c index 3b48061c..c34d8bf7 100644 --- 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); diff --git a/helper_thread.c b/helper_thread.c index f0c717f5..eba2898a 100644 --- a/helper_thread.c +++ b/helper_thread.c @@ -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)); diff --git a/idletime.c b/idletime.c index 2f59f510..fc1df8e9 100644 --- a/idletime.c +++ b/idletime.c @@ -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); } diff --git a/pshared.c b/pshared.c index 74812ede..21192556 100644 --- 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)); diff --git a/t/read-to-pipe-async.c b/t/read-to-pipe-async.c index ebdd8f10..03fe9ea4 100644 --- a/t/read-to-pipe-async.c +++ b/t/read-to-pipe-async.c @@ -20,6 +20,7 @@ * Copyright (C) 2016 Jens Axboe * */ + #include #include #include @@ -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; -- 2.25.1