[PATCH] fio: pretty close to compiling/working on FreeBSD now
[disktools.git] / fio-aio.c
CommitLineData
f5087211
JA
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <errno.h>
5#include "fio.h"
6#include "os.h"
7
8#ifdef FIO_HAVE_LIBAIO
9
10#define ev_to_iou(ev) (struct io_u *) ((unsigned long) (ev)->obj)
11
12struct libaio_data {
13 io_context_t aio_ctx;
14 struct io_event *aio_events;
15};
16
17static void fio_libaio_io_prep(struct thread_data *td, struct io_u *io_u,
18 int read)
19{
20 if (read)
21 io_prep_pread(&io_u->iocb, td->fd, io_u->buf, io_u->buflen, io_u->offset);
22 else
23 io_prep_pwrite(&io_u->iocb, td->fd, io_u->buf, io_u->buflen, io_u->offset);
24}
25
26static struct io_u *fio_libaio_event(struct thread_data *td, int event)
27{
28 struct libaio_data *ld = td->aio_data;
29
30 return ev_to_iou(ld->aio_events + event);
31}
32
33static int fio_libaio_getevents(struct thread_data *td, int min, int max,
34 struct timespec *t)
35{
36 struct libaio_data *ld = td->aio_data;
37
38 int r;
39
40 do {
41 r = io_getevents(ld->aio_ctx, min, max, ld->aio_events, t);
42 if (r != -EAGAIN && r != -EINTR)
43 break;
44 } while (1);
45
46 return r;
47}
48
49static int fio_libaio_queue(struct thread_data *td, struct io_u *io_u)
50{
51 struct libaio_data *ld = td->aio_data;
52 struct iocb *iocb = &io_u->iocb;
53 int ret;
54
55 do {
56 ret = io_submit(ld->aio_ctx, 1, &iocb);
57 if (ret == 1)
58 return 0;
59 else if (ret == -EAGAIN)
60 usleep(100);
61 else if (ret == -EINTR)
62 continue;
63 else
64 break;
65 } while (1);
66
67 return ret;
68
69}
70
71static int fio_libaio_cancel(struct thread_data *td, struct io_u *io_u)
72{
73 struct libaio_data *ld = td->aio_data;
74
75 return io_cancel(ld->aio_ctx, &io_u->iocb, ld->aio_events);
76}
77
78int fio_libaio_init(struct thread_data *td)
79{
80 struct libaio_data *ld = malloc(sizeof(*ld));
81
82 memset(ld, 0, sizeof(*ld));
83 if (io_queue_init(td->aio_depth, &ld->aio_ctx)) {
84 td_verror(td, errno);
85 return 1;
86 }
87
88 td->io_prep = fio_libaio_io_prep;
89 td->io_queue = fio_libaio_queue;
90 td->io_getevents = fio_libaio_getevents;
91 td->io_event = fio_libaio_event;
92 td->io_cancel = fio_libaio_cancel;
93
94 ld->aio_events = malloc(td->aio_depth * sizeof(struct io_event));
95 td->aio_data = ld;
96 return 0;
97}
98
99void fio_libaio_cleanup(struct thread_data *td)
100{
101 struct libaio_data *ld = td->aio_data;
102
103 if (ld) {
104 io_destroy(ld->aio_ctx);
105 if (ld->aio_events)
106 free(ld->aio_events);
107
108 free(ld);
109 td->aio_data = NULL;
110 }
111}
112
113#else /* FIO_HAVE_LIBAIO */
114
115int fio_libaio_init(struct thread_data *td)
116{
117 return EINVAL;
118}
119
120void fio_libaio_cleanup(struct thread_data *td)
121{
122}
123
124#endif /* FIO_HAVE_LIBAIO */
125
126#ifdef FIO_HAVE_POSIXAIO
127
128struct posixaio_data {
129 struct io_u **aio_events;
130};
131
132static int fio_posixaio_cancel(struct thread_data *td, struct io_u *io_u)
133{
134 int r = aio_cancel(td->fd, &io_u->aiocb);
135
136 if (r == 1 || r == AIO_CANCELED)
137 return 0;
138
139 return 1;
140}
141
142static void fio_posixaio_prep(struct thread_data *td, struct io_u *io_u,
143 int read)
144{
145 struct aiocb *aiocb = &io_u->aiocb;
146
147 aiocb->aio_fildes = td->fd;
148 aiocb->aio_buf = io_u->buf;
149 aiocb->aio_nbytes = io_u->buflen;
150 aiocb->aio_offset = io_u->offset;
151
152 if (read)
153 aiocb->aio_lio_opcode = LIO_READ;
154 else
155 aiocb->aio_lio_opcode = LIO_WRITE;
156
157 io_u->seen = 0;
158}
159
160static int fio_posixaio_getevents(struct thread_data *td, int min, int max,
161 struct timespec *t)
162{
163 struct posixaio_data *pd = td->aio_data;
164 struct list_head *entry;
165 int r;
166
167 r = 0;
168restart:
169 list_for_each(entry, &td->io_u_busylist) {
170 struct io_u *io_u = list_entry(entry, struct io_u, list);
171
172 if (io_u->seen)
173 continue;
174
175 if (aio_error(&io_u->aiocb) != EINPROGRESS) {
176 pd->aio_events[r++] = io_u;
177 io_u->seen = 1;
178 }
179
180 if (r >= max)
181 break;
182 }
183
184 if (r >= min)
185 return r;
186
187 /*
188 * hrmpf, we need to wait for more. we should use aio_suspend, for
189 * now just sleep a little and recheck status of busy-and-not-seen
190 */
191 usleep(1000);
192 goto restart;
193}
194
195static struct io_u *fio_posixaio_event(struct thread_data *td, int event)
196{
197 struct posixaio_data *pd = td->aio_data;
198
199 return pd->aio_events[event];
200}
201
202static int fio_posixaio_queue(struct thread_data *td, struct io_u *io_u)
203{
204 struct aiocb *aiocb = &io_u->aiocb;
205
206 if (aiocb->aio_lio_opcode == LIO_READ)
207 return aio_read(aiocb);
208 else
209 return aio_write(aiocb);
210}
211
212int fio_posixaio_init(struct thread_data *td)
213{
214 struct posixaio_data *pd = malloc(sizeof(*pd));
215
216 pd->aio_events = malloc(td->aio_depth * sizeof(struct io_u *));
217
218 td->io_prep = fio_posixaio_prep;
219 td->io_queue = fio_posixaio_queue;
220 td->io_getevents = fio_posixaio_getevents;
221 td->io_event = fio_posixaio_event;
222 td->io_cancel = fio_posixaio_cancel;
223
224 td->aio_data = pd;
225 return 0;
226}
227
228void fio_posixaio_cleanup(struct thread_data *td)
229{
230 struct posixaio_data *pd = td->aio_data;
231
232 if (pd) {
233 free(pd->aio_events);
234 free(pd);
235 td->aio_data = NULL;
236 }
237}
238
239#else /* FIO_HAVE_POSIXAIO */
240
241int fio_posixaio_init(struct thread_data *td)
242{
243 return EINVAL;
244}
245
246void fio_posixaio_cleanup(struct thread_data *td)
247{
248}
249
250#endif /* FIO_HAVE_POSIXAIO */