… | |
… | |
110 | } |
110 | } |
111 | |
111 | |
112 | /*****************************************************************************/ |
112 | /*****************************************************************************/ |
113 | /* actual backed implementation */ |
113 | /* actual backed implementation */ |
114 | |
114 | |
|
|
115 | /* we use out own wrapper structure in acse we ever want to do something "clever" */ |
115 | typedef struct aniocb |
116 | typedef struct aniocb |
116 | { |
117 | { |
117 | struct iocb io; |
118 | struct iocb io; |
118 | /*int inuse;*/ |
119 | /*int inuse;*/ |
119 | } *ANIOCBP; |
120 | } *ANIOCBP; |
120 | |
121 | |
121 | inline_size |
122 | inline_size |
122 | void |
123 | void |
123 | linuxaio_array_needsize_iocbp (ANIOCBP *base, int count) |
124 | linuxaio_array_needsize_iocbp (ANIOCBP *base, int count) |
124 | { |
125 | { |
125 | /* TODO: quite the overhead to allocate every iocb separately */ |
126 | /* TODO: quite the overhead to allocate every iocb separately, maybe use our own alocator? */ |
126 | while (count--) |
127 | while (count--) |
127 | { |
128 | { |
128 | *base = (ANIOCBP)ev_malloc (sizeof (**base)); |
129 | *base = (ANIOCBP)ev_malloc (sizeof (**base)); |
129 | /* TODO: full zero initialize required? */ |
130 | /* TODO: full zero initialize required? */ |
130 | memset (*base, 0, sizeof (**base)); |
131 | memset (*base, 0, sizeof (**base)); |
131 | /* would be nice to initialize fd/data as well */ |
132 | /* would be nice to initialize fd/data as well, but array_needsize API doesn't support that */ |
132 | (*base)->io.aio_lio_opcode = IOCB_CMD_POLL; |
133 | (*base)->io.aio_lio_opcode = IOCB_CMD_POLL; |
133 | ++base; |
134 | ++base; |
134 | } |
135 | } |
135 | } |
136 | } |
136 | |
137 | |
… | |
… | |
212 | unsigned tail = *(volatile unsigned *)&ring->tail; |
213 | unsigned tail = *(volatile unsigned *)&ring->tail; |
213 | |
214 | |
214 | if (head == tail) |
215 | if (head == tail) |
215 | return 0; |
216 | return 0; |
216 | |
217 | |
|
|
218 | /* bail out if the ring buffer doesn't match the expected layout */ |
217 | if (ecb_expect_false (ring->magic != AIO_RING_MAGIC) |
219 | if (ecb_expect_false (ring->magic != AIO_RING_MAGIC) |
218 | || ring->incompat_features != AIO_RING_INCOMPAT_FEATURES |
220 | || ring->incompat_features != AIO_RING_INCOMPAT_FEATURES |
219 | || ring->header_length != sizeof (struct aio_ring)) /* TODO: or use it to find io_event[0]? */ |
221 | || ring->header_length != sizeof (struct aio_ring)) /* TODO: or use it to find io_event[0]? */ |
220 | return 0; |
222 | return 0; |
221 | |
223 | |
… | |
… | |
244 | |
246 | |
245 | if (linuxaio_get_events_from_ring (EV_A)) |
247 | if (linuxaio_get_events_from_ring (EV_A)) |
246 | return; |
248 | return; |
247 | |
249 | |
248 | /* no events, so wait for at least one, then poll ring buffer again */ |
250 | /* no events, so wait for at least one, then poll ring buffer again */ |
249 | /* this degraded to one event per loop iteration */ |
251 | /* this degrades to one event per loop iteration */ |
250 | /* if the ring buffer changes layout, but so be it */ |
252 | /* if the ring buffer changes layout, but so be it */ |
251 | |
253 | |
252 | ts.tv_sec = (long)timeout; |
254 | ts.tv_sec = (long)timeout; |
253 | ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1e9); |
255 | ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1e9); |
254 | |
256 | |
… | |
… | |
283 | { |
285 | { |
284 | /* This happens when the ring buffer is full, at least. I assume this means |
286 | /* This happens when the ring buffer is full, at least. I assume this means |
285 | * that the event was queued synchronously during io_submit, and thus |
287 | * that the event was queued synchronously during io_submit, and thus |
286 | * the buffer overflowd. |
288 | * the buffer overflowd. |
287 | * In this case, we just try next loop iteration. |
289 | * In this case, we just try next loop iteration. |
|
|
290 | * This should not result in a few fds taking priority, as the interface |
|
|
291 | * is one-shot, and we submit iocb's in a round-robin fashion. |
288 | */ |
292 | */ |
289 | memmove (linuxaio_submits, linuxaio_submits + submitted, (linuxaio_submitcnt - submitted) * sizeof (*linuxaio_submits)); |
293 | memmove (linuxaio_submits, linuxaio_submits + submitted, (linuxaio_submitcnt - submitted) * sizeof (*linuxaio_submits)); |
290 | linuxaio_submitcnt -= submitted; |
294 | linuxaio_submitcnt -= submitted; |
291 | timeout = 0; |
295 | timeout = 0; |
292 | break; |
296 | break; |
293 | } |
297 | } |
294 | else |
298 | else |
295 | /* TODO: we get EAGAIN when the ring buffer is full for some reason */ |
|
|
296 | /* TODO: should we always just try next time? */ |
|
|
297 | ev_syserr ("(libev) io_submit"); |
299 | ev_syserr ("(libev) io_submit"); |
298 | |
300 | |
299 | submitted += res; |
301 | submitted += res; |
300 | } |
302 | } |
301 | |
303 | |
… | |
… | |
342 | |
344 | |
343 | inline_size |
345 | inline_size |
344 | void |
346 | void |
345 | linuxaio_fork (EV_P) |
347 | linuxaio_fork (EV_P) |
346 | { |
348 | { |
347 | /* TODO: verify and test */ |
|
|
348 | |
|
|
349 | /* this frees all iocbs, which is very heavy-handed */ |
349 | /* this frees all iocbs, which is very heavy-handed */ |
350 | linuxaio_destroy (EV_A); |
350 | linuxaio_destroy (EV_A); |
351 | linuxaio_submitcnt = 0; /* all pointers were invalidated */ |
351 | linuxaio_submitcnt = 0; /* all pointers were invalidated */ |
352 | |
352 | |
353 | linuxaio_ctx = 0; |
353 | linuxaio_ctx = 0; |