engines: separate declaration and assignment
[fio.git] / engines / null.c
1 /*
2  * null engine
3  *
4  * IO engine that doesn't do any real IO transfers, it just pretends to.
5  * The main purpose is to test fio itself.
6  *
7  * It also can act as external C++ engine - compiled with:
8  *
9  * g++ -O2 -g -shared -rdynamic -fPIC -o cpp_null null.c \
10  *      -include ../config-host.h -DFIO_EXTERNAL_ENGINE
11  *
12  * to test it execute:
13  *
14  * LD_LIBRARY_PATH=./engines ./fio examples/cpp_null.fio
15  *
16  */
17 #include <stdlib.h>
18 #include <assert.h>
19
20 #include "../fio.h"
21
22 struct null_data {
23         struct io_u **io_us;
24         int queued;
25         int events;
26 };
27
28 static struct io_u *null_event(struct null_data *nd, int event)
29 {
30         return nd->io_us[event];
31 }
32
33 static int null_getevents(struct null_data *nd, unsigned int min_events,
34                           unsigned int fio_unused max,
35                           const struct timespec fio_unused *t)
36 {
37         int ret = 0;
38
39         if (min_events) {
40                 ret = nd->events;
41                 nd->events = 0;
42         }
43
44         return ret;
45 }
46
47 static void null_queued(struct thread_data *td, struct null_data *nd)
48 {
49         struct timespec now;
50
51         if (!fio_fill_issue_time(td))
52                 return;
53
54         fio_gettime(&now, NULL);
55
56         for (int i = 0; i < nd->queued; i++) {
57                 struct io_u *io_u = nd->io_us[i];
58
59                 memcpy(&io_u->issue_time, &now, sizeof(now));
60                 io_u_queued(td, io_u);
61         }
62 }
63
64 static int null_commit(struct thread_data *td, struct null_data *nd)
65 {
66         if (!nd->events) {
67                 null_queued(td, nd);
68
69 #ifndef FIO_EXTERNAL_ENGINE
70                 io_u_mark_submit(td, nd->queued);
71 #endif
72                 nd->events = nd->queued;
73                 nd->queued = 0;
74         }
75
76         return 0;
77 }
78
79 static enum fio_q_status null_queue(struct thread_data *td,
80                                     struct null_data *nd, struct io_u *io_u)
81 {
82         fio_ro_check(td, io_u);
83
84         if (td->io_ops->flags & FIO_SYNCIO)
85                 return FIO_Q_COMPLETED;
86         if (nd->events)
87                 return FIO_Q_BUSY;
88
89         nd->io_us[nd->queued++] = io_u;
90         return FIO_Q_QUEUED;
91 }
92
93 static int null_open(struct null_data fio_unused *nd,
94                      struct fio_file fio_unused *f)
95 {
96         return 0;
97 }
98
99 static void null_cleanup(struct null_data *nd)
100 {
101         if (nd) {
102                 free(nd->io_us);
103                 free(nd);
104         }
105 }
106
107 static struct null_data *null_init(struct thread_data *td)
108 {
109         struct null_data *nd;
110         nd = malloc(sizeof(*nd));
111
112         memset(nd, 0, sizeof(*nd));
113
114         if (td->o.iodepth != 1) {
115                 nd->io_us = malloc(td->o.iodepth * sizeof(struct io_u *));
116                 memset(nd->io_us, 0, td->o.iodepth * sizeof(struct io_u *));
117                 td->io_ops->flags |= FIO_ASYNCIO_SETS_ISSUE_TIME;
118         } else
119                 td->io_ops->flags |= FIO_SYNCIO;
120
121         td_set_ioengine_flags(td);
122         return nd;
123 }
124
125 #ifndef __cplusplus
126
127 static struct io_u *fio_null_event(struct thread_data *td, int event)
128 {
129         return null_event(td->io_ops_data, event);
130 }
131
132 static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
133                               unsigned int max, const struct timespec *t)
134 {
135         struct null_data *nd = td->io_ops_data;
136         return null_getevents(nd, min_events, max, t);
137 }
138
139 static int fio_null_commit(struct thread_data *td)
140 {
141         return null_commit(td, td->io_ops_data);
142 }
143
144 static enum fio_q_status fio_null_queue(struct thread_data *td,
145                                         struct io_u *io_u)
146 {
147         return null_queue(td, td->io_ops_data, io_u);
148 }
149
150 static int fio_null_open(struct thread_data *td, struct fio_file *f)
151 {
152         return null_open(td->io_ops_data, f);
153 }
154
155 static void fio_null_cleanup(struct thread_data *td)
156 {
157         null_cleanup(td->io_ops_data);
158 }
159
160 static int fio_null_init(struct thread_data *td)
161 {
162         td->io_ops_data = null_init(td);
163         assert(td->io_ops_data);
164         return 0;
165 }
166
167 static struct ioengine_ops ioengine = {
168         .name           = "null",
169         .version        = FIO_IOOPS_VERSION,
170         .queue          = fio_null_queue,
171         .commit         = fio_null_commit,
172         .getevents      = fio_null_getevents,
173         .event          = fio_null_event,
174         .init           = fio_null_init,
175         .cleanup        = fio_null_cleanup,
176         .open_file      = fio_null_open,
177         .flags          = FIO_DISKLESSIO | FIO_FAKEIO,
178 };
179
180 static void fio_init fio_null_register(void)
181 {
182         register_ioengine(&ioengine);
183 }
184
185 static void fio_exit fio_null_unregister(void)
186 {
187         unregister_ioengine(&ioengine);
188 }
189
190 #else
191
192 #ifdef FIO_EXTERNAL_ENGINE
193
194 struct NullData {
195         NullData(struct thread_data *td)
196         {
197                 impl_ = null_init(td);
198                 assert(impl_);
199         }
200
201         ~NullData()
202         {
203                 null_cleanup(impl_);
204         }
205
206         static NullData *get(struct thread_data *td)
207         {
208                 return reinterpret_cast<NullData *>(td->io_ops_data);
209         }
210
211         io_u *fio_null_event(struct thread_data *, int event)
212         {
213                 return null_event(impl_, event);
214         }
215
216         int fio_null_getevents(struct thread_data *, unsigned int min_events,
217                                unsigned int max, const struct timespec *t)
218         {
219                 return null_getevents(impl_, min_events, max, t);
220         }
221
222         int fio_null_commit(struct thread_data *td)
223         {
224                 return null_commit(td, impl_);
225         }
226
227         fio_q_status fio_null_queue(struct thread_data *td, struct io_u *io_u)
228         {
229                 return null_queue(td, impl_, io_u);
230         }
231
232         int fio_null_open(struct thread_data *, struct fio_file *f)
233         {
234                 return null_open(impl_, f);
235         }
236
237 private:
238         struct null_data *impl_;
239 };
240
241 extern "C" {
242
243 static struct io_u *fio_null_event(struct thread_data *td, int event)
244 {
245         return NullData::get(td)->fio_null_event(td, event);
246 }
247
248 static int fio_null_getevents(struct thread_data *td, unsigned int min_events,
249                               unsigned int max, const struct timespec *t)
250 {
251         return NullData::get(td)->fio_null_getevents(td, min_events, max, t);
252 }
253
254 static int fio_null_commit(struct thread_data *td)
255 {
256         return NullData::get(td)->fio_null_commit(td);
257 }
258
259 static fio_q_status fio_null_queue(struct thread_data *td, struct io_u *io_u)
260 {
261         return NullData::get(td)->fio_null_queue(td, io_u);
262 }
263
264 static int fio_null_open(struct thread_data *td, struct fio_file *f)
265 {
266         return NullData::get(td)->fio_null_open(td, f);
267 }
268
269 static int fio_null_init(struct thread_data *td)
270 {
271         td->io_ops_data = new NullData(td);
272         return 0;
273 }
274
275 static void fio_null_cleanup(struct thread_data *td)
276 {
277         delete NullData::get(td);
278 }
279
280 static struct ioengine_ops ioengine;
281 void get_ioengine(struct ioengine_ops **ioengine_ptr)
282 {
283         *ioengine_ptr = &ioengine;
284
285         ioengine.name           = "cpp_null";
286         ioengine.version        = FIO_IOOPS_VERSION;
287         ioengine.queue          = fio_null_queue;
288         ioengine.commit         = fio_null_commit;
289         ioengine.getevents      = fio_null_getevents;
290         ioengine.event          = fio_null_event;
291         ioengine.init           = fio_null_init;
292         ioengine.cleanup        = fio_null_cleanup;
293         ioengine.open_file      = fio_null_open;
294         ioengine.flags          = FIO_DISKLESSIO | FIO_FAKEIO;
295 }
296 }
297 #endif /* FIO_EXTERNAL_ENGINE */
298
299 #endif /* __cplusplus */