ioloop.h revision ae800c8a965688ab17415397dbc759a429e78199
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen#ifndef IOLOOP_H
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen#define IOLOOP_H
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen#include <sys/time.h>
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen#include <time.h>
64f30df0bee5218c9a69915e796d9d1376cfbf29Timo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstruct io;
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstruct timeout;
4462bd7b4c7ef3de006f060e155a90e5de7cae21Timo Sirainenstruct ioloop;
f6c1297c26b355c4aec2a08978f51ec3efecb351Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenenum io_condition {
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen IO_READ = 0x01,
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen IO_WRITE = 0x02,
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen /* IO_ERROR can be used to check when writable pipe's reader side
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen closes the pipe. For other uses IO_READ should work just as well. */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen IO_ERROR = 0x04,
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen /* internal */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen IO_NOTIFY = 0x08
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen};
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainenenum io_notify_result {
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen /* Notify added successfully */
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen IO_NOTIFY_ADDED,
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen /* Specified file doesn't exist, can't wait on it */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen IO_NOTIFY_NOTFOUND,
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen /* Can't add notify for specified file. Main reasons for this:
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen a) No notify support at all, b) Only directory notifies supported */
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen IO_NOTIFY_NOSUPPORT
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen};
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainentypedef void io_callback_t(void *context);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainentypedef void timeout_callback_t(void *context);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainentypedef void io_loop_time_moved_callback_t(time_t old_time, time_t new_time);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* Time when the I/O loop started calling handlers.
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen Can be used instead of time(NULL). */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenextern time_t ioloop_time;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenextern struct timeval ioloop_timeval;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenextern struct ioloop *current_ioloop;
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* You can create different handlers for IO_READ and IO_WRITE. IO_READ and
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen IO_ERROR can't use different handlers (and there's no point anyway).
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen Don't try to add multiple handlers for the same type. It's not checked and
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen the behavior will be undefined. */
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainenstruct io *io_add(int fd, enum io_condition condition,
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen io_callback_t *callback, void *context);
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen#define io_add(fd, condition, callback, context) \
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen CONTEXT_CALLBACK(io_add, io_callback_t, \
57a712a4998e4bb0073080232225380cd2cea625Timo Sirainen callback, context, fd, condition)
57a712a4998e4bb0073080232225380cd2cea625Timo Sirainenenum io_notify_result io_add_notify(const char *path, io_callback_t *callback,
57a712a4998e4bb0073080232225380cd2cea625Timo Sirainen void *context, struct io **io_r);
c37098f8ce6d512ba41f09564d04ed25720f0a77Timo Sirainen#ifdef CONTEXT_TYPE_SAFETY
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen# define io_add_notify(path, callback, context, io_r) \
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen ({(void)(1 ? 0 : callback(context)); \
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen io_add_notify(path, (io_callback_t *)callback, context, io_r); })
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen#else
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen# define io_add_notify(path, callback, context, io_r) \
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen io_add_notify(path, (io_callback_t *)callback, context, io_r)
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen#endif
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* Remove I/O handler, and set io pointer to NULL. */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_remove(struct io **io);
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen/* Like io_remove(), but assume that the file descriptor is already closed.
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen With some backends this simply frees the memory. */
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainenvoid io_remove_closed(struct io **io);
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen
bfcca12a441275b7f4cd510b95669b163263b2e7Timo Sirainen/* Timeout handlers */
bfcca12a441275b7f4cd510b95669b163263b2e7Timo Sirainenstruct timeout *timeout_add(unsigned int msecs, timeout_callback_t *callback,
bfcca12a441275b7f4cd510b95669b163263b2e7Timo Sirainen void *context);
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen#define timeout_add(msecs, callback, context) \
2e5d624013c30633e8ded148d338ce46c321a995Timo Sirainen CONTEXT_CALLBACK(timeout_add, timeout_callback_t, \
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen callback, context, msecs)
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen/* Remove timeout handler, and set timeout pointer to NULL. */
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainenvoid timeout_remove(struct timeout **timeout);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* Reset timeout so it's next run after now+msecs. */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid timeout_reset(struct timeout *timeout);
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_run(struct ioloop *ioloop);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_stop(struct ioloop *ioloop); /* safe to run in signal handler */
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainenbool io_loop_is_running(struct ioloop *ioloop);
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen
5b6470e0e2ef4012430cdeca7d9b89c1278a0ed4Timo Sirainen/* call these if you wish to run the iteration only once */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_set_running(struct ioloop *ioloop);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_handler_run(struct ioloop *ioloop);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenstruct ioloop *io_loop_create(void);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* Specify the maximum number of fds we're expecting to use. */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_set_max_fd_count(struct ioloop *ioloop, unsigned int max_fds);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* Destroy I/O loop and set ioloop pointer to NULL. */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_destroy(struct ioloop **ioloop);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen/* If time moves backwards or jumps forwards call the callback. */
6380f2bc729a03b328793e8ad6ba7587620fa184Timo Sirainenvoid io_loop_set_time_moved_callback(struct ioloop *ioloop,
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen io_loop_time_moved_callback_t *callback);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen/* Change the current_ioloop. */
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_set_current(struct ioloop *ioloop);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen/* This context is used for all further I/O and timeout callbacks that are
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen added until returning to ioloop. When a callback is called, this context is
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen again activated. */
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainenstruct ioloop_context *io_loop_context_new(struct ioloop *ioloop);
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainenvoid io_loop_context_ref(struct ioloop_context *ctx);
64f30df0bee5218c9a69915e796d9d1376cfbf29Timo Sirainenvoid io_loop_context_unref(struct ioloop_context **ctx);
57f4445a46726a17bfe78b0964dd301a6ccb40ecTimo Sirainen/* Call the activate callback when this context is activated (I/O callback is
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen about to be called), and the deactivate callback when the context is
c8296ac1ed68ed5c5168de545b76f9b27fc76d35Timo Sirainen deactivated (I/O callback has returned). You can add multiple callbacks. */
void io_loop_context_add_callbacks(struct ioloop_context *ctx,
io_callback_t *activate,
io_callback_t *deactivate, void *context);
/* Remove callbacks with the given callbacks and context. */
void io_loop_context_remove_callbacks(struct ioloop_context *ctx,
io_callback_t *activate,
io_callback_t *deactivate, void *context);
/* 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);
/* Like io_loop_move_io(), but for timeouts. */
struct timeout *io_loop_move_timeout(struct timeout **timeout);
#endif