5111910ec518f9d318f7b444d13eea462b5a98fc
[fio.git] / lib / tp.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <unistd.h>
5 #include <errno.h>
6 #include <pthread.h>
7
8 #include "../smalloc.h"
9 #include "../log.h"
10 #include "tp.h"
11
12 static void tp_flush_work(struct flist_head *list)
13 {
14         struct tp_work *work;
15
16         while (!flist_empty(list)) {
17                 work = flist_entry(list->next, struct tp_work, list);
18                 flist_del(&work->list);
19                 work->fn(work);
20         }
21 }
22
23 static void *tp_thread(void *data)
24 {
25         struct tp_data *tdat = data;
26         struct flist_head work_list;
27
28         INIT_FLIST_HEAD(&work_list);
29
30         while (1) {
31                 pthread_mutex_lock(&tdat->lock);
32
33                 if (!tdat->thread_exit && flist_empty(&tdat->work))
34                         pthread_cond_wait(&tdat->cv, &tdat->lock);
35
36                 if (!flist_empty(&tdat->work))
37                         flist_splice_tail_init(&tdat->work, &work_list);
38
39                 pthread_mutex_unlock(&tdat->lock);
40
41                 if (flist_empty(&work_list)) {
42                         if (tdat->thread_exit)
43                                 break;
44                         continue;
45                 }
46
47                 tp_flush_work(&work_list);
48         }
49
50         return NULL;
51 }
52
53 void tp_queue_work(struct tp_data *tdat, struct tp_work *work)
54 {
55         work->done = 0;
56
57         pthread_mutex_lock(&tdat->lock);
58         flist_add_tail(&work->list, &tdat->work);
59         pthread_cond_signal(&tdat->cv);
60         pthread_mutex_unlock(&tdat->lock);
61 }
62
63 void tp_init(struct tp_data **tdatp)
64 {
65         struct tp_data *tdat;
66         int ret;
67
68         if (*tdatp)
69                 return;
70
71         *tdatp = tdat = smalloc(sizeof(*tdat));
72         pthread_mutex_init(&tdat->lock, NULL);
73         INIT_FLIST_HEAD(&tdat->work);
74         pthread_cond_init(&tdat->cv, NULL);
75         pthread_cond_init(&tdat->sleep_cv, NULL);
76
77         ret = pthread_create(&tdat->thread, NULL, tp_thread, tdat);
78         if (ret)
79                 log_err("fio: failed to create tp thread\n");
80 }
81
82 void tp_exit(struct tp_data **tdatp)
83 {
84         struct tp_data *tdat = *tdatp;
85         void *ret;
86
87         if (!tdat)
88                 return;
89
90         tdat->thread_exit = 1;
91         pthread_mutex_lock(&tdat->lock);
92         pthread_cond_signal(&tdat->cv);
93         pthread_mutex_unlock(&tdat->lock);
94
95         pthread_join(tdat->thread, &ret);
96
97         sfree(tdat);
98         *tdatp = NULL;
99 }