From de01eb22da25422e5ad58d3e90f76c492ca0df34 Mon Sep 17 00:00:00 2001 From: Marc Alexander Lehmann Date: Tue, 9 Jul 2019 00:04:35 +0000 Subject: [PATCH] *** empty log message *** --- Changes | 8 +++++--- ev_iouring.c | 10 +++++----- ev_linuxaio.c | 19 +++++++++++++++---- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Changes b/Changes index 976a192..e7f25e7 100644 --- a/Changes +++ b/Changes @@ -1,14 +1,16 @@ Revision history for libev, a high-performance and full-featured event loop. -TODO: revisit 59.x timer in the light of mdoenr powersaving +TODO: revisit 59.x timer in the light of modern powersaving TODO: maybe use timerfd to detect time jumps on linux - linuxaio backend resulted in random memory corruption when loop is forked. - linuxaio backend might have tried to cancel an iocb multiple times (was unable to trigger this). + - linuxaio backend now employs a generation counter to + avoid handlign spurious events from cancelled requests. - io_cancel can return EINTR, deal with it. also, assume - io_asubmit also retursn EINTR. - - fix some othe rminor bugs in linuxaio backend. + io_submit also returns EINTR. + - fix some other minor bugs in linuxaio backend. - cleanup: replace expect_true/false and noinline by their libecb counterparts. - move syscall infrastructure from ev_linuxaio.c to ev.c. diff --git a/ev_iouring.c b/ev_iouring.c index 65caaac..35b5913 100644 --- a/ev_iouring.c +++ b/ev_iouring.c @@ -381,17 +381,17 @@ iouring_modify (EV_P_ int fd, int oev, int nev) sqe->fd = fd; sqe->user_data = -1; iouring_sqe_submit (EV_A_ sqe); - } - /* increment generation counter to avoid handling old events */ - ++anfds [fd].egen; + /* increment generation counter to avoid handling old events */ + ++anfds [fd].egen; + } if (nev) { struct io_uring_sqe *sqe = iouring_sqe_get (EV_A); sqe->opcode = IORING_OP_POLL_ADD; sqe->fd = fd; - sqe->user_data = (uint32_t)fd | ((__u64)anfds [fd].egen << 32); + sqe->user_data = (uint32_t)fd | ((__u64)(uint32_t)anfds [fd].egen << 32); sqe->poll_events = (nev & EV_READ ? POLLIN : 0) | (nev & EV_WRITE ? POLLOUT : 0); @@ -444,7 +444,7 @@ iouring_process_cqe (EV_P_ struct io_uring_cqe *cqe) /* ignore event if generation doesn't match */ /* this should actually be very rare */ - if (ecb_expect_false ((uint32_t)anfds [fd].egen != gen)) + if (ecb_expect_false (gen != (uint32_t)anfds [fd].egen)) return; if (ecb_expect_false (res < 0)) diff --git a/ev_linuxaio.c b/ev_linuxaio.c index 78931a1..499481d 100644 --- a/ev_linuxaio.c +++ b/ev_linuxaio.c @@ -214,7 +214,6 @@ linuxaio_array_needsize_iocbp (ANIOCBP *base, int offset, int count) memset (iocb, 0, sizeof (*iocb)); iocb->io.aio_lio_opcode = IOCB_CMD_POLL; - iocb->io.aio_data = offset; iocb->io.aio_fildes = offset; base [offset++] = iocb; @@ -236,18 +235,20 @@ linuxaio_modify (EV_P_ int fd, int oev, int nev) { array_needsize (ANIOCBP, linuxaio_iocbps, linuxaio_iocbpmax, fd + 1, linuxaio_array_needsize_iocbp); ANIOCBP iocb = linuxaio_iocbps [fd]; + ANFD *anfd = &anfds [fd]; if (ecb_expect_false (iocb->io.aio_reqprio < 0)) { /* we handed this fd over to epoll, so undo this first */ /* we do it manually because the optimisations on epoll_modify won't do us any good */ epoll_ctl (backend_fd, EPOLL_CTL_DEL, fd, 0); - anfds [fd].emask = 0; + anfd->emask = 0; iocb->io.aio_reqprio = 0; } else if (ecb_expect_false (iocb->io.aio_buf)) { /* iocb active, so cancel it first before resubmit */ + /* this assumes we only ever get one call per fd per loop iteration */ for (;;) { /* on all relevant kernels, io_cancel fails with EINPROGRESS on "success" */ @@ -264,6 +265,9 @@ linuxaio_modify (EV_P_ int fd, int oev, int nev) break; } } + + /* increment generation counter to avoid handling old events */ + ++anfd->egen; } iocb->io.aio_buf = @@ -272,6 +276,8 @@ linuxaio_modify (EV_P_ int fd, int oev, int nev) if (nev) { + iocb->io.aio_data = (uint32_t)fd | ((__u64)(uint32_t)anfd->egen << 32); + /* queue iocb up for io_submit */ /* this assumes we only ever get one call per fd per loop iteration */ ++linuxaio_submitcnt; @@ -300,11 +306,16 @@ linuxaio_parse_events (EV_P_ struct io_event *ev, int nr) { while (nr) { - int fd = ev->data; - int res = ev->res; + int fd = ev->data & 0xffffffff; + uint32_t gen = ev->data >> 32; + int res = ev->res; assert (("libev: iocb fd must be in-bounds", fd >= 0 && fd < anfdmax)); + /* ignore event if generation doesn't match */ + if (ecb_expect_false (gen != (uint32_t)anfds [fd].egen)) + continue; + /* feed events, we do not expect or handle POLLNVAL */ fd_event ( EV_A_