Ensure that stat outputs are serialized
authorJens Axboe <axboe@kernel.dk>
Fri, 26 Apr 2013 23:05:57 +0000 (17:05 -0600)
committerJens Axboe <axboe@kernel.dk>
Fri, 26 Apr 2013 23:05:57 +0000 (17:05 -0600)
Two issues:

- We don't want potentially two stat outputs running at the same time.
  This could potentially happen if USR1 or interval stats race with
  the thread exit.

- We could potentially crash if the interval or USR1 signaled stat
  output trigger when fio is tearing down. Let the main thread wait
  for any in-progress output in that case.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
backend.c
stat.c
stat.h

index 4d4e8efda0601f43e5400163b56af2e16f2e4110..89ffee1277f5ad47f733b56e9bf5c86ad9b39fc8 100644 (file)
--- a/backend.c
+++ b/backend.c
@@ -1895,6 +1895,7 @@ int fio_backend(void)
                return 1;
 
        set_genesis_time();
+       stat_init();
        create_disk_util_thread();
 
        cgroup_list = smalloc(sizeof(*cgroup_list));
@@ -1924,5 +1925,6 @@ int fio_backend(void)
        fio_mutex_remove(startup_mutex);
        fio_mutex_remove(writeout_mutex);
        fio_mutex_remove(disk_thread_mutex);
+       stat_exit();
        return exit_value;
 }
diff --git a/stat.c b/stat.c
index 03a45fc70a197562cc09c2a21d1fbf9f645c3867..b3861887e2a204b404acb9c043f1c7302a7c32be 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -14,6 +14,8 @@
 #include "lib/getrusage.h"
 #include "idletime.h"
 
+static struct fio_mutex *stat_mutex;
+
 void update_rusage_stat(struct thread_data *td)
 {
        struct thread_stat *ts = &td->ts;
@@ -1141,7 +1143,7 @@ void init_thread_stat(struct thread_stat *ts)
        ts->groupid = -1;
 }
 
-void show_run_stats(void)
+static void __show_run_stats(void)
 {
        struct group_run_stats *runstats, *rs;
        struct thread_data *td;
@@ -1359,6 +1361,13 @@ void show_run_stats(void)
        free(threadstats);
 }
 
+void show_run_stats(void)
+{
+       fio_mutex_down(stat_mutex);
+       __show_run_stats();
+       fio_mutex_up(stat_mutex);
+}
+
 static void *__show_running_run_stats(void fio_unused *arg)
 {
        struct thread_data *td;
@@ -1393,7 +1402,7 @@ static void *__show_running_run_stats(void fio_unused *arg)
                td->update_rusage = 0;
        }
 
-       show_run_stats();
+       __show_run_stats();
 
        for_each_td(td, i) {
                if (td_read(td) && td->io_bytes[DDIR_READ])
@@ -1405,6 +1414,7 @@ static void *__show_running_run_stats(void fio_unused *arg)
        }
 
        free(rt);
+       fio_mutex_up(stat_mutex);
        return NULL;
 }
 
@@ -1417,8 +1427,14 @@ void show_running_run_stats(void)
 {
        pthread_t thread;
 
-       pthread_create(&thread, NULL, __show_running_run_stats, NULL);
-       pthread_detach(thread);
+       fio_mutex_down(stat_mutex);
+
+       if (!pthread_create(&thread, NULL, __show_running_run_stats, NULL)) {
+               pthread_detach(thread);
+               return;
+       }
+
+       fio_mutex_up(stat_mutex);
 }
 
 static int status_interval_init;
@@ -1701,3 +1717,18 @@ void add_iops_sample(struct thread_data *td, enum fio_ddir ddir,
 
        fio_gettime(&td->iops_sample_time, NULL);
 }
+
+void stat_init(void)
+{
+       stat_mutex = fio_mutex_init(FIO_MUTEX_UNLOCKED);
+}
+
+void stat_exit(void)
+{
+       /*
+        * When we have the mutex, we know out-of-band access to it
+        * have ended.
+        */
+       fio_mutex_down(stat_mutex);
+       fio_mutex_remove(stat_mutex);
+}
diff --git a/stat.h b/stat.h
index b1bf5dc383ac0a321fe08b823b8697eec18218a6..541b77e480d05a4ddf9a4f98b14d02f6b7129a97 100644 (file)
--- a/stat.h
+++ b/stat.h
@@ -199,6 +199,9 @@ struct jobs_eta {
        uint8_t run_str[];
 };
 
+extern void stat_init(void);
+extern void stat_exit(void);
+
 extern void show_thread_status(struct thread_stat *ts, struct group_run_stats *rs);
 extern void show_group_stats(struct group_run_stats *rs);
 extern int calc_thread_status(struct jobs_eta *je, int force);