+ res = select(max(fd, timerfd) + 1, &rfds, NULL, &efds,
+ timerfd >= 0 ? NULL : &timeout);
+ if (res < 0) {
+ log_err("fio: select() call in helper thread failed: %s",
+ strerror(errno));
+ return A_EXIT;
+ }
+ if (FD_ISSET(fd, &rfds))
+ read_from_pipe(fd, &action, sizeof(action));
+ if (timerfd >= 0 && FD_ISSET(timerfd, &rfds)) {
+ res = read(timerfd, &exp, sizeof(exp));
+ assert(res == sizeof(exp));
+ }
+ return action;
+}
+
+/*
+ * Verify whether or not timer @it has expired. If timer @it has expired, call
+ * @it->func(). @now is the current time. @msec_to_next_event is an
+ * input/output parameter that represents the time until the next event.
+ */
+static int eval_timer(struct interval_timer *it, const struct timespec *now,
+ unsigned int *msec_to_next_event)
+{
+ int64_t delta_ms;
+ bool expired;
+
+ /* interval == 0 means that the timer is disabled. */
+ if (it->interval_ms == 0)
+ return 0;
+
+ delta_ms = rel_time_since(now, &it->expires);
+ expired = delta_ms <= sleep_accuracy_ms;
+ if (expired) {
+ timespec_add_msec(&it->expires, it->interval_ms);
+ delta_ms = rel_time_since(now, &it->expires);
+ if (delta_ms < it->interval_ms - sleep_accuracy_ms ||
+ delta_ms > it->interval_ms + sleep_accuracy_ms) {
+ dprint(FD_HELPERTHREAD,
+ "%s: delta = %" PRIi64 " <> %u. Clock jump?\n",
+ it->name, delta_ms, it->interval_ms);
+ delta_ms = it->interval_ms;
+ it->expires = *now;
+ timespec_add_msec(&it->expires, it->interval_ms);
+ }
+ }
+ *msec_to_next_event = min((unsigned int)delta_ms, *msec_to_next_event);
+ return expired ? it->func() : 0;
+}
+
+static void *helper_thread_main(void *data)
+{
+ struct helper_data *hd = data;
+ unsigned int msec_to_next_event, next_log;
+ struct interval_timer timer[] = {
+ {
+ .name = "disk_util",
+ .interval_ms = DISK_UTIL_MSEC,
+ .func = update_io_ticks,
+ },
+ {
+ .name = "status_interval",
+ .interval_ms = status_interval,
+ .func = __show_running_run_stats,
+ },
+ {
+ .name = "steadystate",
+ .interval_ms = steadystate_enabled ? STEADYSTATE_MSEC :
+ 0,
+ .func = steadystate_check,
+ }
+ };
+ struct timespec ts;
+ int clk_tck, ret = 0;