… | |
… | |
321 | /* get any events from ring buffer, return true if any were handled */ |
321 | /* get any events from ring buffer, return true if any were handled */ |
322 | static int |
322 | static int |
323 | linuxaio_get_events_from_ring (EV_P) |
323 | linuxaio_get_events_from_ring (EV_P) |
324 | { |
324 | { |
325 | struct aio_ring *ring = (struct aio_ring *)linuxaio_ctx; |
325 | struct aio_ring *ring = (struct aio_ring *)linuxaio_ctx; |
|
|
326 | unsigned head, tail; |
326 | |
327 | |
327 | /* the kernel reads and writes both of these variables, */ |
328 | /* the kernel reads and writes both of these variables, */ |
328 | /* as a C extension, we assume that volatile use here */ |
329 | /* as a C extension, we assume that volatile use here */ |
329 | /* both makes reads atomic and once-only */ |
330 | /* both makes reads atomic and once-only */ |
330 | unsigned head = *(volatile unsigned *)&ring->head; |
331 | head = *(volatile unsigned *)&ring->head; |
|
|
332 | ECB_MEMORY_FENCE_ACQUIRE; |
331 | unsigned tail = *(volatile unsigned *)&ring->tail; |
333 | tail = *(volatile unsigned *)&ring->tail; |
332 | |
334 | |
333 | if (head == tail) |
335 | if (head == tail) |
334 | return 0; |
336 | return 0; |
335 | |
|
|
336 | /* make sure the events up to tail are visible */ |
|
|
337 | ECB_MEMORY_FENCE_ACQUIRE; |
|
|
338 | |
337 | |
339 | /* parse all available events, but only once, to avoid starvation */ |
338 | /* parse all available events, but only once, to avoid starvation */ |
340 | if (tail > head) /* normal case around */ |
339 | if (tail > head) /* normal case around */ |
341 | linuxaio_parse_events (EV_A_ ring->io_events + head, tail - head); |
340 | linuxaio_parse_events (EV_A_ ring->io_events + head, tail - head); |
342 | else /* wrapped around */ |
341 | else /* wrapped around */ |
… | |
… | |
394 | { |
393 | { |
395 | int res; |
394 | int res; |
396 | |
395 | |
397 | EV_RELEASE_CB; |
396 | EV_RELEASE_CB; |
398 | |
397 | |
399 | ts.tv_sec = (long)timeout; |
398 | EV_TS_SET (ts, timeout); |
400 | ts.tv_nsec = (long)((timeout - ts.tv_sec) * 1e9); |
|
|
401 | |
|
|
402 | res = evsys_io_getevents (linuxaio_ctx, 1, want, ioev, &ts); |
399 | res = evsys_io_getevents (linuxaio_ctx, 1, want, ioev, &ts); |
403 | |
400 | |
404 | EV_ACQUIRE_CB; |
401 | EV_ACQUIRE_CB; |
405 | |
402 | |
406 | if (res < 0) |
403 | if (res < 0) |
… | |
… | |
492 | } |
489 | } |
493 | |
490 | |
494 | ++linuxaio_iteration; |
491 | ++linuxaio_iteration; |
495 | if (linuxaio_io_setup (EV_A) < 0) |
492 | if (linuxaio_io_setup (EV_A) < 0) |
496 | { |
493 | { |
|
|
494 | /* TODO: rearm all and recreate epoll backend from scratch */ |
|
|
495 | /* TODO: might be more prudent? */ |
|
|
496 | |
497 | /* to bad, we can't get a new aio context, go 100% epoll */ |
497 | /* to bad, we can't get a new aio context, go 100% epoll */ |
498 | linuxaio_free_iocbp (EV_A); |
498 | linuxaio_free_iocbp (EV_A); |
499 | ev_io_stop (EV_A_ &linuxaio_epoll_w); |
499 | ev_io_stop (EV_A_ &linuxaio_epoll_w); |
500 | ev_ref (EV_A); |
500 | ev_ref (EV_A); |
501 | linuxaio_ctx = 0; |
501 | linuxaio_ctx = 0; |
|
|
502 | |
|
|
503 | backend = EVBACKEND_EPOLL; |
502 | backend_modify = epoll_modify; |
504 | backend_modify = epoll_modify; |
503 | backend_poll = epoll_poll; |
505 | backend_poll = epoll_poll; |
504 | } |
506 | } |
505 | |
507 | |
506 | timeout = 0; |
508 | timeout = 0; |
… | |
… | |
515 | res = 1; /* skip this iocb */ |
517 | res = 1; /* skip this iocb */ |
516 | } |
518 | } |
517 | else if (errno == EINTR) /* not seen in reality, not documented */ |
519 | else if (errno == EINTR) /* not seen in reality, not documented */ |
518 | res = 0; /* silently ignore and retry */ |
520 | res = 0; /* silently ignore and retry */ |
519 | else |
521 | else |
|
|
522 | { |
520 | ev_syserr ("(libev) linuxaio io_submit"); |
523 | ev_syserr ("(libev) linuxaio io_submit"); |
|
|
524 | res = 0; |
|
|
525 | } |
521 | |
526 | |
522 | submitted += res; |
527 | submitted += res; |
523 | } |
528 | } |
524 | |
529 | |
525 | linuxaio_submitcnt = 0; |
530 | linuxaio_submitcnt = 0; |
… | |
… | |
553 | ev_io_init (EV_A_ &linuxaio_epoll_w, linuxaio_epoll_cb, backend_fd, EV_READ); |
558 | ev_io_init (EV_A_ &linuxaio_epoll_w, linuxaio_epoll_cb, backend_fd, EV_READ); |
554 | ev_set_priority (&linuxaio_epoll_w, EV_MAXPRI); |
559 | ev_set_priority (&linuxaio_epoll_w, EV_MAXPRI); |
555 | ev_io_start (EV_A_ &linuxaio_epoll_w); |
560 | ev_io_start (EV_A_ &linuxaio_epoll_w); |
556 | ev_unref (EV_A); /* watcher should not keep loop alive */ |
561 | ev_unref (EV_A); /* watcher should not keep loop alive */ |
557 | |
562 | |
558 | backend_modify = linuxaio_modify; |
563 | backend_modify = linuxaio_modify; |
559 | backend_poll = linuxaio_poll; |
564 | backend_poll = linuxaio_poll; |
560 | |
565 | |
561 | linuxaio_iocbpmax = 0; |
566 | linuxaio_iocbpmax = 0; |
562 | linuxaio_iocbps = 0; |
567 | linuxaio_iocbps = 0; |
563 | |
568 | |
564 | linuxaio_submits = 0; |
569 | linuxaio_submits = 0; |
… | |
… | |
575 | epoll_destroy (EV_A); |
580 | epoll_destroy (EV_A); |
576 | linuxaio_free_iocbp (EV_A); |
581 | linuxaio_free_iocbp (EV_A); |
577 | evsys_io_destroy (linuxaio_ctx); /* fails in child, aio context is destroyed */ |
582 | evsys_io_destroy (linuxaio_ctx); /* fails in child, aio context is destroyed */ |
578 | } |
583 | } |
579 | |
584 | |
580 | inline_size |
585 | ecb_cold |
581 | void |
586 | static void |
582 | linuxaio_fork (EV_P) |
587 | linuxaio_fork (EV_P) |
583 | { |
588 | { |
584 | /* this frees all iocbs, which is very heavy-handed */ |
589 | /* this frees all iocbs, which is very heavy-handed */ |
585 | linuxaio_destroy (EV_A); |
590 | linuxaio_destroy (EV_A); |
586 | linuxaio_submitcnt = 0; /* all pointers were invalidated */ |
591 | linuxaio_submitcnt = 0; /* all pointers were invalidated */ |
… | |
… | |
590 | while (linuxaio_io_setup (EV_A) < 0) |
595 | while (linuxaio_io_setup (EV_A) < 0) |
591 | ev_syserr ("(libev) linuxaio io_setup"); |
596 | ev_syserr ("(libev) linuxaio io_setup"); |
592 | |
597 | |
593 | /* forking epoll should also effectively unregister all fds from the backend */ |
598 | /* forking epoll should also effectively unregister all fds from the backend */ |
594 | epoll_fork (EV_A); |
599 | epoll_fork (EV_A); |
|
|
600 | /* epoll_fork already did this. hopefully */ |
|
|
601 | /*fd_rearm_all (EV_A);*/ |
595 | |
602 | |
596 | ev_io_stop (EV_A_ &linuxaio_epoll_w); |
603 | ev_io_stop (EV_A_ &linuxaio_epoll_w); |
597 | ev_io_set (EV_A_ &linuxaio_epoll_w, backend_fd, EV_READ); |
604 | ev_io_set (EV_A_ &linuxaio_epoll_w, backend_fd, EV_READ); |
598 | ev_io_start (EV_A_ &linuxaio_epoll_w); |
605 | ev_io_start (EV_A_ &linuxaio_epoll_w); |
599 | |
|
|
600 | /* epoll_fork already did this. hopefully */ |
|
|
601 | /*fd_rearm_all (EV_A);*/ |
|
|
602 | } |
606 | } |
603 | |
607 | |