Call path below SIGALRM isn't safe

We do allocations, open files, printf, etc from the SIGALRM signal
handler which gets run every 250 msecs. This isn't necessarily
safe and could deadlock. Move it to thread context instead.

Signed-off-by: Jens Axboe <jaxboe@fusionio.com>
diff --git a/eta.c b/eta.c
index 81dbfa7..608e0dd 100644
--- a/eta.c
+++ b/eta.c
@@ -328,7 +328,11 @@
 	}
 
 	disp_time = mtime_since(&disp_prev_time, &now);
-	if (disp_time < 1000)
+
+	/*
+	 * Allow a little slack, the target is to print it every 1000 msecs
+	 */
+	if (disp_time < 900)
 		return;
 
 	calc_rate(disp_time, io_bytes, disp_io_bytes, rate);
diff --git a/fio.c b/fio.c
index d20fc24..91bf6b6 100644
--- a/fio.c
+++ b/fio.c
@@ -28,6 +28,7 @@
 #include <time.h>
 #include <locale.h>
 #include <assert.h>
+#include <time.h>
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/ipc.h>
@@ -62,7 +63,7 @@
 static struct fio_mutex *writeout_mutex;
 static volatile int fio_abort;
 static int exit_value;
-static struct itimerval itimer;
+static timer_t ival_timer;
 static pthread_t gtod_thread;
 static struct flist_head *cgroup_list;
 static char *cgroup_mnt;
@@ -113,17 +114,21 @@
 
 static void status_timer_arm(void)
 {
-	itimer.it_value.tv_sec = 0;
-	itimer.it_value.tv_usec = DISK_UTIL_MSEC * 1000;
-	setitimer(ITIMER_REAL, &itimer, NULL);
+	struct itimerspec value;
+
+	value.it_value.tv_sec = 0;
+	value.it_value.tv_nsec = DISK_UTIL_MSEC * 1000000;
+	value.it_interval.tv_sec = 0;
+	value.it_interval.tv_nsec = DISK_UTIL_MSEC * 1000000;
+
+	timer_settime(ival_timer, 0, &value, NULL);
 }
 
-static void sig_alrm(int fio_unused sig)
+static void ival_fn(union sigval sig)
 {
 	if (threads) {
 		update_io_ticks();
 		print_thread_status();
-		status_timer_arm();
 	}
 }
 
@@ -143,16 +148,28 @@
 	}
 }
 
+static void posix_timer_teardown(void)
+{
+	timer_delete(ival_timer);
+}
+
+static void posix_timer_setup(void)
+{
+	struct sigevent evt;
+
+	memset(&evt, 0, sizeof(evt));
+	evt.sigev_notify = SIGEV_THREAD;
+	evt.sigev_notify_function = ival_fn;
+
+	if (timer_create(CLOCK_MONOTONIC, &evt, &ival_timer) < 0)
+		perror("timer_create");
+}
+
 static void set_sig_handlers(void)
 {
 	struct sigaction act;
 
 	memset(&act, 0, sizeof(act));
-	act.sa_handler = sig_alrm;
-	act.sa_flags = SA_RESTART;
-	sigaction(SIGALRM, &act, NULL);
-
-	memset(&act, 0, sizeof(act));
 	act.sa_handler = sig_int;
 	act.sa_flags = SA_RESTART;
 	sigaction(SIGINT, &act, NULL);
@@ -1689,6 +1706,7 @@
 
 	set_genesis_time();
 
+	posix_timer_setup();
 	status_timer_arm();
 
 	cgroup_list = smalloc(sizeof(*cgroup_list));
@@ -1709,6 +1727,7 @@
 	sfree(cgroup_list);
 	sfree(cgroup_mnt);
 
+	posix_timer_teardown();
 	fio_mutex_remove(startup_mutex);
 	fio_mutex_remove(writeout_mutex);
 	return exit_value;