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;
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;
#include "lib.h"
#include "array.h"
+#include "llist.h"
#include "time-util.h"
#include "istream-private.h"
#include "ioloop-private.h"
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)
}
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);
}
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(¤t_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(¤t_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;
+}
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);