From: Timo Sirainen Date: Mon, 1 Mar 2021 10:56:21 +0000 (+0200) Subject: lib: test-ioloop - Make sure recreating 0-timeout in callback works X-Git-Tag: 2.3.15~134 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d92eb240cdcbebf5e09dab46641a54c030bd06b8;p=thirdparty%2Fdovecot%2Fcore.git lib: test-ioloop - Make sure recreating 0-timeout in callback works --- diff --git a/src/lib/ioloop.c b/src/lib/ioloop.c index f3be87480d..43251cd3f6 100644 --- a/src/lib/ioloop.c +++ b/src/lib/ioloop.c @@ -288,7 +288,9 @@ struct timeout *timeout_add_to(struct ioloop *ioloop, unsigned int msecs, /* start this timeout in the next run cycle */ array_push_back(&timeout->ioloop->timeouts_new, &timeout); } else { - /* trigger zero timeouts as soon as possible */ + /* Trigger zero timeouts as soon as possible. When ioloop is + running, refresh the timestamp to prevent infinite loops + in case a timeout callback keeps recreating the 0-timeout. */ timeout_update_next(timeout, timeout->ioloop->running ? NULL : &ioloop_timeval); priorityq_add(timeout->ioloop->timeouts, &timeout->item); diff --git a/src/lib/test-ioloop.c b/src/lib/test-ioloop.c index 57fdacd3e5..91f38e0ea2 100644 --- a/src/lib/test-ioloop.c +++ b/src/lib/test-ioloop.c @@ -168,6 +168,56 @@ static void test_ioloop_zero_timeout(void) test_end(); } +struct zero_timeout_recreate_ctx { + struct timeout *to; + unsigned int counter; +}; + +static void +zero_timeout_recreate_callback(struct zero_timeout_recreate_ctx *ctx) +{ + timeout_remove(&ctx->to); + ctx->to = timeout_add_short(0, zero_timeout_recreate_callback, ctx); + ctx->counter++; +} + +static void test_ioloop_zero_timeout_recreate(void) +{ + struct ioloop *ioloop; + struct io *io; + struct zero_timeout_recreate_ctx ctx = { .counter = 0 }; + int fd[2]; + + test_begin("ioloop zero timeout recreate"); + + if (pipe(fd) < 0) + i_fatal("pipe() failed: %m"); + switch (fork()) { + case (pid_t)-1: + i_fatal("fork() failed: %m"); + case 0: + sleep(1); + char c = 0; + if (write(fd[1], &c, 1) < 0) + i_fatal("write(pipe) failed: %m"); + test_exit(0); + default: + break; + } + + ioloop = io_loop_create(); + ctx.to = timeout_add_short(0, zero_timeout_recreate_callback, &ctx); + io = io_add(fd[0], IO_READ, io_loop_stop, ioloop); + + io_loop_run(ioloop); + test_assert_ucmp(ctx.counter, >, 1000); + + timeout_remove(&ctx.to); + io_remove(&io); + io_loop_destroy(&ioloop); + test_end(); +} + static void io_callback(void *context ATTR_UNUSED) { } @@ -241,6 +291,7 @@ void test_ioloop(void) { test_ioloop_timeout(); test_ioloop_zero_timeout(); + test_ioloop_zero_timeout_recreate(); test_ioloop_find_fd_conditions(); test_ioloop_pending_io(); test_ioloop_fd();