]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Added io_wait_timer
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 15 Nov 2016 10:21:56 +0000 (11:21 +0100)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 15 Nov 2016 20:38:07 +0000 (22:38 +0200)
This allows easier tracking of how much time the io_wait_timer has been
spending on (multiple) ioloops.

src/lib/ioloop-private.h
src/lib/ioloop.c
src/lib/ioloop.h

index 97d20749ee3961be5f695b24def11b7ea8ddeecf..a4b879f9c2d1f3990a979d371e7c305ac2fec4c8 100644 (file)
@@ -18,6 +18,7 @@ struct ioloop {
        struct io_file *next_io_file;
        struct priorityq *timeouts;
        ARRAY(struct timeout *) timeouts_new;
+       struct io_wait_timer *wait_timers;
 
         struct ioloop_handler_context *handler_context;
         struct ioloop_notify_handler_context *notify_handler_context;
@@ -79,6 +80,15 @@ struct timeout {
        unsigned int one_shot:1;
 };
 
+struct io_wait_timer {
+       struct io_wait_timer *prev, *next;
+       const char *source_filename;
+       unsigned int source_linenum;
+
+       struct ioloop *ioloop;
+       uint64_t usecs;
+};
+
 struct ioloop_context_callback {
        io_callback_t *activate;
        io_callback_t *deactivate;
index 59a1219c0981cfc52d3c211ffa0163b4cd41d398..a04b98765e749882b8972f7b00a985cfad1f9253 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "array.h"
+#include "llist.h"
 #include "time-util.h"
 #include "istream-private.h"
 #include "ioloop-private.h"
@@ -499,10 +500,14 @@ static void io_loops_timeouts_update(long diff_secs)
 
 static void ioloop_add_wait_time(struct ioloop *ioloop)
 {
+       struct io_wait_timer *timer;
        long long diff =
                timeval_diff_usecs(&ioloop_timeval, &ioloop->wait_started);
        ioloop->ioloop_wait_usecs += diff;
        ioloop_global_wait_usecs += diff;
+
+       for (timer = ioloop->wait_timers; timer != NULL; timer = timer->next)
+               timer->usecs += diff;
 }
 
 static void io_loop_handle_timeouts_real(struct ioloop *ioloop)
@@ -740,6 +745,15 @@ void io_loop_destroy(struct ioloop **_ioloop)
        }
        priorityq_deinit(&ioloop->timeouts);
 
+       while (ioloop->wait_timers != NULL) {
+               struct io_wait_timer *timer = ioloop->wait_timers;
+
+               i_warning("IO wait timer leak: %s:%u",
+                         timer->source_filename,
+                         timer->source_linenum);
+               io_wait_timer_remove(&timer);
+       }
+
        if (ioloop->handler_context != NULL)
                io_loop_handler_deinit(ioloop);
 
@@ -1002,3 +1016,42 @@ enum io_condition io_loop_find_fd_conditions(struct ioloop *ioloop, int fd)
        }
        return conditions;
 }
+
+#undef io_wait_timer_add
+struct io_wait_timer *
+io_wait_timer_add(const char *source_filename, unsigned int source_linenum)
+{
+       struct io_wait_timer *timer;
+
+       timer = i_new(struct io_wait_timer, 1);
+       timer->ioloop = current_ioloop;
+       timer->source_filename = source_filename;
+       timer->source_linenum = source_linenum;
+       DLLIST_PREPEND(&current_ioloop->wait_timers, timer);
+       return timer;
+}
+
+struct io_wait_timer *io_wait_timer_move(struct io_wait_timer **_timer)
+{
+       struct io_wait_timer *timer = *_timer;
+
+       *_timer = NULL;
+       DLLIST_REMOVE(&timer->ioloop->wait_timers, timer);
+       DLLIST_PREPEND(&current_ioloop->wait_timers, timer);
+       timer->ioloop = current_ioloop;
+       return timer;
+}
+
+void io_wait_timer_remove(struct io_wait_timer **_timer)
+{
+       struct io_wait_timer *timer = *_timer;
+
+       *_timer = NULL;
+       DLLIST_REMOVE(&timer->ioloop->wait_timers, timer);
+       i_free(timer);
+}
+
+uint64_t io_wait_timer_get_usecs(struct io_wait_timer *timer)
+{
+       return timer->usecs;
+}
index c33d841064635e3807d23691d4b46370e02ed064..f42e7286b0cd37916ef3e0946c0de54f8aa0f2b5 100644 (file)
@@ -183,6 +183,18 @@ struct ioloop_context *io_loop_get_current_context(struct ioloop *ioloop);
    Returns fd on success, -1 on error. */
 int io_loop_extract_notify_fd(struct ioloop *ioloop);
 
+/* IO wait timers can be used to track how much time the io_wait_timer has
+   spent on waiting in its ioloops. This is similar to
+   io_loop_get_wait_usecs(), but it's easier to use when the wait time needs
+   to be tracked across multiple ioloops. */
+struct io_wait_timer *
+io_wait_timer_add(const char *source_filename, unsigned int source_linenum);
+#define io_wait_timer_add() \
+       io_wait_timer_add(__FILE__, __LINE__)
+struct io_wait_timer *io_wait_timer_move(struct io_wait_timer **timer);
+void io_wait_timer_remove(struct io_wait_timer **timer);
+uint64_t io_wait_timer_get_usecs(struct io_wait_timer *timer);
+
 /* Move the given I/O into the current I/O loop if it's not already
    there. New I/O is returned, while the old one is freed. */
 struct io *io_loop_move_io(struct io **io);