ab27b55d32f96380e120cc5aff46ba8d4628746e
[fio.git] / engines / solarisaio.c
1 /*
2  * Native Solaris async IO engine
3  *
4  */
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9
10 #include "../fio.h"
11
12 #ifdef FIO_HAVE_SOLARISAIO
13
14 #include <sys/asynch.h>
15
16 struct solarisaio_data {
17         struct io_u **aio_events;
18         unsigned int nr;
19 };
20
21 static int fio_solarisaio_cancel(struct thread_data fio_unused *td,
22                                struct io_u *io_u)
23 {
24         return aiocancel(&io_u->resultp);
25 }
26
27 static int fio_solarisaio_prep(struct thread_data fio_unused *td,
28                             struct io_u *io_u)
29 {
30         io_u->resultp.aio_return = AIO_INPROGRESS;
31         return 0;
32 }
33
34 static int fio_solarisaio_getevents(struct thread_data *td, unsigned int min,
35                                     unsigned int max, struct timespec *t)
36 {
37         struct solarisaio_data *sd = td->io_ops->data;
38         struct timeval tv;
39         unsigned int r;
40
41         r = 0;
42         do {
43                 struct io_u *io_u;
44                 aio_result_t *p;
45
46                 if (!min || !t) {
47                         tv.tv_sec = 0;
48                         tv.tv_usec = 0;
49                 } else {
50                         tv.tv_sec = t->tv_sec;
51                         tv.tv_usec = t->tv_nsec / 1000;
52                 }
53
54                 p = aiowait(&tv);
55                 if (p) {
56                         io_u = container_of(p, struct io_u, resultp);
57
58                         sd->aio_events[r++] = io_u;
59                         sd->nr--;
60
61                         if (io_u->resultp.aio_return >= 0) {
62                                 io_u->resid = io_u->xfer_buflen
63                                                 - io_u->resultp.aio_return;
64                                 io_u->error = 0;
65                         } else
66                                 io_u->error = io_u->resultp.aio_return;
67                 }
68         } while (r < min);
69
70         return r;
71 }
72
73 static struct io_u *fio_solarisaio_event(struct thread_data *td, int event)
74 {
75         struct solarisaio_data *sd = td->io_ops->data;
76
77         return sd->aio_events[event];
78 }
79
80 static int fio_solarisaio_queue(struct thread_data fio_unused *td,
81                               struct io_u *io_u)
82 {
83         struct solarisaio_data *sd = td->io_ops->data;
84         struct fio_file *f = io_u->file;
85         off_t off;
86         int ret;
87
88         fio_ro_check(td, io_u);
89
90         if (io_u->ddir == DDIR_SYNC) {
91                 if (sd->nr)
92                         return FIO_Q_BUSY;
93                 if (fsync(f->fd) < 0)
94                         io_u->error = errno;
95
96                 return FIO_Q_COMPLETED;
97         }
98
99         if (sd->nr == td->o.iodepth)
100                 return FIO_Q_BUSY;
101
102         off = io_u->offset;
103         if (io_u->ddir == DDIR_READ)
104                 ret = aioread(f->fd, io_u->xfer_buf, io_u->xfer_buflen, off,
105                                         SEEK_SET, &io_u->resultp);
106         else
107                 ret = aiowrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, off,
108                                         SEEK_SET, &io_u->resultp);
109         if (ret) {
110                 io_u->error = errno;
111                 td_verror(td, io_u->error, "xfer");
112                 return FIO_Q_COMPLETED;
113         }
114
115         sd->nr++;
116         return FIO_Q_QUEUED;
117 }
118
119 static void fio_solarisaio_cleanup(struct thread_data *td)
120 {
121         struct solarisaio_data *sd = td->io_ops->data;
122
123         if (sd) {
124                 free(sd->aio_events);
125                 free(sd);
126         }
127 }
128
129 static int fio_solarisaio_init(struct thread_data *td)
130 {
131         struct solarisaio_data *sd = malloc(sizeof(*sd));
132
133         memset(sd, 0, sizeof(*sd));
134         sd->aio_events = malloc(td->o.iodepth * sizeof(struct io_u *));
135         memset(sd->aio_events, 0, td->o.iodepth * sizeof(struct io_u *));
136
137         td->io_ops->data = sd;
138         return 0;
139 }
140
141 static struct ioengine_ops ioengine = {
142         .name           = "solarisaio",
143         .version        = FIO_IOOPS_VERSION,
144         .init           = fio_solarisaio_init,
145         .prep           = fio_solarisaio_prep,
146         .queue          = fio_solarisaio_queue,
147         .cancel         = fio_solarisaio_cancel,
148         .getevents      = fio_solarisaio_getevents,
149         .event          = fio_solarisaio_event,
150         .cleanup        = fio_solarisaio_cleanup,
151         .open_file      = generic_open_file,
152         .close_file     = generic_close_file,
153 };
154
155 #else /* FIO_HAVE_SOLARISAIO */
156
157 /*
158  * When we have a proper configure system in place, we simply wont build
159  * and install this io engine. For now install a crippled version that
160  * just complains and fails to load.
161  */
162 static int fio_solarisaio_init(struct thread_data fio_unused *td)
163 {
164         fprintf(stderr, "fio: solarisaio not available\n");
165         return 1;
166 }
167
168 static struct ioengine_ops ioengine = {
169         .name           = "solarisaio",
170         .version        = FIO_IOOPS_VERSION,
171         .init           = fio_solarisaio_init,
172 };
173
174 #endif
175
176 static void fio_init fio_solarisaio_register(void)
177 {
178         register_ioengine(&ioengine);
179 }
180
181 static void fio_exit fio_solarisaio_unregister(void)
182 {
183         unregister_ioengine(&ioengine);
184 }