From e2e70f5566cb8978b74de517c24a0f236d3d01ee Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 12 Oct 2017 16:58:34 +1030 Subject: [PATCH] io: fix duplex read on last bytes of closed pipe. Signed-off-by: Rusty Russell --- ccan/io/io.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ccan/io/io.c b/ccan/io/io.c index cc2b1afa..7eea9c35 100644 --- a/ccan/io/io.c +++ b/ccan/io/io.c @@ -363,14 +363,20 @@ void io_wake(const void *wait) backend_wake(wait); } -/* Returns false if this has been freed. */ -static bool do_plan(struct io_conn *conn, struct io_plan *plan) +/* Returns false if this should not be touched (eg. freed). */ +static bool do_plan(struct io_conn *conn, struct io_plan *plan, + bool idle_on_epipe) { /* We shouldn't have polled for this event if this wasn't true! */ assert(plan->status == IO_POLLING); switch (plan->io(conn->fd.fd, &plan->arg)) { case -1: + if (errno == EPIPE && idle_on_epipe) { + plan->status = IO_UNSET; + backend_new_plan(conn); + return false; + } io_close(conn); return false; case 0: @@ -386,11 +392,15 @@ static bool do_plan(struct io_conn *conn, struct io_plan *plan) void io_ready(struct io_conn *conn, int pollflags) { if (pollflags & POLLIN) - if (!do_plan(conn, &conn->plan[IO_IN])) + if (!do_plan(conn, &conn->plan[IO_IN], false)) return; if (pollflags & POLLOUT) - do_plan(conn, &conn->plan[IO_OUT]); + /* If we're writing to a closed pipe, we need to wait for + * read to fail if we're duplex: we want to drain it! */ + do_plan(conn, &conn->plan[IO_OUT], + (conn->plan[IO_IN].status == IO_POLLING + || conn->plan[IO_IN].status == IO_ALWAYS)); } void io_do_always(struct io_conn *conn) -- 2.39.2