]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
ioloop: Added io_set_pending()
authorTimo Sirainen <tss@iki.fi>
Thu, 3 Apr 2014 16:47:49 +0000 (19:47 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 3 Apr 2014 16:47:49 +0000 (19:47 +0300)
src/lib/ioloop-epoll.c
src/lib/ioloop-kqueue.c
src/lib/ioloop-poll.c
src/lib/ioloop-private.h
src/lib/ioloop-select.c
src/lib/ioloop.c
src/lib/ioloop.h

index 5aca317bfa2a5871d5ff42c6661305ce84104550..285360a82e99ad2a7126f672b6daa1e06a345d6b 100644 (file)
@@ -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;
index e1a60f9f30854182434bfd24d4ce387c3435b0cb..f8a3069d0c4f00a5e1e5ddfbaff767f4224b20c0 100644 (file)
@@ -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;
index 704b8471c670f76c29be3ea7790c8131b46ead39..8d1b2d93451c22671a85c6f02e12c012fa910a20 100644 (file)
@@ -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;
index afbe39d6ae6dd8c2ee75218818fc0b39cad90b98..b5b4dcd7e44780a84a14644d7f64e6809c5b0b47 100644 (file)
@@ -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);
index a216166fe941c223c7ce8cf0d8eb0e6a2b963240..02baf61a7dfe2a192e4583d4cedb46f77758f056 100644 (file)
@@ -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;
index 31d73dd0e92f0d980d6f8ffa297853520753a555..ce32af4b20904a049f370248f5bd856a637654e3 100644 (file)
@@ -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;
 }
index 37ecf7d517dc3eb5763ef321766ad486cc58a6d7..421a8da0eb2a9d74247d4eb57864ec76072cad20 100644 (file)
@@ -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,