Based on lib/poll.c, we should not invoke both notify_read() and
notify_write() on the same event, since the first call may change the
handle state and invalided the write event.
When having both read and write event, prefer the read event since it is
is a reply for older command.
When returning events, use switch case for more efficient conversion
from libnbd events to libev events.
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
examples/copy-libev.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/examples/copy-libev.c b/examples/copy-libev.c
index 1b1e9df..3f687a1 100644
--- a/examples/copy-libev.c
+++ b/examples/copy-libev.c
@@ -119,16 +119,20 @@ get_fd(struct connection *c)
static inline int
get_events(struct connection *c)
{
- int events = 0;
unsigned dir = nbd_aio_get_direction (c->nbd);
- if (dir & LIBNBD_AIO_DIRECTION_WRITE)
- events |= EV_WRITE;
+ switch (dir) {
+ case LIBNBD_AIO_DIRECTION_READ:
+ return EV_READ;
+ case LIBNBD_AIO_DIRECTION_WRITE:
+ return EV_WRITE;
+ case LIBNBD_AIO_DIRECTION_BOTH:
+ return EV_READ | EV_WRITE;
+ default:
+ return 0;
+ }
- if (dir & LIBNBD_AIO_DIRECTION_READ)
- events |= EV_READ;
- return events;
}
/* Start async copy or zero request. */
@@ -241,11 +245,15 @@ io_cb (struct ev_loop *loop, ev_io *w, int revents)
{
struct connection *c = (struct connection *)w;
- if (revents & EV_WRITE)
- nbd_aio_notify_write (c->nbd);
+ /* Based on lib/poll.c, we need to prefer read over write, and avoid
+ * invoking both notify_read() and notify_write(), since notify_read() may
+ * change the state of the handle.
+ */
if (revents & EV_READ)
nbd_aio_notify_read (c->nbd);
+ else if (revents & EV_WRITE)
+ nbd_aio_notify_write (c->nbd);
}
static inline void
--
2.26.3