diff --git a/ccan/README b/ccan/README index d75a4c10d..54b413cdf 100644 --- a/ccan/README +++ b/ccan/README @@ -1,3 +1,3 @@ CCAN imported from http://ccodearchive.net. -CCAN version: init-2367-ged6dd33 +CCAN version: init-2380-gd00c9d1b diff --git a/ccan/ccan/crypto/ripemd160/ripemd160.h b/ccan/ccan/crypto/ripemd160/ripemd160.h index 377a07df4..56854cff2 100644 --- a/ccan/ccan/crypto/ripemd160/ripemd160.h +++ b/ccan/ccan/crypto/ripemd160/ripemd160.h @@ -49,7 +49,7 @@ struct ripemd160_ctx { uint32_t s[5]; uint64_t bytes; union { - uint32_t u32[8]; + uint32_t u32[16]; unsigned char u8[64]; } buf; #endif diff --git a/ccan/ccan/io/io.c b/ccan/ccan/io/io.c index f298af707..12b248902 100644 --- a/ccan/ccan/io/io.c +++ b/ccan/ccan/io/io.c @@ -392,12 +392,25 @@ void io_ready(struct io_conn *conn, int pollflags) void io_do_always(struct io_conn *conn) { + /* There's a corner case where the in next_plan wakes up the + * out, placing it in IO_ALWAYS and we end up processing it immediately, + * only to leave it in the always list. + * + * Yet we can't just process one, in case they are both supposed + * to be done, so grab state beforehand. + */ + bool always_out = (conn->plan[IO_OUT].status == IO_ALWAYS); + if (conn->plan[IO_IN].status == IO_ALWAYS) if (!next_plan(conn, &conn->plan[IO_IN])) return; - if (conn->plan[IO_OUT].status == IO_ALWAYS) + if (always_out) { + /* You can't *unalways* a conn (except by freeing, in which + * case next_plan() returned false */ + assert(conn->plan[IO_OUT].status == IO_ALWAYS); next_plan(conn, &conn->plan[IO_OUT]); + } } void io_do_wakeup(struct io_conn *conn, enum io_direction dir) diff --git a/ccan/ccan/io/test/run-40-wakeup-mutual.c b/ccan/ccan/io/test/run-40-wakeup-mutual.c new file mode 100644 index 000000000..04ec94429 --- /dev/null +++ b/ccan/ccan/io/test/run-40-wakeup-mutual.c @@ -0,0 +1,54 @@ +/* Test previous issue: in duplex case, we wake reader reader wakes writer. */ +#include +/* Include the C files directly. */ +#include +#include +#include +#include +#include + +static struct io_plan *block_reading(struct io_conn *conn, void *unused) +{ + static char buf[1]; + return io_read(conn, buf, sizeof(buf), io_never, NULL); +} + +static struct io_plan *writer_woken(struct io_conn *conn, void *unused) +{ + pass("Writer woken up"); + return io_write(conn, "1", 1, io_close_cb, NULL); +} + +static struct io_plan *reader_woken(struct io_conn *conn, void *unused) +{ + pass("Reader woken up"); + /* Wake writer */ + io_wake(conn); + return block_reading(conn, unused); +} + +static struct io_plan *setup_conn(struct io_conn *conn, void *trigger) +{ + return io_duplex(conn, + io_wait(conn, trigger, reader_woken, NULL), + io_out_wait(conn, conn, writer_woken, NULL)); +} + +int main(void) +{ + int fds[2]; + + plan_tests(3); + ok1(socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) == 0); + + /* We use 'fds' as pointer to wake writer. */ + io_new_conn(NULL, fds[0], setup_conn, fds); + + io_wake(fds); + io_loop(NULL, NULL); + + close(fds[1]); + + /* This exits depending on whether all tests passed */ + return exit_status(); +}