From 564de8d10188bc855343f915ca9fdbbf9c722465 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 16 Mar 2018 08:38:34 -0700 Subject: [PATCH] Signal td->free_cond with the associated mutex held Calling pthread_cond_signal() or pthread_cond_broadcast() without holding the associated mutex can lead to missed wakeups. Hence ensure that td->io_u_lock is held around pthread_cond_signal(&td->free_cond) calls. A quote from the POSIX spec (http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html): "The pthread_cond_broadcast() or pthread_cond_signal() functions may be called by a thread whether or not it currently owns the mutex that threads calling pthread_cond_wait() or pthread_cond_timedwait() have associated with the condition variable during their waits; however, if predictable scheduling behavior is required, then that mutex shall be locked by the thread calling pthread_cond_broadcast() or pthread_cond_signal()." Signed-off-by: Bart Van Assche --- io_u.c | 4 ++-- verify.c | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/io_u.c b/io_u.c index 84d93155..f3b59322 100644 --- a/io_u.c +++ b/io_u.c @@ -856,8 +856,8 @@ void put_io_u(struct thread_data *td, struct io_u *io_u) assert(!(td->flags & TD_F_CHILD)); } io_u_qpush(&td->io_u_freelist, io_u); - td_io_u_unlock(td); td_io_u_free_notify(td); + td_io_u_unlock(td); } void clear_io_u(struct thread_data *td, struct io_u *io_u) @@ -889,8 +889,8 @@ void requeue_io_u(struct thread_data *td, struct io_u **io_u) } io_u_rpush(&td->io_u_requeues, __io_u); - td_io_u_unlock(td); td_io_u_free_notify(td); + td_io_u_unlock(td); *io_u = NULL; } diff --git a/verify.c b/verify.c index 17af3bb9..d10670bb 100644 --- a/verify.c +++ b/verify.c @@ -1454,9 +1454,9 @@ static void *verify_async_thread(void *data) done: pthread_mutex_lock(&td->io_u_lock); td->nr_verify_threads--; + pthread_cond_signal(&td->free_cond); pthread_mutex_unlock(&td->io_u_lock); - pthread_cond_signal(&td->free_cond); return NULL; } @@ -1492,9 +1492,12 @@ int verify_async_init(struct thread_data *td) if (i != td->o.verify_async) { log_err("fio: only %d verify threads started, exiting\n", i); + + pthread_mutex_lock(&td->io_u_lock); td->verify_thread_exit = 1; - write_barrier(); pthread_cond_broadcast(&td->verify_cond); + pthread_mutex_unlock(&td->io_u_lock); + return 1; } @@ -1503,12 +1506,10 @@ int verify_async_init(struct thread_data *td) void verify_async_exit(struct thread_data *td) { + pthread_mutex_lock(&td->io_u_lock); td->verify_thread_exit = 1; - write_barrier(); pthread_cond_broadcast(&td->verify_cond); - pthread_mutex_lock(&td->io_u_lock); - while (td->nr_verify_threads) pthread_cond_wait(&td->free_cond, &td->io_u_lock); -- 2.25.1