From: Timo Sirainen Date: Thu, 3 Apr 2014 16:47:49 +0000 (+0300) Subject: ioloop: Added io_set_pending() X-Git-Tag: 2.2.13.rc1~176 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f922ecaf766c60c10f642f3ac2d5f7748ff642b0;p=thirdparty%2Fdovecot%2Fcore.git ioloop: Added io_set_pending() --- diff --git a/src/lib/ioloop-epoll.c b/src/lib/ioloop-epoll.c index 5aca317bfa..285360a82e 100644 --- a/src/lib/ioloop-epoll.c +++ b/src/lib/ioloop-epoll.c @@ -161,7 +161,7 @@ void io_loop_handle_remove(struct io_file *io, bool closed) i_free(io); } -void io_loop_handler_run(struct ioloop *ioloop) +void io_loop_handler_run_internal(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct epoll_event *events; diff --git a/src/lib/ioloop-kqueue.c b/src/lib/ioloop-kqueue.c index e1a60f9f30..f8a3069d0c 100644 --- a/src/lib/ioloop-kqueue.c +++ b/src/lib/ioloop-kqueue.c @@ -108,7 +108,7 @@ void io_loop_handle_remove(struct io_file *io, bool closed) i_free(io); } -void io_loop_handler_run(struct ioloop *ioloop) +void io_loop_handler_run_internal(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct kevent *events; diff --git a/src/lib/ioloop-poll.c b/src/lib/ioloop-poll.c index 704b8471c6..8d1b2d9345 100644 --- a/src/lib/ioloop-poll.c +++ b/src/lib/ioloop-poll.c @@ -143,7 +143,7 @@ void io_loop_handle_remove(struct io_file *io, bool closed ATTR_UNUSED) } } -void io_loop_handler_run(struct ioloop *ioloop) +void io_loop_handler_run_internal(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct pollfd *pollfd; diff --git a/src/lib/ioloop-private.h b/src/lib/ioloop-private.h index afbe39d6ae..b5b4dcd7e4 100644 --- a/src/lib/ioloop-private.h +++ b/src/lib/ioloop-private.h @@ -24,6 +24,8 @@ struct ioloop { io_loop_time_moved_callback_t *time_moved_callback; time_t next_max_time; + unsigned int io_pending_count; + unsigned int running:1; unsigned int iolooping:1; }; @@ -31,6 +33,9 @@ struct ioloop { struct io { enum io_condition condition; unsigned int source_linenum; + /* trigger I/O callback even if OS doesn't think there is input + pending */ + bool pending; io_callback_t *callback; void *context; @@ -79,6 +84,8 @@ int io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r); void io_loop_handle_timeouts(struct ioloop *ioloop); void io_loop_call_io(struct io *io); +void io_loop_handler_run_internal(struct ioloop *ioloop); + /* I/O handler calls */ void io_loop_handle_add(struct io_file *io); void io_loop_handle_remove(struct io_file *io, bool closed); diff --git a/src/lib/ioloop-select.c b/src/lib/ioloop-select.c index a216166fe9..02baf61a7d 100644 --- a/src/lib/ioloop-select.c +++ b/src/lib/ioloop-select.c @@ -103,7 +103,7 @@ void io_loop_handle_remove(struct io_file *io, bool closed ATTR_UNUSED) (FD_ISSET((fd), &(ctx)->tmp_write_fds) && ((cond) & IO_WRITE)) || \ (FD_ISSET((fd), &(ctx)->tmp_except_fds))) -void io_loop_handler_run(struct ioloop *ioloop) +void io_loop_handler_run_internal(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct timeval tv; diff --git a/src/lib/ioloop.c b/src/lib/ioloop.c index 31d73dd0e9..ce32af4b20 100644 --- a/src/lib/ioloop.c +++ b/src/lib/ioloop.c @@ -93,6 +93,11 @@ static void io_remove_full(struct io **_io, bool closed) kqueue code relies on this. */ io->callback = NULL; + if (io->pending) { + i_assert(io->ioloop->io_pending_count > 0); + io->ioloop->io_pending_count--; + } + if (io->ctx != NULL) io_loop_context_unref(&io->ctx); @@ -118,6 +123,16 @@ void io_remove_closed(struct io **io) io_remove_full(io, TRUE); } +void io_set_pending(struct io *io) +{ + i_assert((io->condition & IO_NOTIFY) == 0); + + if (!io->pending) { + io->pending = TRUE; + io->ioloop->io_pending_count++; + } +} + static void timeout_update_next(struct timeout *timeout, struct timeval *tv_now) { if (tv_now == NULL) { @@ -382,6 +397,12 @@ void io_loop_call_io(struct io *io) struct ioloop *ioloop = io->ioloop; unsigned int t_id; + if (io->pending) { + i_assert(ioloop->io_pending_count > 0); + ioloop->io_pending_count--; + io->pending = FALSE; + } + if (io->ctx != NULL) io_loop_context_activate(io->ctx); t_id = t_push(); @@ -413,6 +434,24 @@ void io_loop_run(struct ioloop *ioloop) ioloop->iolooping = FALSE; } +static void io_loop_call_pending(struct ioloop *ioloop) +{ + struct io_file *io; + + for (io = ioloop->io_files; ioloop->io_pending_count > 0; ) { + ioloop->next_io_file = io->next; + if (io->io.pending) + io_loop_call_io(&io->io); + io = ioloop->next_io_file; + } +} + +void io_loop_handler_run(struct ioloop *ioloop) +{ + io_loop_handler_run_internal(ioloop); + io_loop_call_pending(ioloop); +} + void io_loop_stop(struct ioloop *ioloop) { ioloop->running = FALSE; @@ -484,6 +523,7 @@ void io_loop_destroy(struct ioloop **_ioloop) io->io.source_linenum, io->fd); io_remove(&_io); } + i_assert(ioloop->io_pending_count == 0); while ((item = priorityq_pop(ioloop->timeouts)) != NULL) { struct timeout *to = (struct timeout *)item; @@ -686,6 +726,8 @@ struct io *io_loop_move_io(struct io **_io) new_io = io_add(old_io_file->fd, old_io->condition, old_io->source_linenum, old_io->callback, old_io->context); + if (old_io->pending) + io_set_pending(new_io); io_remove(_io); return new_io; } diff --git a/src/lib/ioloop.h b/src/lib/ioloop.h index 37ecf7d517..421a8da0eb 100644 --- a/src/lib/ioloop.h +++ b/src/lib/ioloop.h @@ -67,6 +67,12 @@ void io_remove(struct io **io); With some backends this simply frees the memory. */ void io_remove_closed(struct io **io); +/* Make sure the I/O callback is called by io_loop_run() even if there isn't + any input actually pending currently as seen by the OS. This may be useful + if some of the input has already read into some internal buffer and the + caller wants to handle it the same way as if the fd itself had input. */ +void io_set_pending(struct io *io); + /* Timeout handlers */ struct timeout * timeout_add(unsigned int msecs, unsigned int source_linenum,