init: use __log_buf() if we know buf != NULL
[fio.git] / flow.c
1 #include "fio.h"
2 #include "fio_sem.h"
3 #include "smalloc.h"
4 #include "flist.h"
5
6 struct fio_flow {
7         unsigned int refs;
8         struct flist_head list;
9         unsigned int id;
10         long long int flow_counter;
11 };
12
13 static struct flist_head *flow_list;
14 static struct fio_sem *flow_lock;
15
16 int flow_threshold_exceeded(struct thread_data *td)
17 {
18         struct fio_flow *flow = td->flow;
19         long long flow_counter;
20
21         if (!flow)
22                 return 0;
23
24         if (td->o.flow > 0)
25                 flow_counter = flow->flow_counter;
26         else
27                 flow_counter = -flow->flow_counter;
28
29         if (flow_counter > td->o.flow_watermark) {
30                 if (td->o.flow_sleep) {
31                         io_u_quiesce(td);
32                         usleep(td->o.flow_sleep);
33                 }
34
35                 return 1;
36         }
37
38         /* No synchronization needed because it doesn't
39          * matter if the flow count is slightly inaccurate */
40         flow->flow_counter += td->o.flow;
41         return 0;
42 }
43
44 static struct fio_flow *flow_get(unsigned int id)
45 {
46         struct fio_flow *flow = NULL;
47         struct flist_head *n;
48
49         if (!flow_lock)
50                 return NULL;
51
52         fio_sem_down(flow_lock);
53
54         flist_for_each(n, flow_list) {
55                 flow = flist_entry(n, struct fio_flow, list);
56                 if (flow->id == id)
57                         break;
58
59                 flow = NULL;
60         }
61
62         if (!flow) {
63                 flow = smalloc(sizeof(*flow));
64                 if (!flow) {
65                         fio_sem_up(flow_lock);
66                         return NULL;
67                 }
68                 flow->refs = 0;
69                 INIT_FLIST_HEAD(&flow->list);
70                 flow->id = id;
71                 flow->flow_counter = 0;
72
73                 flist_add_tail(&flow->list, flow_list);
74         }
75
76         flow->refs++;
77         fio_sem_up(flow_lock);
78         return flow;
79 }
80
81 static void flow_put(struct fio_flow *flow)
82 {
83         if (!flow_lock)
84                 return;
85
86         fio_sem_down(flow_lock);
87
88         if (!--flow->refs) {
89                 flist_del(&flow->list);
90                 sfree(flow);
91         }
92
93         fio_sem_up(flow_lock);
94 }
95
96 void flow_init_job(struct thread_data *td)
97 {
98         if (td->o.flow)
99                 td->flow = flow_get(td->o.flow_id);
100 }
101
102 void flow_exit_job(struct thread_data *td)
103 {
104         if (td->flow) {
105                 flow_put(td->flow);
106                 td->flow = NULL;
107         }
108 }
109
110 void flow_init(void)
111 {
112         flow_list = smalloc(sizeof(*flow_list));
113         if (!flow_list) {
114                 log_err("fio: smalloc pool exhausted\n");
115                 return;
116         }
117
118         flow_lock = fio_sem_init(FIO_SEM_UNLOCKED);
119         if (!flow_lock) {
120                 log_err("fio: failed to allocate flow lock\n");
121                 sfree(flow_list);
122                 return;
123         }
124
125         INIT_FLIST_HEAD(flow_list);
126 }
127
128 void flow_exit(void)
129 {
130         if (flow_lock)
131                 fio_sem_remove(flow_lock);
132         if (flow_list)
133                 sfree(flow_list);
134 }