f031df4de508855120d41268dd32f6f05049a508
[fio.git] / helper_thread.c
1 #include "fio.h"
2 #include "smalloc.h"
3 #include "helper_thread.h"
4
5 static struct helper_data {
6         volatile int exit;
7         volatile int reset;
8         volatile int do_stat;
9         struct sk_out *sk_out;
10         pthread_t thread;
11         pthread_mutex_t lock;
12         pthread_cond_t cond;
13         struct fio_mutex *startup_mutex;
14 } *helper_data;
15
16 void helper_thread_destroy(void)
17 {
18         pthread_cond_destroy(&helper_data->cond);
19         pthread_mutex_destroy(&helper_data->lock);
20         sfree(helper_data);
21 }
22
23 void helper_reset(void)
24 {
25         if (!helper_data)
26                 return;
27
28         pthread_mutex_lock(&helper_data->lock);
29
30         if (!helper_data->reset) {
31                 helper_data->reset = 1;
32                 pthread_cond_signal(&helper_data->cond);
33         }
34
35         pthread_mutex_unlock(&helper_data->lock);
36 }
37
38 void helper_do_stat(void)
39 {
40         if (!helper_data)
41                 return;
42
43         pthread_mutex_lock(&helper_data->lock);
44         helper_data->do_stat = 1;
45         pthread_cond_signal(&helper_data->cond);
46         pthread_mutex_unlock(&helper_data->lock);
47 }
48
49 bool helper_should_exit(void)
50 {
51         if (!helper_data)
52                 return true;
53
54         return helper_data->exit;
55 }
56
57 void helper_thread_exit(void)
58 {
59         void *ret;
60
61         pthread_mutex_lock(&helper_data->lock);
62         helper_data->exit = 1;
63         pthread_cond_signal(&helper_data->cond);
64         pthread_mutex_unlock(&helper_data->lock);
65
66         pthread_join(helper_data->thread, &ret);
67 }
68
69 static void *helper_thread_main(void *data)
70 {
71         struct helper_data *hd = data;
72         unsigned int msec_to_next_event, next_log;
73         struct timeval tv, last_du;
74         int ret = 0;
75
76         sk_out_assign(hd->sk_out);
77
78         gettimeofday(&tv, NULL);
79         memcpy(&last_du, &tv, sizeof(tv));
80
81         fio_mutex_up(hd->startup_mutex);
82
83         msec_to_next_event = DISK_UTIL_MSEC;
84         while (!ret && !hd->exit) {
85                 struct timespec ts;
86                 struct timeval now;
87                 uint64_t since_du;
88
89                 timeval_add_msec(&tv, msec_to_next_event);
90                 ts.tv_sec = tv.tv_sec;
91                 ts.tv_nsec = tv.tv_usec * 1000;
92
93                 pthread_mutex_lock(&hd->lock);
94                 pthread_cond_timedwait(&hd->cond, &hd->lock, &ts);
95
96                 gettimeofday(&now, NULL);
97
98                 if (hd->reset) {
99                         memcpy(&tv, &now, sizeof(tv));
100                         memcpy(&last_du, &now, sizeof(last_du));
101                         hd->reset = 0;
102                 }
103
104                 pthread_mutex_unlock(&hd->lock);
105
106                 since_du = mtime_since(&last_du, &now);
107                 if (since_du >= DISK_UTIL_MSEC || DISK_UTIL_MSEC - since_du < 10) {
108                         ret = update_io_ticks();
109                         timeval_add_msec(&last_du, DISK_UTIL_MSEC);
110                         msec_to_next_event = DISK_UTIL_MSEC;
111                         if (since_du >= DISK_UTIL_MSEC)
112                                 msec_to_next_event -= (since_du - DISK_UTIL_MSEC);
113                 } else
114                         msec_to_next_event = DISK_UTIL_MSEC - since_du;
115
116                 if (hd->do_stat) {
117                         hd->do_stat = 0;
118                         __show_running_run_stats();
119                 }
120
121                 next_log = calc_log_samples();
122                 if (!next_log)
123                         next_log = DISK_UTIL_MSEC;
124
125                 msec_to_next_event = min(next_log, msec_to_next_event);
126
127                 if (!is_backend)
128                         print_thread_status();
129         }
130
131         fio_writeout_logs(false);
132
133         sk_out_drop();
134         return NULL;
135 }
136
137 int helper_thread_create(struct fio_mutex *startup_mutex, struct sk_out *sk_out)
138 {
139         struct helper_data *hd;
140         int ret;
141
142         hd = smalloc(sizeof(*hd));
143
144         setup_disk_util();
145
146         hd->sk_out = sk_out;
147
148         ret = mutex_cond_init_pshared(&hd->lock, &hd->cond);
149         if (ret)
150                 return 1;
151
152         hd->startup_mutex = startup_mutex;
153
154         ret = pthread_create(&hd->thread, NULL, helper_thread_main, hd);
155         if (ret) {
156                 log_err("Can't create helper thread: %s\n", strerror(ret));
157                 return 1;
158         }
159
160         helper_data = hd;
161
162         dprint(FD_MUTEX, "wait on startup_mutex\n");
163         fio_mutex_down(startup_mutex);
164         dprint(FD_MUTEX, "done waiting on startup_mutex\n");
165         return 0;
166 }